1 /******************************************************************************
3 * Copyright (C) 2009-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This is the implementation file for the MCAP Control Channel Action
24 ******************************************************************************/
27 #include "bt_target.h"
29 #include "bt_common.h"
38 extern fixed_queue_t *btu_general_alarm_queue;
40 /*****************************************************************************
42 *****************************************************************************/
43 /*******************************************************************************
45 ** Function mca_ccb_rsp_tout
47 ** Description This function processes the response timeout.
51 *******************************************************************************/
52 void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
57 mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
60 /*******************************************************************************
62 ** Function mca_ccb_report_event
64 ** Description This function reports the given event.
68 *******************************************************************************/
69 void mca_ccb_report_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CTRL *p_data)
71 if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback)
72 (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb), mca_ccb_to_hdl(p_ccb), event, p_data);
75 /*******************************************************************************
77 ** Function mca_ccb_free_msg
79 ** Description This function frees the received message.
83 *******************************************************************************/
84 void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
90 /*******************************************************************************
92 ** Function mca_ccb_snd_req
94 ** Description This function builds a request and sends it to the peer.
98 *******************************************************************************/
99 void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
101 tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
103 BOOLEAN is_abort = FALSE;
106 MCA_TRACE_DEBUG ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code);
107 /* check for abort request */
108 if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ))
110 p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
111 /* the Abort API does not have the associated mdl_id.
112 * Get the mdl_id in dcb to compose the request */
113 p_msg->mdl_id = p_dcb->mdl_id;
114 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
115 osi_free_and_reset((void **)&p_ccb->p_tx_req);
116 p_ccb->status = MCA_CCB_STAT_NORM;
120 /* no pending outgoing messages or it's an abort request for a pending data channel */
121 if ((!p_ccb->p_tx_req) || is_abort)
123 p_ccb->p_tx_req = p_msg;
126 BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
128 p_pkt->offset = L2CAP_MIN_OFFSET;
129 p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
130 *p++ = p_msg->op_code;
131 UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
132 if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ) {
133 *p++ = p_msg->mdep_id;
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 period_ms_t interval_ms = p_ccb->p_rcb->reg.rsp_tout * 1000;
140 alarm_set_on_queue(p_ccb->mca_ccb_timer, interval_ms,
141 mca_ccb_timer_timeout, p_ccb,
142 btu_general_alarm_queue);
144 /* else the L2CAP channel is congested. keep the message to be sent later */
148 MCA_TRACE_WARNING ("dropping api req");
153 /*******************************************************************************
155 ** Function mca_ccb_snd_rsp
157 ** Description This function builds a response and sends it to
162 *******************************************************************************/
163 void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
165 tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
167 BOOLEAN chk_mdl = FALSE;
168 BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
170 MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
171 /* assume that API functions verified the parameters */
173 p_pkt->offset = L2CAP_MIN_OFFSET;
174 p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
175 *p++ = p_msg->op_code;
176 *p++ = p_msg->rsp_code;
177 UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
178 if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP) {
182 else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP) {
186 if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS) {
187 mca_dcb_by_hdl(p_msg->dcb_idx);
188 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA,
190 p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA,
192 p_ccb->status = MCA_CCB_STAT_PENDING;
193 /* set p_tx_req to block API_REQ/API_RSP before DL is up */
194 osi_free_and_reset((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;
199 osi_free_and_reset((void **)&p_ccb->p_rx_msg);
200 p_pkt->len = p - p_start;
201 L2CA_DataWrite(p_ccb->lcid, p_pkt);
204 /*******************************************************************************
206 ** Function mca_ccb_do_disconn
208 ** Description This function closes a control channel.
212 *******************************************************************************/
213 void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
217 mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
218 L2CA_DisconnectReq(p_ccb->lcid);
221 /*******************************************************************************
223 ** Function mca_ccb_cong
225 ** Description This function sets the congestion state for the CCB.
229 *******************************************************************************/
230 void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
232 MCA_TRACE_DEBUG ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
233 p_ccb->cong = p_data->llcong;
236 /* if there's a held packet, send it now */
237 if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific)
239 p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req;
240 p_ccb->p_tx_req = NULL;
241 mca_ccb_snd_req (p_ccb, p_data);
246 /*******************************************************************************
248 ** Function mca_ccb_hdl_req
250 ** Description This function is called when a MCAP request is received from
251 ** the peer. It calls the application callback function to
256 *******************************************************************************/
257 void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
259 BT_HDR *p_pkt = &p_data->hdr;
263 tMCA_CCB_MSG *p_rx_msg = NULL;
264 UINT8 reject_code = MCA_RSP_NO_RESOURCE;
265 BOOLEAN send_rsp = FALSE;
266 BOOLEAN check_req = FALSE;
269 MCA_TRACE_DEBUG ("mca_ccb_hdl_req status:%d", p_ccb->status);
270 p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
271 p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
272 evt_data.hdr.op_code = *p++;
273 reject_opcode = evt_data.hdr.op_code+1;
275 if (p_pkt->len >= 3) {
276 BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
278 android_errorWriteLog(0x534e4554, "110791536");
279 evt_data.hdr.mdl_id = 0;
282 MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id);
283 if (p_ccb->status == MCA_CCB_STAT_PENDING)
285 MCA_TRACE_DEBUG ("received req inpending state");
286 /* allow abort in pending state */
287 if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
289 reject_code = MCA_RSP_SUCCESS;
291 /* clear the pending status */
292 p_ccb->status = MCA_CCB_STAT_NORM;
293 if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
295 mca_dcb_dealloc(p_dcb, NULL);
296 osi_free_and_reset((void **)&p_ccb->p_tx_req);
300 reject_code = MCA_RSP_BAD_OP;
302 else if (p_ccb->p_rx_msg)
304 MCA_TRACE_DEBUG ("still handling prev req");
305 /* still holding previous message, reject this new one ?? */
308 else if (p_ccb->p_tx_req)
310 MCA_TRACE_DEBUG ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
311 /* sent a request; waiting for response */
312 if (p_ccb->ctrl_vpsm == 0)
314 MCA_TRACE_DEBUG ("local is ACP. accept the cmd from INT");
315 /* local is acceptor, need to handle the request */
317 reject_code = MCA_RSP_SUCCESS;
318 /* drop the previous request */
319 if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
320 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
322 mca_dcb_dealloc(p_dcb, NULL);
324 osi_free_and_reset((void **)&p_ccb->p_tx_req);
325 mca_stop_timer(p_ccb);
329 /* local is initiator, ignore the req */
334 else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
337 reject_code = (UINT8)p_pkt->layer_specific;
338 if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
339 (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
340 (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
342 /* invalid op code */
343 reject_opcode = MCA_OP_ERROR_RSP;
344 evt_data.hdr.mdl_id = 0;
350 reject_code = MCA_RSP_SUCCESS;
355 if (reject_code == MCA_RSP_SUCCESS)
357 reject_code = MCA_RSP_BAD_MDL;
358 if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
359 ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
361 reject_code = MCA_RSP_SUCCESS;
362 /* mdl_id is valid according to the spec */
363 switch (evt_data.hdr.op_code)
365 case MCA_OP_MDL_CREATE_REQ:
366 evt_data.create_ind.dep_id = *p++;
367 evt_data.create_ind.cfg = *p++;
368 p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
369 if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
371 MCA_TRACE_ERROR ("not a valid local mdep id");
372 reject_code = MCA_RSP_BAD_MDEP;
374 else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
376 MCA_TRACE_DEBUG ("the mdl_id is currently used in the CL(create)");
377 mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
381 /* check if this dep still have MDL available */
382 if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
384 MCA_TRACE_ERROR ("the mdep is currently using max_mdl");
385 reject_code = MCA_RSP_MDEP_BUSY;
390 case MCA_OP_MDL_RECONNECT_REQ:
391 if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
393 MCA_TRACE_ERROR ("the mdl_id is currently used in the CL(reconn)");
394 reject_code = MCA_RSP_MDL_BUSY;
398 case MCA_OP_MDL_ABORT_REQ:
399 reject_code = MCA_RSP_BAD_OP;
402 case MCA_OP_MDL_DELETE_REQ:
403 /* delete the associated mdl */
404 mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
412 if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
414 BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU);
415 p_buf->offset = L2CAP_MIN_OFFSET;
416 p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
417 *p++ = reject_opcode;
419 UINT16_TO_BE_STREAM(p, evt_data.hdr.mdl_id);
421 if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
423 *p++ = evt_data.create_ind.cfg;
427 p_buf->len = p - p_start;
428 L2CA_DataWrite (p_ccb->lcid, p_buf);
431 if (reject_code == MCA_RSP_SUCCESS)
433 /* use the received GKI buffer to store information to double check response API */
434 p_rx_msg->op_code = evt_data.hdr.op_code;
435 p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
436 p_ccb->p_rx_msg = p_rx_msg;
440 p_ccb->p_rx_msg = NULL;
442 mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
448 /*******************************************************************************
450 ** Function mca_ccb_hdl_rsp
452 ** Description This function is called when a MCAP response is received from
453 ** the peer. It calls the application callback function with
458 *******************************************************************************/
459 void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
461 BT_HDR *p_pkt = &p_data->hdr;
464 BOOLEAN chk_mdl = FALSE;
466 tMCA_RESULT result = MCA_BAD_HANDLE;
469 if (p_pkt->len < sizeof(evt_data.hdr.op_code) +
470 sizeof(evt_data.rsp.rsp_code) +
471 sizeof(evt_data.hdr.mdl_id)) {
472 android_errorWriteLog(0x534e4554, "116319076");
473 MCA_TRACE_ERROR("%s: Response packet is too short", __func__);
475 else if (p_ccb->p_tx_req)
477 /* verify that the received response matches the sent request */
478 p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
479 evt_data.hdr.op_code = *p++;
480 if ((evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP) &&
482 sizeof(evt_data.hdr.op_code) + sizeof(evt_data.rsp.rsp_code) +
483 sizeof(evt_data.hdr.mdl_id) +
484 sizeof(evt_data.create_cfm.cfg))) {
485 android_errorWriteLog(0x534e4554, "116319076");
486 MCA_TRACE_ERROR("%s: MDL Create Response packet is too short",
489 else if ((evt_data.hdr.op_code == 0) ||
490 ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
492 evt_data.rsp.rsp_code = *p++;
493 mca_stop_timer(p_ccb);
494 BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
495 if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
497 evt_data.create_cfm.cfg = *p++;
500 else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
505 p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
506 if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
508 if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
510 MCA_TRACE_ERROR ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
511 /* change the response code to be an error */
512 if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
514 evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
516 p_ccb->status = MCA_CCB_STAT_PENDING;
517 MCA_Abort(mca_ccb_to_hdl(p_ccb));
520 else if (p_dcb->p_chnl_cfg)
522 /* the data channel configuration is known. Proceed with data channel initiation */
523 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
524 p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
525 p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
528 p_tbl = mca_tc_tbl_dalloc(p_dcb);
531 p_tbl->state = MCA_TC_ST_CONN;
532 p_ccb->status = MCA_CCB_STAT_PENDING;
533 result = MCA_SUCCESS;
539 /* mark this MCL as pending and wait for MCA_DataChnlCfg */
540 p_ccb->status = MCA_CCB_STAT_PENDING;
541 result = MCA_SUCCESS;
545 if (result != MCA_SUCCESS && p_dcb)
547 mca_dcb_dealloc(p_dcb, NULL);
549 } /* end of chk_mdl */
551 if (p_ccb->status != MCA_CCB_STAT_PENDING)
552 osi_free_and_reset((void **)&p_ccb->p_tx_req);
553 mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
555 /* else a bad response is received */
559 /* not expecting any response. drop it */
560 MCA_TRACE_WARNING ("dropping received rsp (not expecting a response)");
565 /*******************************************************************************
567 ** Function mca_ccb_ll_open
569 ** Description This function is called to report MCA_CONNECT_IND_EVT event.
570 ** It also clears the congestion flag (ccb.cong).
574 *******************************************************************************/
575 void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
579 evt_data.connect_ind.mtu = p_data->open.peer_mtu;
580 memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
581 mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
584 /*******************************************************************************
586 ** Function mca_ccb_dl_open
588 ** Description This function is called when data channel is open.
589 ** It clears p_tx_req to allow other message exchage on this CL.
593 *******************************************************************************/
594 void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
598 osi_free_and_reset((void **)&p_ccb->p_tx_req);
599 osi_free_and_reset((void **)&p_ccb->p_rx_msg);
600 p_ccb->status = MCA_CCB_STAT_NORM;