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