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 <string.h> 26 27#include "bt_target.h" 28#include "gki.h" 29#include "mca_api.h" 30#include "mca_defs.h" 31#include "mca_int.h" 32#include "wcassert.h" 33#include "l2c_api.h" 34 35/* Main Control block for MCA */ 36#if MCA_DYNAMIC_MEMORY == FALSE 37tMCA_CB mca_cb; 38#endif 39 40/***************************************************************************** 41** constants 42*****************************************************************************/ 43 44/* table of standard opcode message size */ 45const 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*******************************************************************************/ 68tMCA_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*******************************************************************************/ 95tMCA_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*******************************************************************************/ 122tMCA_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 WC_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 MCA_TRACE_DEBUG1("mca_tc_tbl_calloc cb_idx: %d", p_tbl->cb_idx); 149 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*******************************************************************************/ 163tMCA_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 WC_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 MCA_TRACE_DEBUG2("mca_tc_tbl_dalloc tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx); 190 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*******************************************************************************/ 204tMCA_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*******************************************************************************/ 230void 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*******************************************************************************/ 255void 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 p_opt = &p_dcb->p_chnl_cfg->fcr_opt; 269 fcs = p_dcb->p_chnl_cfg->fcs; 270 } 271 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO)); 272 p_cfg->mtu_present = TRUE; 273 p_cfg->mtu = p_tbl->my_mtu; 274 p_cfg->fcr_present = TRUE; 275 memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS)); 276 if (fcs & MCA_FCS_PRESNT_MASK) 277 { 278 p_cfg->fcs_present = TRUE; 279 p_cfg->fcs = (fcs & MCA_FCS_USE_MASK); 280 } 281} 282 283/******************************************************************************* 284** 285** Function mca_tc_close_ind 286** 287** Description This function is called by the L2CAP interface when the 288** L2CAP channel is closed. It looks up the CCB or DCB for 289** the channel and sends it a close event. The reason 290** parameter is the same value passed by the L2CAP 291** callback function. 292** 293** Returns Nothing. 294** 295*******************************************************************************/ 296void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason) 297{ 298 tMCA_CCB *p_ccb; 299 tMCA_DCB *p_dcb; 300 tMCA_CLOSE close; 301 302 close.param = MCA_ACP; 303 close.reason = reason; 304 close.lcid = p_tbl->lcid; 305 306 MCA_TRACE_DEBUG3("mca_tc_close_ind tcid: %d, cb_idx:%d, old: %d", 307 p_tbl->tcid, p_tbl->cb_idx, p_tbl->state); 308 309 /* Check if the transport channel is in use */ 310 if (p_tbl->state == MCA_TC_ST_UNUSED) 311 return; 312 313 /* clear mca_tc_tbl entry */ 314 if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT) 315 close.param = MCA_INT; 316 p_tbl->cfg_flags = 0; 317 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 318 319 /* if control channel, notify ccb that channel close */ 320 if (p_tbl->tcid == MCA_CTRL_TCID) 321 { 322 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 323 mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close); 324 } 325 /* notify dcb that channel close */ 326 else 327 { 328 /* look up dcb */ 329 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 330 if (p_dcb != NULL) 331 { 332 mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close); 333 } 334 } 335 p_tbl->state = MCA_TC_ST_UNUSED; 336} 337 338/******************************************************************************* 339** 340** Function mca_tc_open_ind 341** 342** Description This function is called by the L2CAP interface when 343** the L2CAP channel is opened. It looks up the CCB or DCB 344** for the channel and sends it an open event. 345** 346** Returns Nothing. 347** 348*******************************************************************************/ 349void mca_tc_open_ind(tMCA_TC_TBL *p_tbl) 350{ 351 tMCA_CCB *p_ccb; 352 tMCA_DCB *p_dcb; 353 tMCA_OPEN open; 354 355 MCA_TRACE_DEBUG2("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx); 356 p_tbl->state = MCA_TC_ST_OPEN; 357 358 open.peer_mtu = p_tbl->peer_mtu; 359 open.lcid = p_tbl->lcid; 360 /* use param to indicate the role of connection. 361 * MCA_ACP, if ACP */ 362 open.param = MCA_INT; 363 if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) 364 { 365 open.param = MCA_ACP; 366 } 367 368 /* if control channel, notify ccb that channel open */ 369 if (p_tbl->tcid == MCA_CTRL_TCID) 370 { 371 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 372 373 mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open); 374 } 375 /* must be data channel, notify dcb that channel open */ 376 else 377 { 378 /* look up dcb */ 379 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 380 381 /* put lcid in event data */ 382 if (p_dcb != NULL) 383 { 384 mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open); 385 } 386 } 387} 388 389 390/******************************************************************************* 391** 392** Function mca_tc_cong_ind 393** 394** Description This function is called by the L2CAP interface layer when 395** L2CAP calls the congestion callback. It looks up the CCB 396** or DCB for the channel and sends it a congestion event. 397** The is_congested parameter is the same value passed by 398** the L2CAP callback function. 399** 400** 401** Returns Nothing. 402** 403*******************************************************************************/ 404void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested) 405{ 406 tMCA_CCB *p_ccb; 407 tMCA_DCB *p_dcb; 408 409 MCA_TRACE_DEBUG2("mca_tc_cong_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx); 410 /* if control channel, notify ccb of congestion */ 411 if (p_tbl->tcid == MCA_CTRL_TCID) 412 { 413 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 414 mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested); 415 } 416 /* notify dcb that channel open */ 417 else 418 { 419 /* look up dcb by cb_idx */ 420 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 421 if (p_dcb != NULL) 422 { 423 mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested); 424 } 425 } 426} 427 428 429/******************************************************************************* 430** 431** Function mca_tc_data_ind 432** 433** Description This function is called by the L2CAP interface layer when 434** incoming data is received from L2CAP. It looks up the CCB 435** or DCB for the channel and routes the data accordingly. 436** 437** Returns Nothing. 438** 439*******************************************************************************/ 440void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf) 441{ 442 tMCA_CCB *p_ccb; 443 tMCA_DCB *p_dcb; 444 UINT8 event = MCA_CCB_MSG_RSP_EVT; 445 UINT8 *p; 446 UINT8 rej_rsp_code = MCA_RSP_SUCCESS; 447 448 MCA_TRACE_DEBUG2("mca_tc_data_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx); 449 450 451 /* if control channel, handle control message */ 452 if (p_tbl->tcid == MCA_CTRL_TCID) 453 { 454 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 455 if (p_ccb) 456 { 457 p = (UINT8*)(p_buf+1) + p_buf->offset; 458 /* all the request opcode has bit 0 set. response code has bit 0 clear */ 459 if ((*p) & 0x01) 460 event = MCA_CCB_MSG_REQ_EVT; 461 462 if (*p < MCA_NUM_STANDARD_OPCODE) 463 { 464 if (p_buf->len != mca_std_msg_len[*p]) 465 { 466 MCA_TRACE_ERROR3 ("opcode: %d required len:%d, got len:%d", *p, mca_std_msg_len[*p], p_buf->len); 467 rej_rsp_code = MCA_RSP_BAD_PARAM; 468 } 469 } 470 else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) 471 { 472 MCA_TRACE_ERROR2 ("unsupported SYNC opcode: %d len:%d", *p, p_buf->len); 473 /* reject unsupported request */ 474 rej_rsp_code = MCA_RSP_NO_SUPPORT; 475 } 476 else 477 { 478 MCA_TRACE_ERROR2 ("bad opcode: %d len:%d", *p, p_buf->len); 479 /* reject unsupported request */ 480 rej_rsp_code = MCA_RSP_BAD_OPCODE; 481 } 482 483 p_buf->layer_specific = rej_rsp_code; 484 /* forward the request/response to state machine */ 485 mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf); 486 } /* got a valid ccb */ 487 else 488 GKI_freebuf(p_buf); 489 } 490 /* else send event to dcb */ 491 else 492 { 493 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 494 if (p_dcb != NULL) 495 { 496 mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf); 497 } 498 else 499 GKI_freebuf(p_buf); 500 } 501} 502 503/******************************************************************************* 504** 505** Function mca_rcb_alloc 506** 507** Description This function allocates a registration control block. 508** If no free RCB is available, it returns NULL. 509** 510** Returns tMCA_RCB * 511** 512*******************************************************************************/ 513tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg) 514{ 515 int i; 516 tMCA_RCB *p_rcb = NULL; 517 518 for (i=0; i<MCA_NUM_REGS; i++) 519 { 520 if (mca_cb.rcb[i].p_cback == NULL) 521 { 522 p_rcb = &mca_cb.rcb[i]; 523 memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG)); 524 break; 525 } 526 } 527 return p_rcb; 528} 529 530/******************************************************************************* 531** 532** Function mca_rcb_dealloc 533** 534** Description This function deallocates the RCB with the given handle. 535** 536** Returns void. 537** 538*******************************************************************************/ 539void mca_rcb_dealloc(tMCA_HANDLE handle) 540{ 541 int i; 542 BOOLEAN done = TRUE; 543 tMCA_RCB *p_rcb; 544 tMCA_CCB *p_ccb; 545 546 if (handle && (handle<=MCA_NUM_REGS)) 547 { 548 handle--; 549 p_rcb = &mca_cb.rcb[handle]; 550 if (p_rcb->p_cback) 551 { 552 p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS]; 553 /* check if all associated CCB are disconnected */ 554 for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++) 555 { 556 if (p_ccb->p_rcb) 557 { 558 done = FALSE; 559 mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL); 560 } 561 } 562 563 if (done) 564 { 565 memset (p_rcb, 0, sizeof(tMCA_RCB)); 566 MCA_TRACE_DEBUG1("Reset MCA_RCB index=%d",handle); 567 } 568 } 569 } 570} 571 572/******************************************************************************* 573** 574** Function mca_rcb_to_handle 575** 576** Description This function converts a pointer to an RCB to 577** a handle (tMCA_HANDLE). It returns the handle. 578** 579** Returns void. 580** 581*******************************************************************************/ 582tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb) 583{ 584 return(UINT8) (p_rcb - mca_cb.rcb + 1); 585} 586 587/******************************************************************************* 588** 589** Function mca_rcb_by_handle 590** 591** Description This function finds the RCB for a handle (tMCA_HANDLE). 592** It returns a pointer to the RCB. If no RCB matches the 593** handle it returns NULL. 594** 595** Returns tMCA_RCB * 596** 597*******************************************************************************/ 598tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle) 599{ 600 tMCA_RCB *p_rcb = NULL; 601 602 if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback) 603 { 604 p_rcb = &mca_cb.rcb[handle-1]; 605 } 606 return p_rcb; 607} 608 609/******************************************************************************* 610** 611** Function mca_is_valid_dep_id 612** 613** Description This function checks if the given dep_id is valid. 614** 615** Returns TRUE, if this is a valid local dep_id 616** 617*******************************************************************************/ 618BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep) 619{ 620 BOOLEAN valid = FALSE; 621 if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) 622 { 623 valid = TRUE; 624 } 625 return valid; 626} 627 628/******************************************************************************* 629** 630** Function mca_free_buf 631** 632** Description free memory for specified GKI packet 633** 634** Returns void 635** 636*******************************************************************************/ 637void mca_free_buf (void **p_buf) 638{ 639 if (p_buf && *p_buf) 640 { 641 GKI_freebuf(*p_buf); 642 *p_buf = NULL; 643 } 644} 645