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 implementation file for the MCAP Main Control Block and 22 * Utility functions. 23 * 24 ******************************************************************************/ 25 #include <assert.h> 26 #include <string.h> 27 28 #include "bt_target.h" 29 #include "bt_common.h" 30 #include "mca_api.h" 31 #include "mca_defs.h" 32 #include "mca_int.h" 33 #include "l2c_api.h" 34 35 /* Main Control block for MCA */ 36 #if MCA_DYNAMIC_MEMORY == FALSE 37 tMCA_CB mca_cb; 38 #endif 39 40 /***************************************************************************** 41 ** constants 42 *****************************************************************************/ 43 44 /* table of standard opcode message size */ 45 const UINT8 mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = { 46 4, /* MCA_OP_ERROR_RSP */ 47 5, /* MCA_OP_MDL_CREATE_REQ */ 48 5, /* MCA_OP_MDL_CREATE_RSP */ 49 3, /* MCA_OP_MDL_RECONNECT_REQ */ 50 4, /* MCA_OP_MDL_RECONNECT_RSP */ 51 3, /* MCA_OP_MDL_ABORT_REQ */ 52 4, /* MCA_OP_MDL_ABORT_RSP */ 53 3, /* MCA_OP_MDL_DELETE_REQ */ 54 4 /* MCA_OP_MDL_DELETE_RSP */ 55 }; 56 57 58 /******************************************************************************* 59 ** 60 ** Function mca_handle_by_cpsm 61 ** 62 ** Description This function returns the handle for the given control 63 ** channel PSM. 0, if not found. 64 ** 65 ** Returns the MCA handle. 66 ** 67 *******************************************************************************/ 68 tMCA_HANDLE mca_handle_by_cpsm(UINT16 psm) 69 { 70 int i; 71 tMCA_HANDLE handle = 0; 72 tMCA_RCB *p_rcb = &mca_cb.rcb[0]; 73 74 for (i=0; i<MCA_NUM_REGS; i++, p_rcb++) 75 { 76 if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm) 77 { 78 handle = i+1; 79 break; 80 } 81 } 82 return handle; 83 } 84 85 /******************************************************************************* 86 ** 87 ** Function mca_handle_by_dpsm 88 ** 89 ** Description This function returns the handle for the given data 90 ** channel PSM. 0, if not found. 91 ** 92 ** Returns the MCA handle. 93 ** 94 *******************************************************************************/ 95 tMCA_HANDLE mca_handle_by_dpsm(UINT16 psm) 96 { 97 int i; 98 tMCA_HANDLE handle = 0; 99 tMCA_RCB *p_rcb = &mca_cb.rcb[0]; 100 101 for (i=0; i<MCA_NUM_REGS; i++, p_rcb++) 102 { 103 if (p_rcb->p_cback && p_rcb->reg.data_psm == psm) 104 { 105 handle = i+1; 106 break; 107 } 108 } 109 return handle; 110 } 111 112 /******************************************************************************* 113 ** 114 ** Function mca_tc_tbl_calloc 115 ** 116 ** Description This function allocates a transport table for the given 117 ** control channel. 118 ** 119 ** Returns The tranport table. 120 ** 121 *******************************************************************************/ 122 tMCA_TC_TBL * mca_tc_tbl_calloc(tMCA_CCB *p_ccb) 123 { 124 tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl; 125 int i; 126 127 /* find next free entry in tc table */ 128 for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) 129 { 130 if (p_tbl->state == MCA_TC_ST_UNUSED) 131 { 132 break; 133 } 134 } 135 136 /* sanity check */ 137 assert(i != MCA_NUM_TC_TBL); 138 139 /* initialize entry */ 140 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 141 p_tbl->cfg_flags= 0; 142 p_tbl->cb_idx = mca_ccb_to_hdl(p_ccb); 143 p_tbl->tcid = MCA_CTRL_TCID; 144 p_tbl->my_mtu = MCA_CTRL_MTU; 145 p_tbl->state = MCA_TC_ST_IDLE; 146 p_tbl->lcid = p_ccb->lcid; 147 mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i; 148 149 MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx); 150 return p_tbl; 151 } 152 153 /******************************************************************************* 154 ** 155 ** Function mca_tc_tbl_dalloc 156 ** 157 ** Description This function allocates a transport table for the given 158 ** data channel. 159 ** 160 ** Returns The tranport table. 161 ** 162 *******************************************************************************/ 163 tMCA_TC_TBL * mca_tc_tbl_dalloc(tMCA_DCB *p_dcb) 164 { 165 tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl; 166 int i; 167 168 /* find next free entry in tc table */ 169 for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) 170 { 171 if (p_tbl->state == MCA_TC_ST_UNUSED) 172 { 173 break; 174 } 175 } 176 177 /* sanity check */ 178 assert(i != MCA_NUM_TC_TBL); 179 180 /* initialize entry */ 181 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 182 p_tbl->cfg_flags= 0; 183 p_tbl->cb_idx = mca_dcb_to_hdl(p_dcb); 184 p_tbl->tcid = p_dcb->p_cs->type + 1; 185 p_tbl->my_mtu = p_dcb->p_chnl_cfg->data_mtu; 186 p_tbl->state = MCA_TC_ST_IDLE; 187 p_tbl->lcid = p_dcb->lcid; 188 mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i; 189 190 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx); 191 return p_tbl; 192 } 193 194 /******************************************************************************* 195 ** 196 ** Function mca_tc_tbl_by_lcid 197 ** 198 ** Description Find the transport channel table entry by LCID. 199 ** 200 ** 201 ** Returns The tranport table. 202 ** 203 *******************************************************************************/ 204 tMCA_TC_TBL *mca_tc_tbl_by_lcid(UINT16 lcid) 205 { 206 UINT8 idx; 207 208 if (lcid) 209 { 210 idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID]; 211 212 if (idx < MCA_NUM_TC_TBL) 213 { 214 return &mca_cb.tc.tc_tbl[idx]; 215 } 216 } 217 return NULL; 218 } 219 220 /******************************************************************************* 221 ** 222 ** Function mca_free_tc_tbl_by_lcid 223 ** 224 ** Description Find the transport table entry by LCID 225 ** and free the tc_tbl 226 ** 227 ** Returns void. 228 ** 229 *******************************************************************************/ 230 void mca_free_tc_tbl_by_lcid(UINT16 lcid) 231 { 232 UINT8 idx; 233 234 if (lcid) 235 { 236 idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID]; 237 238 if (idx < MCA_NUM_TC_TBL) 239 { 240 mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED; 241 } 242 } 243 } 244 245 246 /******************************************************************************* 247 ** 248 ** Function mca_set_cfg_by_tbl 249 ** 250 ** Description Set the L2CAP configuration information 251 ** 252 ** Returns none. 253 ** 254 *******************************************************************************/ 255 void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl) 256 { 257 tMCA_DCB *p_dcb; 258 const tL2CAP_FCR_OPTS *p_opt; 259 tMCA_FCS_OPT fcs = MCA_FCS_NONE; 260 261 if (p_tbl->tcid == MCA_CTRL_TCID) 262 { 263 p_opt = &mca_l2c_fcr_opts_def; 264 } 265 else 266 { 267 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 268 if (p_dcb) 269 { 270 p_opt = &p_dcb->p_chnl_cfg->fcr_opt; 271 fcs = p_dcb->p_chnl_cfg->fcs; 272 } 273 } 274 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO)); 275 p_cfg->mtu_present = TRUE; 276 p_cfg->mtu = p_tbl->my_mtu; 277 p_cfg->fcr_present = TRUE; 278 memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS)); 279 if (fcs & MCA_FCS_PRESNT_MASK) 280 { 281 p_cfg->fcs_present = TRUE; 282 p_cfg->fcs = (fcs & MCA_FCS_USE_MASK); 283 } 284 } 285 286 /******************************************************************************* 287 ** 288 ** Function mca_tc_close_ind 289 ** 290 ** Description This function is called by the L2CAP interface when the 291 ** L2CAP channel is closed. It looks up the CCB or DCB for 292 ** the channel and sends it a close event. The reason 293 ** parameter is the same value passed by the L2CAP 294 ** callback function. 295 ** 296 ** Returns Nothing. 297 ** 298 *******************************************************************************/ 299 void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason) 300 { 301 tMCA_CCB *p_ccb; 302 tMCA_DCB *p_dcb; 303 tMCA_CLOSE close; 304 305 close.param = MCA_ACP; 306 close.reason = reason; 307 close.lcid = p_tbl->lcid; 308 309 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, 310 p_tbl->tcid, p_tbl->cb_idx, p_tbl->state); 311 312 /* Check if the transport channel is in use */ 313 if (p_tbl->state == MCA_TC_ST_UNUSED) 314 return; 315 316 /* clear mca_tc_tbl entry */ 317 if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT) 318 close.param = MCA_INT; 319 p_tbl->cfg_flags = 0; 320 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 321 322 /* if control channel, notify ccb that channel close */ 323 if (p_tbl->tcid == MCA_CTRL_TCID) 324 { 325 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 326 mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close); 327 } 328 /* notify dcb that channel close */ 329 else 330 { 331 /* look up dcb */ 332 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 333 if (p_dcb != NULL) 334 { 335 mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close); 336 } 337 } 338 p_tbl->state = MCA_TC_ST_UNUSED; 339 } 340 341 /******************************************************************************* 342 ** 343 ** Function mca_tc_open_ind 344 ** 345 ** Description This function is called by the L2CAP interface when 346 ** the L2CAP channel is opened. It looks up the CCB or DCB 347 ** for the channel and sends it an open event. 348 ** 349 ** Returns Nothing. 350 ** 351 *******************************************************************************/ 352 void mca_tc_open_ind(tMCA_TC_TBL *p_tbl) 353 { 354 tMCA_CCB *p_ccb; 355 tMCA_DCB *p_dcb; 356 tMCA_OPEN open; 357 358 MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx); 359 p_tbl->state = MCA_TC_ST_OPEN; 360 361 open.peer_mtu = p_tbl->peer_mtu; 362 open.lcid = p_tbl->lcid; 363 /* use param to indicate the role of connection. 364 * MCA_ACP, if ACP */ 365 open.param = MCA_INT; 366 if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) 367 { 368 open.param = MCA_ACP; 369 } 370 371 /* if control channel, notify ccb that channel open */ 372 if (p_tbl->tcid == MCA_CTRL_TCID) 373 { 374 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 375 376 mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open); 377 } 378 /* must be data channel, notify dcb that channel open */ 379 else 380 { 381 /* look up dcb */ 382 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 383 384 /* put lcid in event data */ 385 if (p_dcb != NULL) 386 { 387 mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open); 388 } 389 } 390 } 391 392 393 /******************************************************************************* 394 ** 395 ** Function mca_tc_cong_ind 396 ** 397 ** Description This function is called by the L2CAP interface layer when 398 ** L2CAP calls the congestion callback. It looks up the CCB 399 ** or DCB for the channel and sends it a congestion event. 400 ** The is_congested parameter is the same value passed by 401 ** the L2CAP callback function. 402 ** 403 ** 404 ** Returns Nothing. 405 ** 406 *******************************************************************************/ 407 void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested) 408 { 409 tMCA_CCB *p_ccb; 410 tMCA_DCB *p_dcb; 411 412 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx); 413 414 /* if control channel, notify ccb of congestion */ 415 if (p_tbl->tcid == MCA_CTRL_TCID) 416 { 417 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 418 mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested); 419 } 420 /* notify dcb that channel open */ 421 else 422 { 423 /* look up dcb by cb_idx */ 424 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 425 if (p_dcb != NULL) 426 { 427 mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested); 428 } 429 } 430 } 431 432 433 /******************************************************************************* 434 ** 435 ** Function mca_tc_data_ind 436 ** 437 ** Description This function is called by the L2CAP interface layer when 438 ** incoming data is received from L2CAP. It looks up the CCB 439 ** or DCB for the channel and routes the data accordingly. 440 ** 441 ** Returns Nothing. 442 ** 443 *******************************************************************************/ 444 void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf) 445 { 446 tMCA_CCB *p_ccb; 447 tMCA_DCB *p_dcb; 448 UINT8 event = MCA_CCB_MSG_RSP_EVT; 449 UINT8 *p; 450 UINT8 rej_rsp_code = MCA_RSP_SUCCESS; 451 452 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx); 453 454 /* if control channel, handle control message */ 455 if (p_tbl->tcid == MCA_CTRL_TCID) 456 { 457 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 458 if (p_ccb) 459 { 460 p = (UINT8*)(p_buf+1) + p_buf->offset; 461 /* all the request opcode has bit 0 set. response code has bit 0 clear */ 462 if ((*p) & 0x01) 463 event = MCA_CCB_MSG_REQ_EVT; 464 465 if (*p < MCA_NUM_STANDARD_OPCODE) 466 { 467 if (p_buf->len != mca_std_msg_len[*p]) 468 { 469 MCA_TRACE_ERROR ("$s() - opcode: %d required len: %d, got len: %d" 470 , __func__, *p, mca_std_msg_len[*p], p_buf->len); 471 rej_rsp_code = MCA_RSP_BAD_PARAM; 472 } 473 } 474 else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) 475 { 476 MCA_TRACE_ERROR ("%s() - unsupported SYNC opcode: %d len:%d" 477 , __func__, *p, p_buf->len); 478 /* reject unsupported request */ 479 rej_rsp_code = MCA_RSP_NO_SUPPORT; 480 } 481 else 482 { 483 MCA_TRACE_ERROR ("%s() - bad opcode: %d len:%d", __func__, *p, p_buf->len); 484 /* reject unsupported request */ 485 rej_rsp_code = MCA_RSP_BAD_OPCODE; 486 } 487 488 p_buf->layer_specific = rej_rsp_code; 489 /* forward the request/response to state machine */ 490 mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf); 491 } /* got a valid ccb */ 492 else 493 osi_free(p_buf); 494 } 495 /* else send event to dcb */ 496 else 497 { 498 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 499 if (p_dcb != NULL) 500 { 501 mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf); 502 } 503 else 504 osi_free(p_buf); 505 } 506 } 507 508 /******************************************************************************* 509 ** 510 ** Function mca_rcb_alloc 511 ** 512 ** Description This function allocates a registration control block. 513 ** If no free RCB is available, it returns NULL. 514 ** 515 ** Returns tMCA_RCB * 516 ** 517 *******************************************************************************/ 518 tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg) 519 { 520 int i; 521 tMCA_RCB *p_rcb = NULL; 522 523 for (i=0; i<MCA_NUM_REGS; i++) 524 { 525 if (mca_cb.rcb[i].p_cback == NULL) 526 { 527 p_rcb = &mca_cb.rcb[i]; 528 memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG)); 529 break; 530 } 531 } 532 return p_rcb; 533 } 534 535 /******************************************************************************* 536 ** 537 ** Function mca_rcb_dealloc 538 ** 539 ** Description This function deallocates the RCB with the given handle. 540 ** 541 ** Returns void. 542 ** 543 *******************************************************************************/ 544 void mca_rcb_dealloc(tMCA_HANDLE handle) 545 { 546 int i; 547 BOOLEAN done = TRUE; 548 tMCA_RCB *p_rcb; 549 tMCA_CCB *p_ccb; 550 551 if (handle && (handle<=MCA_NUM_REGS)) 552 { 553 handle--; 554 p_rcb = &mca_cb.rcb[handle]; 555 if (p_rcb->p_cback) 556 { 557 p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS]; 558 /* check if all associated CCB are disconnected */ 559 for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++) 560 { 561 if (p_ccb->p_rcb) 562 { 563 done = FALSE; 564 mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL); 565 } 566 } 567 568 if (done) 569 { 570 memset (p_rcb, 0, sizeof(tMCA_RCB)); 571 MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle); 572 } 573 } 574 } 575 } 576 577 /******************************************************************************* 578 ** 579 ** Function mca_rcb_to_handle 580 ** 581 ** Description This function converts a pointer to an RCB to 582 ** a handle (tMCA_HANDLE). It returns the handle. 583 ** 584 ** Returns void. 585 ** 586 *******************************************************************************/ 587 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb) 588 { 589 return(UINT8) (p_rcb - mca_cb.rcb + 1); 590 } 591 592 /******************************************************************************* 593 ** 594 ** Function mca_rcb_by_handle 595 ** 596 ** Description This function finds the RCB for a handle (tMCA_HANDLE). 597 ** It returns a pointer to the RCB. If no RCB matches the 598 ** handle it returns NULL. 599 ** 600 ** Returns tMCA_RCB * 601 ** 602 *******************************************************************************/ 603 tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle) 604 { 605 tMCA_RCB *p_rcb = NULL; 606 607 if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback) 608 { 609 p_rcb = &mca_cb.rcb[handle-1]; 610 } 611 return p_rcb; 612 } 613 614 /******************************************************************************* 615 ** 616 ** Function mca_is_valid_dep_id 617 ** 618 ** Description This function checks if the given dep_id is valid. 619 ** 620 ** Returns TRUE, if this is a valid local dep_id 621 ** 622 *******************************************************************************/ 623 BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep) 624 { 625 BOOLEAN valid = FALSE; 626 if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) 627 { 628 valid = TRUE; 629 } 630 return valid; 631 } 632