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