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 Control Channel Action 22 * Functions. 23 * 24 ******************************************************************************/ 25 #include <string.h> 26 #include "bt_target.h" 27 #include "bt_utils.h" 28 #include "bt_common.h" 29 #include "btm_api.h" 30 #include "mca_api.h" 31 #include "mca_defs.h" 32 #include "mca_int.h" 33 34 35 #include "btu.h" 36 37 extern fixed_queue_t *btu_general_alarm_queue; 38 39 /***************************************************************************** 40 ** constants 41 *****************************************************************************/ 42 /******************************************************************************* 43 ** 44 ** Function mca_ccb_rsp_tout 45 ** 46 ** Description This function processes the response timeout. 47 ** 48 ** Returns void. 49 ** 50 *******************************************************************************/ 51 void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 52 { 53 tMCA_CTRL evt_data; 54 UNUSED(p_data); 55 56 mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data); 57 } 58 59 /******************************************************************************* 60 ** 61 ** Function mca_ccb_report_event 62 ** 63 ** Description This function reports the given event. 64 ** 65 ** Returns void. 66 ** 67 *******************************************************************************/ 68 void mca_ccb_report_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CTRL *p_data) 69 { 70 if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback) 71 (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb), mca_ccb_to_hdl(p_ccb), event, p_data); 72 } 73 74 /******************************************************************************* 75 ** 76 ** Function mca_ccb_free_msg 77 ** 78 ** Description This function frees the received message. 79 ** 80 ** Returns void. 81 ** 82 *******************************************************************************/ 83 void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 84 { 85 UNUSED(p_ccb); 86 osi_free(p_data); 87 } 88 89 /******************************************************************************* 90 ** 91 ** Function mca_ccb_snd_req 92 ** 93 ** Description This function builds a request and sends it to the peer. 94 ** 95 ** Returns void. 96 ** 97 *******************************************************************************/ 98 void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 99 { 100 tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data; 101 UINT8 *p, *p_start; 102 BOOLEAN is_abort = FALSE; 103 tMCA_DCB *p_dcb; 104 105 MCA_TRACE_DEBUG ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code); 106 /* check for abort request */ 107 if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ)) 108 { 109 p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx); 110 /* the Abort API does not have the associated mdl_id. 111 * Get the mdl_id in dcb to compose the request */ 112 p_msg->mdl_id = p_dcb->mdl_id; 113 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); 114 osi_free_and_reset((void **)&p_ccb->p_tx_req); 115 p_ccb->status = MCA_CCB_STAT_NORM; 116 is_abort = TRUE; 117 } 118 119 /* no pending outgoing messages or it's an abort request for a pending data channel */ 120 if ((!p_ccb->p_tx_req) || is_abort) 121 { 122 p_ccb->p_tx_req = p_msg; 123 if (!p_ccb->cong) 124 { 125 BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU); 126 127 p_pkt->offset = L2CAP_MIN_OFFSET; 128 p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET; 129 *p++ = p_msg->op_code; 130 UINT16_TO_BE_STREAM (p, p_msg->mdl_id); 131 if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ) { 132 *p++ = p_msg->mdep_id; 133 *p++ = p_msg->param; 134 } 135 p_msg->hdr.layer_specific = TRUE; /* mark this message as sent */ 136 p_pkt->len = p - p_start; 137 L2CA_DataWrite (p_ccb->lcid, p_pkt); 138 period_ms_t interval_ms = p_ccb->p_rcb->reg.rsp_tout * 1000; 139 alarm_set_on_queue(p_ccb->mca_ccb_timer, interval_ms, 140 mca_ccb_timer_timeout, p_ccb, 141 btu_general_alarm_queue); 142 } 143 /* else the L2CAP channel is congested. keep the message to be sent later */ 144 } 145 else 146 { 147 MCA_TRACE_WARNING ("dropping api req"); 148 osi_free(p_data); 149 } 150 } 151 152 /******************************************************************************* 153 ** 154 ** Function mca_ccb_snd_rsp 155 ** 156 ** Description This function builds a response and sends it to 157 ** the peer. 158 ** 159 ** Returns void. 160 ** 161 *******************************************************************************/ 162 void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 163 { 164 tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data; 165 UINT8 *p, *p_start; 166 BOOLEAN chk_mdl = FALSE; 167 BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU); 168 169 MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code); 170 /* assume that API functions verified the parameters */ 171 172 p_pkt->offset = L2CAP_MIN_OFFSET; 173 p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET; 174 *p++ = p_msg->op_code; 175 *p++ = p_msg->rsp_code; 176 UINT16_TO_BE_STREAM (p, p_msg->mdl_id); 177 if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP) { 178 *p++ = p_msg->param; 179 chk_mdl = TRUE; 180 } 181 else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP) { 182 chk_mdl = TRUE; 183 } 184 185 if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS) { 186 mca_dcb_by_hdl(p_msg->dcb_idx); 187 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, 188 p_ccb->sec_mask, 189 p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA, 190 p_msg->dcb_idx); 191 p_ccb->status = MCA_CCB_STAT_PENDING; 192 /* set p_tx_req to block API_REQ/API_RSP before DL is up */ 193 osi_free_and_reset((void **)&p_ccb->p_tx_req); 194 p_ccb->p_tx_req = p_ccb->p_rx_msg; 195 p_ccb->p_rx_msg = NULL; 196 p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx; 197 } 198 osi_free_and_reset((void **)&p_ccb->p_rx_msg); 199 p_pkt->len = p - p_start; 200 L2CA_DataWrite(p_ccb->lcid, p_pkt); 201 } 202 203 /******************************************************************************* 204 ** 205 ** Function mca_ccb_do_disconn 206 ** 207 ** Description This function closes a control channel. 208 ** 209 ** Returns void. 210 ** 211 *******************************************************************************/ 212 void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 213 { 214 UNUSED(p_data); 215 216 mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID); 217 L2CA_DisconnectReq(p_ccb->lcid); 218 } 219 220 /******************************************************************************* 221 ** 222 ** Function mca_ccb_cong 223 ** 224 ** Description This function sets the congestion state for the CCB. 225 ** 226 ** Returns void. 227 ** 228 *******************************************************************************/ 229 void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 230 { 231 MCA_TRACE_DEBUG ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong); 232 p_ccb->cong = p_data->llcong; 233 if (!p_ccb->cong) 234 { 235 /* if there's a held packet, send it now */ 236 if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific) 237 { 238 p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req; 239 p_ccb->p_tx_req = NULL; 240 mca_ccb_snd_req (p_ccb, p_data); 241 } 242 } 243 } 244 245 /******************************************************************************* 246 ** 247 ** Function mca_ccb_hdl_req 248 ** 249 ** Description This function is called when a MCAP request is received from 250 ** the peer. It calls the application callback function to 251 ** report the event. 252 ** 253 ** Returns void. 254 ** 255 *******************************************************************************/ 256 void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 257 { 258 BT_HDR *p_pkt = &p_data->hdr; 259 UINT8 *p, *p_start; 260 tMCA_DCB *p_dcb; 261 tMCA_CTRL evt_data; 262 tMCA_CCB_MSG *p_rx_msg = NULL; 263 UINT8 reject_code = MCA_RSP_NO_RESOURCE; 264 BOOLEAN send_rsp = FALSE; 265 BOOLEAN check_req = FALSE; 266 UINT8 reject_opcode; 267 268 MCA_TRACE_DEBUG ("mca_ccb_hdl_req status:%d", p_ccb->status); 269 p_rx_msg = (tMCA_CCB_MSG *)p_pkt; 270 p = (UINT8 *)(p_pkt + 1) + p_pkt->offset; 271 evt_data.hdr.op_code = *p++; 272 BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p); 273 reject_opcode = evt_data.hdr.op_code+1; 274 275 MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id); 276 if (p_ccb->status == MCA_CCB_STAT_PENDING) 277 { 278 MCA_TRACE_DEBUG ("received req inpending state"); 279 /* allow abort in pending state */ 280 if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ)) 281 { 282 reject_code = MCA_RSP_SUCCESS; 283 send_rsp = TRUE; 284 /* clear the pending status */ 285 p_ccb->status = MCA_CCB_STAT_NORM; 286 if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL)) 287 { 288 mca_dcb_dealloc(p_dcb, NULL); 289 osi_free_and_reset((void **)&p_ccb->p_tx_req); 290 } 291 } 292 else 293 reject_code = MCA_RSP_BAD_OP; 294 } 295 else if (p_ccb->p_rx_msg) 296 { 297 MCA_TRACE_DEBUG ("still handling prev req"); 298 /* still holding previous message, reject this new one ?? */ 299 300 } 301 else if (p_ccb->p_tx_req) 302 { 303 MCA_TRACE_DEBUG ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm); 304 /* sent a request; waiting for response */ 305 if (p_ccb->ctrl_vpsm == 0) 306 { 307 MCA_TRACE_DEBUG ("local is ACP. accept the cmd from INT"); 308 /* local is acceptor, need to handle the request */ 309 check_req = TRUE; 310 reject_code = MCA_RSP_SUCCESS; 311 /* drop the previous request */ 312 if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) && 313 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) 314 { 315 mca_dcb_dealloc(p_dcb, NULL); 316 } 317 osi_free_and_reset((void **)&p_ccb->p_tx_req); 318 mca_stop_timer(p_ccb); 319 } 320 else 321 { 322 /* local is initiator, ignore the req */ 323 osi_free(p_pkt); 324 return; 325 } 326 } 327 else if (p_pkt->layer_specific != MCA_RSP_SUCCESS) 328 { 329 330 reject_code = (UINT8)p_pkt->layer_specific; 331 if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) && 332 (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) || 333 (evt_data.hdr.op_code > MCA_LAST_SYNC_OP)) 334 { 335 /* invalid op code */ 336 reject_opcode = MCA_OP_ERROR_RSP; 337 evt_data.hdr.mdl_id = 0; 338 } 339 } 340 else 341 { 342 check_req = TRUE; 343 reject_code = MCA_RSP_SUCCESS; 344 } 345 346 if (check_req) 347 { 348 if (reject_code == MCA_RSP_SUCCESS) 349 { 350 reject_code = MCA_RSP_BAD_MDL; 351 if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) || 352 ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ))) 353 { 354 reject_code = MCA_RSP_SUCCESS; 355 /* mdl_id is valid according to the spec */ 356 switch (evt_data.hdr.op_code) 357 { 358 case MCA_OP_MDL_CREATE_REQ: 359 evt_data.create_ind.dep_id = *p++; 360 evt_data.create_ind.cfg = *p++; 361 p_rx_msg->mdep_id = evt_data.create_ind.dep_id; 362 if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id)) 363 { 364 MCA_TRACE_ERROR ("not a valid local mdep id"); 365 reject_code = MCA_RSP_BAD_MDEP; 366 } 367 else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) 368 { 369 MCA_TRACE_DEBUG ("the mdl_id is currently used in the CL(create)"); 370 mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id); 371 } 372 else 373 { 374 /* check if this dep still have MDL available */ 375 if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0) 376 { 377 MCA_TRACE_ERROR ("the mdep is currently using max_mdl"); 378 reject_code = MCA_RSP_MDEP_BUSY; 379 } 380 } 381 break; 382 383 case MCA_OP_MDL_RECONNECT_REQ: 384 if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) 385 { 386 MCA_TRACE_ERROR ("the mdl_id is currently used in the CL(reconn)"); 387 reject_code = MCA_RSP_MDL_BUSY; 388 } 389 break; 390 391 case MCA_OP_MDL_ABORT_REQ: 392 reject_code = MCA_RSP_BAD_OP; 393 break; 394 395 case MCA_OP_MDL_DELETE_REQ: 396 /* delete the associated mdl */ 397 mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id); 398 send_rsp = TRUE; 399 break; 400 } 401 } 402 } 403 } 404 405 if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND)) 406 || send_rsp) { 407 BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU); 408 p_buf->offset = L2CAP_MIN_OFFSET; 409 p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET; 410 *p++ = reject_opcode; 411 *p++ = reject_code; 412 UINT16_TO_BE_STREAM(p, evt_data.hdr.mdl_id); 413 /* 414 if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS)) 415 { 416 *p++ = evt_data.create_ind.cfg; 417 } 418 */ 419 420 p_buf->len = p - p_start; 421 L2CA_DataWrite (p_ccb->lcid, p_buf); 422 } 423 424 if (reject_code == MCA_RSP_SUCCESS) 425 { 426 /* use the received GKI buffer to store information to double check response API */ 427 p_rx_msg->op_code = evt_data.hdr.op_code; 428 p_rx_msg->mdl_id = evt_data.hdr.mdl_id; 429 p_ccb->p_rx_msg = p_rx_msg; 430 if (send_rsp) 431 { 432 osi_free(p_pkt); 433 p_ccb->p_rx_msg = NULL; 434 } 435 mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data); 436 } 437 else 438 osi_free(p_pkt); 439 } 440 441 /******************************************************************************* 442 ** 443 ** Function mca_ccb_hdl_rsp 444 ** 445 ** Description This function is called when a MCAP response is received from 446 ** the peer. It calls the application callback function with 447 ** the results. 448 ** 449 ** Returns void. 450 ** 451 *******************************************************************************/ 452 void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 453 { 454 BT_HDR *p_pkt = &p_data->hdr; 455 UINT8 *p; 456 tMCA_CTRL evt_data; 457 BOOLEAN chk_mdl = FALSE; 458 tMCA_DCB *p_dcb; 459 tMCA_RESULT result = MCA_BAD_HANDLE; 460 tMCA_TC_TBL *p_tbl; 461 462 if (p_ccb->p_tx_req) 463 { 464 /* verify that the received response matches the sent request */ 465 p = (UINT8 *)(p_pkt + 1) + p_pkt->offset; 466 evt_data.hdr.op_code = *p++; 467 if ((evt_data.hdr.op_code == 0) || 468 ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code)) 469 { 470 evt_data.rsp.rsp_code = *p++; 471 mca_stop_timer(p_ccb); 472 BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p); 473 if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP) 474 { 475 evt_data.create_cfm.cfg = *p++; 476 chk_mdl = TRUE; 477 } 478 else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP) 479 chk_mdl = TRUE; 480 481 if (chk_mdl) 482 { 483 p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx); 484 if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS) 485 { 486 if (evt_data.hdr.mdl_id != p_dcb->mdl_id) 487 { 488 MCA_TRACE_ERROR ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id); 489 /* change the response code to be an error */ 490 if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS) 491 { 492 evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL; 493 /* send Abort */ 494 p_ccb->status = MCA_CCB_STAT_PENDING; 495 MCA_Abort(mca_ccb_to_hdl(p_ccb)); 496 } 497 } 498 else if (p_dcb->p_chnl_cfg) 499 { 500 /* the data channel configuration is known. Proceed with data channel initiation */ 501 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask, 502 p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx); 503 p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg); 504 if (p_dcb->lcid) 505 { 506 p_tbl = mca_tc_tbl_dalloc(p_dcb); 507 if (p_tbl) 508 { 509 p_tbl->state = MCA_TC_ST_CONN; 510 p_ccb->status = MCA_CCB_STAT_PENDING; 511 result = MCA_SUCCESS; 512 } 513 } 514 } 515 else 516 { 517 /* mark this MCL as pending and wait for MCA_DataChnlCfg */ 518 p_ccb->status = MCA_CCB_STAT_PENDING; 519 result = MCA_SUCCESS; 520 } 521 } 522 523 if (result != MCA_SUCCESS && p_dcb) 524 { 525 mca_dcb_dealloc(p_dcb, NULL); 526 } 527 } /* end of chk_mdl */ 528 529 if (p_ccb->status != MCA_CCB_STAT_PENDING) 530 osi_free_and_reset((void **)&p_ccb->p_tx_req); 531 mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data); 532 } 533 /* else a bad response is received */ 534 } 535 else 536 { 537 /* not expecting any response. drop it */ 538 MCA_TRACE_WARNING ("dropping received rsp (not expecting a response)"); 539 } 540 osi_free(p_data); 541 } 542 543 /******************************************************************************* 544 ** 545 ** Function mca_ccb_ll_open 546 ** 547 ** Description This function is called to report MCA_CONNECT_IND_EVT event. 548 ** It also clears the congestion flag (ccb.cong). 549 ** 550 ** Returns void. 551 ** 552 *******************************************************************************/ 553 void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 554 { 555 tMCA_CTRL evt_data; 556 p_ccb->cong = FALSE; 557 evt_data.connect_ind.mtu = p_data->open.peer_mtu; 558 memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN); 559 mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data); 560 } 561 562 /******************************************************************************* 563 ** 564 ** Function mca_ccb_dl_open 565 ** 566 ** Description This function is called when data channel is open. 567 ** It clears p_tx_req to allow other message exchage on this CL. 568 ** 569 ** Returns void. 570 ** 571 *******************************************************************************/ 572 void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data) 573 { 574 UNUSED(p_data); 575 576 osi_free_and_reset((void **)&p_ccb->p_tx_req); 577 osi_free_and_reset((void **)&p_ccb->p_rx_msg); 578 p_ccb->status = MCA_CCB_STAT_NORM; 579 } 580 581