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