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