1 /****************************************************************************** 2 * 3 * Copyright (C) 2009-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 is the API implementation file for the Multi-Channel Adaptation 22 * Protocol (MCAP). 23 * 24 ******************************************************************************/ 25 #include <assert.h> 26 #include <string.h> 27 28 #include "bt_target.h" 29 #include "btm_api.h" 30 #include "btm_int.h" 31 #include "mca_api.h" 32 #include "mca_defs.h" 33 #include "mca_int.h" 34 35 #include "btu.h" 36 37 38 /******************************************************************************* 39 ** 40 ** Function mca_process_timeout 41 ** 42 ** Description This function is called by BTU when an MCA timer 43 ** expires. 44 ** 45 ** This function is for use internal to the stack only. 46 ** 47 ** Returns void 48 ** 49 *******************************************************************************/ 50 void mca_ccb_timer_timeout(void *data) 51 { 52 tMCA_CCB *p_ccb = (tMCA_CCB *)data; 53 54 mca_ccb_event(p_ccb, MCA_CCB_RSP_TOUT_EVT, NULL); 55 } 56 57 /******************************************************************************* 58 ** 59 ** Function MCA_Init 60 ** 61 ** Description Initialize MCAP main control block. 62 ** This function is called at stack start up. 63 ** 64 ** Returns void 65 ** 66 *******************************************************************************/ 67 void MCA_Init(void) 68 { 69 memset(&mca_cb, 0, sizeof(tMCA_CB)); 70 71 #if defined(MCA_INITIAL_TRACE_LEVEL) 72 mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL; 73 #else 74 mca_cb.trace_level = BT_TRACE_LEVEL_NONE; 75 #endif 76 } 77 78 /******************************************************************************* 79 ** 80 ** Function MCA_SetTraceLevel 81 ** 82 ** Description This function sets the debug trace level for MCA. 83 ** If 0xff is passed, the current trace level is returned. 84 ** 85 ** Input Parameters: 86 ** level: The level to set the MCA tracing to: 87 ** 0xff-returns the current setting. 88 ** 0-turns off tracing. 89 ** >= 1-Errors. 90 ** >= 2-Warnings. 91 ** >= 3-APIs. 92 ** >= 4-Events. 93 ** >= 5-Debug. 94 ** 95 ** Returns The new trace level or current trace level if 96 ** the input parameter is 0xff. 97 ** 98 *******************************************************************************/ 99 UINT8 MCA_SetTraceLevel (UINT8 level) 100 { 101 if (level != 0xFF) 102 mca_cb.trace_level = level; 103 104 return (mca_cb.trace_level); 105 } 106 107 /******************************************************************************* 108 ** 109 ** Function MCA_Register 110 ** 111 ** Description This function registers an MCAP implementation. 112 ** It is assumed that the control channel PSM and data channel 113 ** PSM are not used by any other instances of the stack. 114 ** If the given p_reg->ctrl_psm is 0, this handle is INT only. 115 ** 116 ** Returns 0, if failed. Otherwise, the MCA handle. 117 ** 118 *******************************************************************************/ 119 tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback) 120 { 121 tMCA_RCB *p_rcb; 122 tMCA_HANDLE handle = 0; 123 tL2CAP_APPL_INFO l2c_cacp_appl; 124 tL2CAP_APPL_INFO l2c_dacp_appl; 125 126 assert(p_reg != NULL ); 127 assert(p_cback != NULL ); 128 129 MCA_TRACE_API ("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm, p_reg->data_psm); 130 131 if ( (p_rcb = mca_rcb_alloc (p_reg)) != NULL) 132 { 133 if (p_reg->ctrl_psm) 134 { 135 if (L2C_INVALID_PSM(p_reg->ctrl_psm) || L2C_INVALID_PSM(p_reg->data_psm)) 136 { 137 MCA_TRACE_ERROR ("INVALID_PSM"); 138 return 0; 139 } 140 141 l2c_cacp_appl = *(tL2CAP_APPL_INFO *)&mca_l2c_int_appl; 142 l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL; 143 l2c_dacp_appl = *(tL2CAP_APPL_INFO *)&l2c_cacp_appl; 144 l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback; 145 l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback; 146 if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO *) &l2c_cacp_appl) && 147 L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO *) &l2c_dacp_appl)) 148 { 149 /* set security level */ 150 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_CTRL, p_reg->sec_mask, 151 p_reg->ctrl_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID); 152 153 /* in theory, we do not need this one for data_psm 154 * If we don't, L2CAP rejects with security block (3), 155 * which is different reject code from what MCAP spec suggests. 156 * we set this one, so mca_l2c_dconn_ind_cback can reject /w no resources (4) */ 157 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_reg->sec_mask, 158 p_reg->data_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID); 159 } 160 else 161 { 162 MCA_TRACE_ERROR ("Failed to register to L2CAP"); 163 return 0; 164 } 165 } 166 else 167 p_rcb->reg.data_psm = 0; 168 handle = mca_rcb_to_handle (p_rcb); 169 p_rcb->p_cback = p_cback; 170 p_rcb->reg.rsp_tout = p_reg->rsp_tout; 171 } 172 return handle; 173 } 174 175 176 /******************************************************************************* 177 ** 178 ** Function MCA_Deregister 179 ** 180 ** Description This function is called to deregister an MCAP implementation. 181 ** Before this function can be called, all control and data 182 ** channels must be removed with MCA_DisconnectReq and MCA_CloseReq. 183 ** 184 ** Returns void 185 ** 186 *******************************************************************************/ 187 void MCA_Deregister(tMCA_HANDLE handle) 188 { 189 tMCA_RCB *p_rcb = mca_rcb_by_handle(handle); 190 191 MCA_TRACE_API ("MCA_Deregister: %d", handle); 192 if (p_rcb && p_rcb->reg.ctrl_psm) 193 { 194 L2CA_Deregister(p_rcb->reg.ctrl_psm); 195 L2CA_Deregister(p_rcb->reg.data_psm); 196 btm_sec_clr_service_by_psm (p_rcb->reg.ctrl_psm); 197 btm_sec_clr_service_by_psm (p_rcb->reg.data_psm); 198 } 199 mca_rcb_dealloc(handle); 200 } 201 202 203 /******************************************************************************* 204 ** 205 ** Function MCA_CreateDep 206 ** 207 ** Description Create a data endpoint. If the MDEP is created successfully, 208 ** the MDEP ID is returned in *p_dep. After a data endpoint is 209 ** created, an application can initiate a connection between this 210 ** endpoint and an endpoint on a peer device. 211 ** 212 ** Returns MCA_SUCCESS if successful, otherwise error. 213 ** 214 *******************************************************************************/ 215 tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs) 216 { 217 tMCA_RESULT result = MCA_BAD_HANDLE; 218 int i; 219 tMCA_RCB *p_rcb = mca_rcb_by_handle(handle); 220 tMCA_CS *p_depcs; 221 222 assert(p_dep != NULL ); 223 assert(p_cs != NULL ); 224 assert(p_cs->p_data_cback != NULL ); 225 226 MCA_TRACE_API ("MCA_CreateDep: %d", handle); 227 if (p_rcb) 228 { 229 if (p_cs->max_mdl > MCA_NUM_MDLS) 230 { 231 MCA_TRACE_ERROR ("max_mdl: %d is too big", p_cs->max_mdl ); 232 result = MCA_BAD_PARAMS; 233 } 234 else 235 { 236 p_depcs = p_rcb->dep; 237 if (p_cs->type == MCA_TDEP_ECHO) 238 { 239 if (p_depcs->p_data_cback) 240 { 241 MCA_TRACE_ERROR ("Already has ECHO MDEP"); 242 return MCA_NO_RESOURCES; 243 } 244 memcpy (p_depcs, p_cs, sizeof (tMCA_CS)); 245 *p_dep = 0; 246 result = MCA_SUCCESS; 247 } 248 else 249 { 250 result = MCA_NO_RESOURCES; 251 /* non-echo MDEP starts from 1 */ 252 p_depcs++; 253 for (i=1; i<MCA_NUM_DEPS; i++, p_depcs++) 254 { 255 if (p_depcs->p_data_cback == NULL) 256 { 257 memcpy (p_depcs, p_cs, sizeof (tMCA_CS)); 258 /* internally use type as the mdep id */ 259 p_depcs->type = i; 260 *p_dep = i; 261 result = MCA_SUCCESS; 262 break; 263 } 264 } 265 } 266 } 267 } 268 return result; 269 } 270 271 272 /******************************************************************************* 273 ** 274 ** Function MCA_DeleteDep 275 ** 276 ** Description Delete a data endpoint. This function is called when 277 ** the implementation is no longer using a data endpoint. 278 ** If this function is called when the endpoint is connected 279 ** the connection is closed and the data endpoint 280 ** is removed. 281 ** 282 ** Returns MCA_SUCCESS if successful, otherwise error. 283 ** 284 *******************************************************************************/ 285 tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep) 286 { 287 tMCA_RESULT result = MCA_BAD_HANDLE; 288 tMCA_RCB *p_rcb = mca_rcb_by_handle(handle); 289 tMCA_DCB *p_dcb; 290 int i, max; 291 tMCA_CS *p_depcs; 292 293 MCA_TRACE_API ("MCA_DeleteDep: %d dep:%d", handle, dep); 294 if (p_rcb) 295 { 296 if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) 297 { 298 result = MCA_SUCCESS; 299 p_rcb->dep[dep].p_data_cback = NULL; 300 p_depcs = &(p_rcb->dep[dep]); 301 i = handle - 1; 302 max = MCA_NUM_MDLS*MCA_NUM_LINKS; 303 p_dcb = &mca_cb.dcb[i*max]; 304 /* make sure no MDL exists for this MDEP */ 305 for (i=0; i<max; i++, p_dcb++) 306 { 307 if (p_dcb->state && p_dcb->p_cs == p_depcs) 308 { 309 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); 310 } 311 } 312 } 313 } 314 return result; 315 } 316 317 /******************************************************************************* 318 ** 319 ** Function MCA_ConnectReq 320 ** 321 ** Description This function initiates an MCAP control channel connection 322 ** to the peer device. When the connection is completed, an 323 ** MCA_CONNECT_IND_EVT is reported to the application via its 324 ** control callback function. 325 ** This control channel is identified by the tMCA_CL. 326 ** If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is 327 ** reported. The security mask parameter overrides the outgoing 328 ** security mask set in MCA_Register(). 329 ** 330 ** Returns MCA_SUCCESS if successful, otherwise error. 331 ** 332 *******************************************************************************/ 333 tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr, 334 UINT16 ctrl_psm, UINT16 sec_mask) 335 { 336 tMCA_RESULT result = MCA_BAD_HANDLE; 337 tMCA_CCB *p_ccb; 338 tMCA_TC_TBL *p_tbl; 339 340 MCA_TRACE_API ("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm); 341 if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL) 342 p_ccb = mca_ccb_alloc(handle, bd_addr); 343 else 344 { 345 MCA_TRACE_ERROR ("control channel already exists"); 346 return MCA_BUSY; 347 } 348 349 if (p_ccb) 350 { 351 p_ccb->ctrl_vpsm = L2CA_Register (ctrl_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl); 352 result = MCA_NO_RESOURCES; 353 if (p_ccb->ctrl_vpsm) 354 { 355 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask, 356 p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID); 357 p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL); 358 if (p_ccb->lcid) 359 { 360 p_tbl = mca_tc_tbl_calloc(p_ccb); 361 if (p_tbl) 362 { 363 p_tbl->state = MCA_TC_ST_CONN; 364 p_ccb->sec_mask = sec_mask; 365 result = MCA_SUCCESS; 366 } 367 } 368 } 369 if (result != MCA_SUCCESS) 370 mca_ccb_dealloc (p_ccb, NULL); 371 } 372 return result; 373 } 374 375 376 /******************************************************************************* 377 ** 378 ** Function MCA_DisconnectReq 379 ** 380 ** Description This function disconnect an MCAP control channel 381 ** to the peer device. 382 ** If associated data channel exists, they are disconnected. 383 ** When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is 384 ** reported to the application via its control callback function. 385 ** 386 ** Returns MCA_SUCCESS if successful, otherwise error. 387 ** 388 *******************************************************************************/ 389 tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl) 390 { 391 tMCA_RESULT result = MCA_BAD_HANDLE; 392 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 393 394 MCA_TRACE_API ("MCA_DisconnectReq: %d ", mcl); 395 if (p_ccb) 396 { 397 result = MCA_SUCCESS; 398 mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL); 399 } 400 return result; 401 } 402 403 404 /******************************************************************************* 405 ** 406 ** Function MCA_CreateMdl 407 ** 408 ** Description This function sends a CREATE_MDL request to the peer device. 409 ** When the response is received, a MCA_CREATE_CFM_EVT is reported 410 ** with the given MDL ID. 411 ** If the response is successful, a data channel is open 412 ** with the given p_chnl_cfg 413 ** If p_chnl_cfg is NULL, the data channel is not initiated until 414 ** MCA_DataChnlCfg is called to provide the p_chnl_cfg. 415 ** When the data channel is open successfully, a MCA_OPEN_CFM_EVT 416 ** is reported. This data channel is identified as tMCA_DL. 417 ** 418 ** Returns MCA_SUCCESS if successful, otherwise error. 419 ** 420 *******************************************************************************/ 421 tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm, 422 UINT16 mdl_id, UINT8 peer_dep_id, 423 UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg) 424 { 425 tMCA_RESULT result = MCA_BAD_HANDLE; 426 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 427 tMCA_DCB *p_dcb; 428 429 MCA_TRACE_API ("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep, mdl_id, peer_dep_id); 430 if (p_ccb) 431 { 432 if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) 433 { 434 MCA_TRACE_ERROR ("pending req"); 435 return MCA_BUSY; 436 } 437 438 if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id))) 439 { 440 MCA_TRACE_ERROR ("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id, mdl_id); 441 return MCA_BAD_PARAMS; 442 } 443 444 if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) 445 { 446 MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id); 447 return MCA_BAD_MDL_ID; 448 } 449 450 p_dcb = mca_dcb_alloc(p_ccb, dep); 451 result = MCA_NO_RESOURCES; 452 if (p_dcb) 453 { 454 /* save the info required by dcb connection */ 455 p_dcb->p_chnl_cfg = p_chnl_cfg; 456 p_dcb->mdl_id = mdl_id; 457 tMCA_CCB_MSG *p_evt_data = 458 (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG)); 459 if (!p_ccb->data_vpsm) 460 p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl); 461 if (p_ccb->data_vpsm) { 462 p_evt_data->dcb_idx = mca_dcb_to_hdl (p_dcb); 463 p_evt_data->mdep_id = peer_dep_id; 464 p_evt_data->mdl_id = mdl_id; 465 p_evt_data->param = cfg; 466 p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ; 467 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; 468 p_evt_data->hdr.layer_specific = FALSE; 469 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); 470 return MCA_SUCCESS; 471 } else { 472 osi_free(p_evt_data); 473 } 474 475 mca_dcb_dealloc(p_dcb, NULL); 476 } 477 } 478 return result; 479 } 480 481 482 /******************************************************************************* 483 ** 484 ** Function MCA_CreateMdlRsp 485 ** 486 ** Description This function sends a CREATE_MDL response to the peer device 487 ** in response to a received MCA_CREATE_IND_EVT. 488 ** If the rsp_code is successful, a data channel is open 489 ** with the given p_chnl_cfg 490 ** When the data channel is open successfully, a MCA_OPEN_IND_EVT 491 ** is reported. This data channel is identified as tMCA_DL. 492 ** 493 ** Returns MCA_SUCCESS if successful, otherwise error. 494 ** 495 *******************************************************************************/ 496 tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, 497 UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code, 498 const tMCA_CHNL_CFG *p_chnl_cfg) 499 { 500 tMCA_RESULT result = MCA_BAD_HANDLE; 501 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 502 tMCA_CCB_MSG evt_data; 503 tMCA_DCB *p_dcb; 504 505 MCA_TRACE_API ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code); 506 assert(p_chnl_cfg != NULL ); 507 if (p_ccb) 508 { 509 if (p_ccb->cong) 510 { 511 MCA_TRACE_ERROR ("congested"); 512 return MCA_BUSY; 513 } 514 if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep ) 515 && (p_ccb->p_rx_msg->mdl_id == mdl_id) && (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ)) 516 { 517 result = MCA_SUCCESS; 518 evt_data.dcb_idx = 0; 519 if (rsp_code == MCA_RSP_SUCCESS) 520 { 521 p_dcb = mca_dcb_alloc(p_ccb, dep); 522 if (p_dcb) 523 { 524 evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb); 525 p_dcb->p_chnl_cfg = p_chnl_cfg; 526 p_dcb->mdl_id = mdl_id; 527 } 528 else 529 { 530 rsp_code = MCA_RSP_MDEP_BUSY; 531 result = MCA_NO_RESOURCES; 532 } 533 } 534 535 if (result == MCA_SUCCESS) 536 { 537 evt_data.mdl_id = mdl_id; 538 evt_data.param = cfg; 539 evt_data.rsp_code = rsp_code; 540 evt_data.op_code = MCA_OP_MDL_CREATE_RSP; 541 mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data); 542 } 543 } 544 else 545 { 546 MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_CreateMdlRsp with the given parameters" ); 547 result = MCA_BAD_PARAMS; 548 } 549 } 550 return result; 551 } 552 553 /******************************************************************************* 554 ** 555 ** Function MCA_CloseReq 556 ** 557 ** Description Close a data channel. When the channel is closed, an 558 ** MCA_CLOSE_CFM_EVT is sent to the application via the 559 ** control callback function for this handle. 560 ** 561 ** Returns MCA_SUCCESS if successful, otherwise error. 562 ** 563 *******************************************************************************/ 564 tMCA_RESULT MCA_CloseReq(tMCA_DL mdl) 565 { 566 tMCA_RESULT result = MCA_BAD_HANDLE; 567 tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl); 568 569 MCA_TRACE_API ("MCA_CloseReq: %d ", mdl); 570 if (p_dcb) 571 { 572 result = MCA_SUCCESS; 573 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); 574 } 575 return result; 576 } 577 578 579 /******************************************************************************* 580 ** 581 ** Function MCA_ReconnectMdl 582 ** 583 ** Description This function sends a RECONNECT_MDL request to the peer device. 584 ** When the response is received, a MCA_RECONNECT_CFM_EVT is reported. 585 ** If p_chnl_cfg is NULL, the data channel is not initiated until 586 ** MCA_DataChnlCfg is called to provide the p_chnl_cfg. 587 ** If the response is successful, a data channel is open. 588 ** When the data channel is open successfully, a MCA_OPEN_CFM_EVT 589 ** is reported. 590 ** 591 ** Returns MCA_SUCCESS if successful, otherwise error. 592 ** 593 *******************************************************************************/ 594 tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm, 595 UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg) 596 { 597 tMCA_RESULT result = MCA_BAD_HANDLE; 598 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 599 tMCA_DCB *p_dcb; 600 601 MCA_TRACE_API ("MCA_ReconnectMdl: %d ", mcl); 602 assert(p_chnl_cfg != NULL ); 603 if (p_ccb) 604 { 605 if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) 606 { 607 MCA_TRACE_ERROR ("pending req"); 608 return MCA_BUSY; 609 } 610 611 if (!MCA_IS_VALID_MDL_ID(mdl_id)) 612 { 613 MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id); 614 return MCA_BAD_PARAMS; 615 } 616 617 if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) 618 { 619 MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id); 620 return MCA_BAD_MDL_ID; 621 } 622 623 p_dcb = mca_dcb_alloc(p_ccb, dep); 624 result = MCA_NO_RESOURCES; 625 if (p_dcb) { 626 tMCA_CCB_MSG *p_evt_data = 627 (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG)); 628 629 p_dcb->p_chnl_cfg = p_chnl_cfg; 630 p_dcb->mdl_id = mdl_id; 631 if (!p_ccb->data_vpsm) 632 p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl); 633 p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb); 634 p_evt_data->mdl_id = mdl_id; 635 p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ; 636 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; 637 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); 638 return MCA_SUCCESS; 639 } 640 } 641 return result; 642 } 643 644 645 /******************************************************************************* 646 ** 647 ** Function MCA_ReconnectMdlRsp 648 ** 649 ** Description This function sends a RECONNECT_MDL response to the peer device 650 ** in response to a MCA_RECONNECT_IND_EVT event. 651 ** If the response is successful, a data channel is open. 652 ** When the data channel is open successfully, a MCA_OPEN_IND_EVT 653 ** is reported. 654 ** 655 ** Returns MCA_SUCCESS if successful, otherwise error. 656 ** 657 *******************************************************************************/ 658 tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, 659 UINT16 mdl_id, UINT8 rsp_code, 660 const tMCA_CHNL_CFG *p_chnl_cfg) 661 { 662 tMCA_RESULT result = MCA_BAD_HANDLE; 663 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 664 tMCA_CCB_MSG evt_data; 665 tMCA_DCB *p_dcb; 666 667 MCA_TRACE_API ("MCA_ReconnectMdlRsp: %d ", mcl); 668 assert(p_chnl_cfg != NULL ); 669 if (p_ccb) 670 { 671 if (p_ccb->cong) 672 { 673 MCA_TRACE_ERROR ("congested"); 674 return MCA_BUSY; 675 } 676 if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) && 677 (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ)) 678 { 679 result = MCA_SUCCESS; 680 evt_data.dcb_idx = 0; 681 if (rsp_code == MCA_RSP_SUCCESS) 682 { 683 p_dcb = mca_dcb_alloc(p_ccb, dep); 684 if (p_dcb) 685 { 686 evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb); 687 p_dcb->p_chnl_cfg = p_chnl_cfg; 688 p_dcb->mdl_id = mdl_id; 689 } 690 else 691 { 692 MCA_TRACE_ERROR ("Out of MDL for this MDEP"); 693 rsp_code = MCA_RSP_MDEP_BUSY; 694 result = MCA_NO_RESOURCES; 695 } 696 } 697 698 evt_data.mdl_id = mdl_id; 699 evt_data.rsp_code = rsp_code; 700 evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP; 701 mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data); 702 } 703 else 704 { 705 MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_ReconnectMdlRsp with the given parameters" ); 706 result = MCA_BAD_PARAMS; 707 } 708 } 709 return result; 710 } 711 712 713 /******************************************************************************* 714 ** 715 ** Function MCA_DataChnlCfg 716 ** 717 ** Description This function initiates a data channel connection toward the 718 ** connected peer device. 719 ** When the data channel is open successfully, a MCA_OPEN_CFM_EVT 720 ** is reported. This data channel is identified as tMCA_DL. 721 ** 722 ** Returns MCA_SUCCESS if successful, otherwise error. 723 ** 724 *******************************************************************************/ 725 tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg) 726 { 727 tMCA_RESULT result = MCA_BAD_HANDLE; 728 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 729 tMCA_DCB *p_dcb; 730 tMCA_TC_TBL *p_tbl; 731 732 MCA_TRACE_API ("MCA_DataChnlCfg: %d ", mcl); 733 assert(p_chnl_cfg != NULL ); 734 if (p_ccb) 735 { 736 result = MCA_NO_RESOURCES; 737 if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) || 738 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) 739 { 740 MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status); 741 return result; 742 } 743 744 p_dcb->p_chnl_cfg = p_chnl_cfg; 745 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask, 746 p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx); 747 p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg); 748 if (p_dcb->lcid) 749 { 750 p_tbl = mca_tc_tbl_dalloc(p_dcb); 751 if (p_tbl) 752 { 753 p_tbl->state = MCA_TC_ST_CONN; 754 result = MCA_SUCCESS; 755 } 756 } 757 } 758 return result; 759 } 760 761 762 /******************************************************************************* 763 ** 764 ** Function MCA_Abort 765 ** 766 ** Description This function sends a ABORT_MDL request to the peer device. 767 ** When the response is received, a MCA_ABORT_CFM_EVT is reported. 768 ** 769 ** Returns MCA_SUCCESS if successful, otherwise error. 770 ** 771 *******************************************************************************/ 772 tMCA_RESULT MCA_Abort(tMCA_CL mcl) 773 { 774 tMCA_RESULT result = MCA_BAD_HANDLE; 775 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 776 tMCA_DCB *p_dcb; 777 778 MCA_TRACE_API ("MCA_Abort: %d", mcl); 779 if (p_ccb) 780 { 781 result = MCA_NO_RESOURCES; 782 /* verify that we are waiting for data channel to come up with the given mdl */ 783 if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) || 784 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) 785 { 786 MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status); 787 return result; 788 } 789 790 if (p_ccb->cong) 791 { 792 MCA_TRACE_ERROR ("congested"); 793 return MCA_BUSY; 794 } 795 796 tMCA_CCB_MSG *p_evt_data = 797 (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG)); 798 result = MCA_SUCCESS; 799 p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ; 800 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; 801 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); 802 } 803 return result; 804 } 805 806 807 /******************************************************************************* 808 ** 809 ** Function MCA_Delete 810 ** 811 ** Description This function sends a DELETE_MDL request to the peer device. 812 ** When the response is received, a MCA_DELETE_CFM_EVT is reported. 813 ** 814 ** Returns MCA_SUCCESS if successful, otherwise error. 815 ** 816 *******************************************************************************/ 817 tMCA_RESULT MCA_Delete(tMCA_CL mcl, UINT16 mdl_id) 818 { 819 tMCA_RESULT result = MCA_BAD_HANDLE; 820 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl); 821 822 MCA_TRACE_API ("MCA_Delete: %d ", mcl); 823 if (p_ccb) 824 { 825 if (p_ccb->cong) 826 { 827 MCA_TRACE_ERROR ("congested"); 828 return MCA_BUSY; 829 } 830 if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID)) 831 { 832 MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id); 833 return MCA_BAD_PARAMS; 834 } 835 836 tMCA_CCB_MSG *p_evt_data = (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG)); 837 result = MCA_SUCCESS; 838 p_evt_data->mdl_id = mdl_id; 839 p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ; 840 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT; 841 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data); 842 } 843 return result; 844 } 845 846 /******************************************************************************* 847 ** 848 ** Function MCA_WriteReq 849 ** 850 ** Description Send a data packet to the peer device. 851 ** 852 ** The application passes the packet using the BT_HDR structure. 853 ** The offset field must be equal to or greater than L2CAP_MIN_OFFSET. 854 ** This allows enough space in the buffer for the L2CAP header. 855 ** 856 ** The memory pointed to by p_pkt must be a GKI buffer 857 ** allocated by the application. This buffer will be freed 858 ** by the protocol stack; the application must not free 859 ** this buffer. 860 ** 861 ** Returns MCA_SUCCESS if successful, otherwise error. 862 ** 863 *******************************************************************************/ 864 tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt) 865 { 866 tMCA_RESULT result = MCA_BAD_HANDLE; 867 tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl); 868 tMCA_DCB_EVT evt_data; 869 870 MCA_TRACE_API ("MCA_WriteReq: %d ", mdl); 871 if (p_dcb) 872 { 873 if (p_dcb->cong) 874 { 875 result = MCA_BUSY; 876 } 877 else 878 { 879 evt_data.p_pkt = p_pkt; 880 result = MCA_SUCCESS; 881 mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data); 882 } 883 } 884 return result; 885 } 886 887 /******************************************************************************* 888 ** 889 ** Function MCA_GetL2CapChannel 890 ** 891 ** Description Get the L2CAP CID used by the given data channel handle. 892 ** 893 ** Returns L2CAP channel ID if successful, otherwise 0. 894 ** 895 *******************************************************************************/ 896 UINT16 MCA_GetL2CapChannel (tMCA_DL mdl) 897 { 898 UINT16 lcid = 0; 899 tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl); 900 901 MCA_TRACE_API ("MCA_GetL2CapChannel: %d ", mdl); 902 if (p_dcb) 903 lcid = p_dcb->lcid; 904 return lcid; 905 } 906 907