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