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