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 <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 tMCA_CLOSE close; 276 277 close.param = MCA_ACP; 278 close.reason = reason; 279 close.lcid = p_tbl->lcid; 280 281 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, p_tbl->tcid, 282 p_tbl->cb_idx, p_tbl->state); 283 284 /* Check if the transport channel is in use */ 285 if (p_tbl->state == MCA_TC_ST_UNUSED) return; 286 287 /* clear mca_tc_tbl entry */ 288 if (p_tbl->cfg_flags & MCA_L2C_CFG_DISCN_INT) close.param = MCA_INT; 289 p_tbl->cfg_flags = 0; 290 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; 291 292 /* if control channel, notify ccb that channel close */ 293 if (p_tbl->tcid == MCA_CTRL_TCID) { 294 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 295 mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT*)&close); 296 } 297 /* notify dcb that channel close */ 298 else { 299 /* look up dcb */ 300 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 301 if (p_dcb != NULL) { 302 mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT*)&close); 303 } 304 } 305 p_tbl->state = MCA_TC_ST_UNUSED; 306 } 307 308 /******************************************************************************* 309 * 310 * Function mca_tc_open_ind 311 * 312 * Description This function is called by the L2CAP interface when 313 * the L2CAP channel is opened. It looks up the CCB or DCB 314 * for the channel and sends it an open event. 315 * 316 * Returns Nothing. 317 * 318 ******************************************************************************/ 319 void mca_tc_open_ind(tMCA_TC_TBL* p_tbl) { 320 tMCA_CCB* p_ccb; 321 tMCA_DCB* p_dcb; 322 tMCA_OPEN open; 323 324 MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, 325 p_tbl->cb_idx); 326 p_tbl->state = MCA_TC_ST_OPEN; 327 328 open.peer_mtu = p_tbl->peer_mtu; 329 open.lcid = p_tbl->lcid; 330 /* use param to indicate the role of connection. 331 * MCA_ACP, if ACP */ 332 open.param = MCA_INT; 333 if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) { 334 open.param = MCA_ACP; 335 } 336 337 /* if control channel, notify ccb that channel open */ 338 if (p_tbl->tcid == MCA_CTRL_TCID) { 339 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 340 341 mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT*)&open); 342 } 343 /* must be data channel, notify dcb that channel open */ 344 else { 345 /* look up dcb */ 346 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 347 348 /* put lcid in event data */ 349 if (p_dcb != NULL) { 350 mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT*)&open); 351 } 352 } 353 } 354 355 /******************************************************************************* 356 * 357 * Function mca_tc_cong_ind 358 * 359 * Description This function is called by the L2CAP interface layer when 360 * L2CAP calls the congestion callback. It looks up the CCB 361 * or DCB for the channel and sends it a congestion event. 362 * The is_congested parameter is the same value passed by 363 * the L2CAP callback function. 364 * 365 * 366 * Returns Nothing. 367 * 368 ******************************************************************************/ 369 void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested) { 370 tMCA_CCB* p_ccb; 371 tMCA_DCB* p_dcb; 372 373 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, 374 p_tbl->cb_idx); 375 376 /* if control channel, notify ccb of congestion */ 377 if (p_tbl->tcid == MCA_CTRL_TCID) { 378 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 379 mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT*)&is_congested); 380 } 381 /* notify dcb that channel open */ 382 else { 383 /* look up dcb by cb_idx */ 384 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 385 if (p_dcb != NULL) { 386 mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT*)&is_congested); 387 } 388 } 389 } 390 391 /******************************************************************************* 392 * 393 * Function mca_tc_data_ind 394 * 395 * Description This function is called by the L2CAP interface layer when 396 * incoming data is received from L2CAP. It looks up the CCB 397 * or DCB for the channel and routes the data accordingly. 398 * 399 * Returns Nothing. 400 * 401 ******************************************************************************/ 402 void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf) { 403 tMCA_CCB* p_ccb; 404 tMCA_DCB* p_dcb; 405 uint8_t event = MCA_CCB_MSG_RSP_EVT; 406 uint8_t* p; 407 uint8_t rej_rsp_code = MCA_RSP_SUCCESS; 408 409 MCA_TRACE_DEBUG("%s: tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, 410 p_tbl->cb_idx); 411 412 /* if control channel, handle control message */ 413 if (p_tbl->tcid == MCA_CTRL_TCID) { 414 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx); 415 if (p_ccb) { 416 p = (uint8_t*)(p_buf + 1) + p_buf->offset; 417 /* all the request opcode has bit 0 set. response code has bit 0 clear */ 418 if ((*p) & 0x01) event = MCA_CCB_MSG_REQ_EVT; 419 420 if (*p < MCA_NUM_STANDARD_OPCODE) { 421 if (p_buf->len != mca_std_msg_len[*p]) { 422 MCA_TRACE_ERROR("%s: opcode 0x%02x required len: %d, got len: %d", 423 __func__, *p, mca_std_msg_len[*p], p_buf->len); 424 rej_rsp_code = MCA_RSP_BAD_PARAM; 425 } 426 } else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) { 427 MCA_TRACE_ERROR("%s: unsupported SYNC opcode: 0x%02x len:%d", __func__, 428 *p, p_buf->len); 429 /* reject unsupported request */ 430 rej_rsp_code = MCA_RSP_NO_SUPPORT; 431 } else { 432 MCA_TRACE_ERROR("%s: bad opcode: 0x%02x len:%d", __func__, *p, 433 p_buf->len); 434 /* reject unsupported request */ 435 rej_rsp_code = MCA_RSP_BAD_OPCODE; 436 } 437 438 p_buf->layer_specific = rej_rsp_code; 439 /* forward the request/response to state machine */ 440 mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT*)p_buf); 441 } /* got a valid ccb */ 442 else 443 osi_free(p_buf); 444 } 445 /* else send event to dcb */ 446 else { 447 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx); 448 if (p_dcb != NULL) { 449 mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT*)p_buf); 450 } else 451 osi_free(p_buf); 452 } 453 } 454 455 /******************************************************************************* 456 * 457 * Function mca_rcb_alloc 458 * 459 * Description This function allocates a registration control block. 460 * If no free RCB is available, it returns NULL. 461 * 462 * Returns tMCA_RCB * 463 * 464 ******************************************************************************/ 465 tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg) { 466 int i; 467 tMCA_RCB* p_rcb = NULL; 468 469 for (i = 0; i < MCA_NUM_REGS; i++) { 470 if (mca_cb.rcb[i].p_cback == NULL) { 471 p_rcb = &mca_cb.rcb[i]; 472 memcpy(&p_rcb->reg, p_reg, sizeof(tMCA_REG)); 473 break; 474 } 475 } 476 return p_rcb; 477 } 478 479 /******************************************************************************* 480 * 481 * Function mca_rcb_dealloc 482 * 483 * Description This function deallocates the RCB with the given handle. 484 * 485 * Returns void. 486 * 487 ******************************************************************************/ 488 void mca_rcb_dealloc(tMCA_HANDLE handle) { 489 int i; 490 bool done = true; 491 tMCA_RCB* p_rcb; 492 tMCA_CCB* p_ccb; 493 494 if (handle && (handle <= MCA_NUM_REGS)) { 495 handle--; 496 p_rcb = &mca_cb.rcb[handle]; 497 if (p_rcb->p_cback) { 498 p_ccb = &mca_cb.ccb[handle * MCA_NUM_LINKS]; 499 /* check if all associated CCB are disconnected */ 500 for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb++) { 501 if (p_ccb->p_rcb) { 502 done = false; 503 mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL); 504 } 505 } 506 507 if (done) { 508 memset(p_rcb, 0, sizeof(tMCA_RCB)); 509 MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle); 510 } 511 } 512 } 513 } 514 515 /******************************************************************************* 516 * 517 * Function mca_rcb_to_handle 518 * 519 * Description This function converts a pointer to an RCB to 520 * a handle (tMCA_HANDLE). It returns the handle. 521 * 522 * Returns void. 523 * 524 ******************************************************************************/ 525 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb) { 526 return (uint8_t)(p_rcb - mca_cb.rcb + 1); 527 } 528 529 /******************************************************************************* 530 * 531 * Function mca_rcb_by_handle 532 * 533 * Description This function finds the RCB for a handle (tMCA_HANDLE). 534 * It returns a pointer to the RCB. If no RCB matches the 535 * handle it returns NULL. 536 * 537 * Returns tMCA_RCB * 538 * 539 ******************************************************************************/ 540 tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle) { 541 tMCA_RCB* p_rcb = NULL; 542 543 if (handle && (handle <= MCA_NUM_REGS) && mca_cb.rcb[handle - 1].p_cback) { 544 p_rcb = &mca_cb.rcb[handle - 1]; 545 } 546 return p_rcb; 547 } 548 549 /******************************************************************************* 550 * 551 * Function mca_is_valid_dep_id 552 * 553 * Description This function checks if the given dep_id is valid. 554 * 555 * Returns true, if this is a valid local dep_id 556 * 557 ******************************************************************************/ 558 bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep) { 559 bool valid = false; 560 if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) { 561 valid = true; 562 } 563 return valid; 564 } 565