• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Main Control Block and
22  *  Utility functions.
23  *
24  ******************************************************************************/
25 #include <base/logging.h>
26 #include <string.h>
27 
28 #include "bt_common.h"
29 #include "bt_target.h"
30 #include "l2c_api.h"
31 #include "mca_api.h"
32 #include "mca_defs.h"
33 #include "mca_int.h"
34 
35 /* Main Control block for MCA */
36 tMCA_CB mca_cb;
37 
38 /*****************************************************************************
39  * constants
40  ****************************************************************************/
41 
42 /* table of standard opcode message size */
43 const uint8_t mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
44     4, /* MCA_OP_ERROR_RSP         */
45     5, /* MCA_OP_MDL_CREATE_REQ    */
46     5, /* MCA_OP_MDL_CREATE_RSP    */
47     3, /* MCA_OP_MDL_RECONNECT_REQ */
48     4, /* MCA_OP_MDL_RECONNECT_RSP */
49     3, /* MCA_OP_MDL_ABORT_REQ     */
50     4, /* MCA_OP_MDL_ABORT_RSP     */
51     3, /* MCA_OP_MDL_DELETE_REQ    */
52     4  /* MCA_OP_MDL_DELETE_RSP    */
53 };
54 
55 /*******************************************************************************
56  *
57  * Function         mca_handle_by_cpsm
58  *
59  * Description      This function returns the handle for the given control
60  *                  channel PSM. 0, if not found.
61  *
62  * Returns          the MCA handle.
63  *
64  ******************************************************************************/
mca_handle_by_cpsm(uint16_t psm)65 tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm) {
66   int i;
67   tMCA_HANDLE handle = 0;
68   tMCA_RCB* p_rcb = &mca_cb.rcb[0];
69 
70   for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
71     if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm) {
72       handle = i + 1;
73       break;
74     }
75   }
76   return handle;
77 }
78 
79 /*******************************************************************************
80  *
81  * Function         mca_handle_by_dpsm
82  *
83  * Description      This function returns the handle for the given data
84  *                  channel PSM. 0, if not found.
85  *
86  * Returns          the MCA handle.
87  *
88  ******************************************************************************/
mca_handle_by_dpsm(uint16_t psm)89 tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm) {
90   int i;
91   tMCA_HANDLE handle = 0;
92   tMCA_RCB* p_rcb = &mca_cb.rcb[0];
93 
94   for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
95     if (p_rcb->p_cback && p_rcb->reg.data_psm == psm) {
96       handle = i + 1;
97       break;
98     }
99   }
100   return handle;
101 }
102 
103 /*******************************************************************************
104  *
105  * Function         mca_tc_tbl_calloc
106  *
107  * Description      This function allocates a transport table for the given
108  *                  control channel.
109  *
110  * Returns          The tranport table.
111  *
112  ******************************************************************************/
mca_tc_tbl_calloc(tMCA_CCB * p_ccb)113 tMCA_TC_TBL* mca_tc_tbl_calloc(tMCA_CCB* p_ccb) {
114   tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
115   int i;
116 
117   /* find next free entry in tc table */
118   for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
119     if (p_tbl->state == MCA_TC_ST_UNUSED) {
120       break;
121     }
122   }
123 
124   /* sanity check */
125   CHECK(i != MCA_NUM_TC_TBL);
126 
127   /* initialize entry */
128   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
129   p_tbl->cfg_flags = 0;
130   p_tbl->cb_idx = mca_ccb_to_hdl(p_ccb);
131   p_tbl->tcid = MCA_CTRL_TCID;
132   p_tbl->my_mtu = MCA_CTRL_MTU;
133   p_tbl->state = MCA_TC_ST_IDLE;
134   p_tbl->lcid = p_ccb->lcid;
135   mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
136 
137   MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
138   return p_tbl;
139 }
140 
141 /*******************************************************************************
142  *
143  * Function         mca_tc_tbl_dalloc
144  *
145  * Description      This function allocates a transport table for the given
146  *                  data channel.
147  *
148  * Returns          The tranport table.
149  *
150  ******************************************************************************/
mca_tc_tbl_dalloc(tMCA_DCB * p_dcb)151 tMCA_TC_TBL* mca_tc_tbl_dalloc(tMCA_DCB* p_dcb) {
152   tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
153   int i;
154 
155   /* find next free entry in tc table */
156   for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
157     if (p_tbl->state == MCA_TC_ST_UNUSED) {
158       break;
159     }
160   }
161 
162   /* sanity check */
163   CHECK(i != MCA_NUM_TC_TBL);
164 
165   /* initialize entry */
166   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
167   p_tbl->cfg_flags = 0;
168   p_tbl->cb_idx = mca_dcb_to_hdl(p_dcb);
169   p_tbl->tcid = p_dcb->p_cs->type + 1;
170   p_tbl->my_mtu = p_dcb->p_chnl_cfg->data_mtu;
171   p_tbl->state = MCA_TC_ST_IDLE;
172   p_tbl->lcid = p_dcb->lcid;
173   mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
174 
175   MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
176                   p_tbl->cb_idx);
177   return p_tbl;
178 }
179 
180 /*******************************************************************************
181  *
182  * Function         mca_tc_tbl_by_lcid
183  *
184  * Description      Find the transport channel table entry by LCID.
185  *
186  *
187  * Returns          The tranport table.
188  *
189  ******************************************************************************/
mca_tc_tbl_by_lcid(uint16_t lcid)190 tMCA_TC_TBL* mca_tc_tbl_by_lcid(uint16_t lcid) {
191   uint8_t idx;
192 
193   if (lcid >= L2CAP_BASE_APPL_CID) {
194     idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
195 
196     if (idx < MCA_NUM_TC_TBL) {
197       return &mca_cb.tc.tc_tbl[idx];
198     }
199   }
200   return NULL;
201 }
202 
203 /*******************************************************************************
204  *
205  * Function         mca_free_tc_tbl_by_lcid
206  *
207  * Description      Find the  transport table entry by LCID
208  *                  and free the tc_tbl
209  *
210  * Returns          void.
211  *
212  ******************************************************************************/
mca_free_tc_tbl_by_lcid(uint16_t lcid)213 void mca_free_tc_tbl_by_lcid(uint16_t lcid) {
214   uint8_t idx;
215 
216   if (lcid >= L2CAP_BASE_APPL_CID) {
217     idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
218 
219     if (idx < MCA_NUM_TC_TBL) {
220       mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
221     }
222   }
223 }
224 
225 /*******************************************************************************
226  *
227  * Function         mca_set_cfg_by_tbl
228  *
229  * Description      Set the L2CAP configuration information
230  *
231  * Returns          none.
232  *
233  ******************************************************************************/
mca_set_cfg_by_tbl(tL2CAP_CFG_INFO * p_cfg,tMCA_TC_TBL * p_tbl)234 void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO* p_cfg, tMCA_TC_TBL* p_tbl) {
235   tMCA_DCB* p_dcb;
236   const tL2CAP_FCR_OPTS* p_opt;
237   tMCA_FCS_OPT fcs = MCA_FCS_NONE;
238 
239   if (p_tbl->tcid == MCA_CTRL_TCID) {
240     p_opt = &mca_l2c_fcr_opts_def;
241   } else {
242     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
243     if (p_dcb) {
244       p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
245       fcs = p_dcb->p_chnl_cfg->fcs;
246     }
247   }
248   memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
249   p_cfg->mtu_present = true;
250   p_cfg->mtu = p_tbl->my_mtu;
251   p_cfg->fcr_present = true;
252   memcpy(&p_cfg->fcr, p_opt, sizeof(tL2CAP_FCR_OPTS));
253   if (fcs & MCA_FCS_PRESNT_MASK) {
254     p_cfg->fcs_present = true;
255     p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
256   }
257 }
258 
259 /*******************************************************************************
260  *
261  * Function         mca_tc_close_ind
262  *
263  * Description      This function is called by the L2CAP interface when the
264  *                  L2CAP channel is closed.  It looks up the CCB or DCB for
265  *                  the channel and sends it a close event.  The reason
266  *                  parameter is the same value passed by the L2CAP
267  *                  callback function.
268  *
269  * Returns          Nothing.
270  *
271  ******************************************************************************/
mca_tc_close_ind(tMCA_TC_TBL * p_tbl,uint16_t reason)272 void mca_tc_close_ind(tMCA_TC_TBL* p_tbl, uint16_t reason) {
273   tMCA_CCB* p_ccb;
274   tMCA_DCB* p_dcb;
275 
276   MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, p_tbl->tcid,
277                   p_tbl->cb_idx, p_tbl->state);
278 
279   /* Check if the transport channel is in use */
280   if (p_tbl->state == MCA_TC_ST_UNUSED) return;
281 
282   tMCA_CLOSE close;
283 
284   close.param = MCA_ACP;
285   close.reason = reason;
286   close.lcid = p_tbl->lcid;
287 
288   /* clear mca_tc_tbl entry */
289   if (p_tbl->cfg_flags & MCA_L2C_CFG_DISCN_INT) close.param = MCA_INT;
290   p_tbl->cfg_flags = 0;
291   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
292 
293   /* if control channel, notify ccb of the channel close */
294   if (p_tbl->tcid == MCA_CTRL_TCID) {
295     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
296     tMCA_CCB_EVT mca_ccb_evt;
297     mca_ccb_evt.close = close;
298     mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, &mca_ccb_evt);
299   } else {
300     /* notify dcb of the channel close */
301     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
302     if (p_dcb != NULL) {
303       tMCA_DCB_EVT mca_dcb_evt;
304       mca_dcb_evt.close = close;
305       mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, &mca_dcb_evt);
306     }
307   }
308   p_tbl->state = MCA_TC_ST_UNUSED;
309 }
310 
311 /*******************************************************************************
312  *
313  * Function         mca_tc_open_ind
314  *
315  * Description      This function is called by the L2CAP interface when
316  *                  the L2CAP channel is opened.  It looks up the CCB or DCB
317  *                  for the channel and sends it an open event.
318  *
319  * Returns          Nothing.
320  *
321  ******************************************************************************/
mca_tc_open_ind(tMCA_TC_TBL * p_tbl)322 void mca_tc_open_ind(tMCA_TC_TBL* p_tbl) {
323   tMCA_CCB* p_ccb;
324   tMCA_DCB* p_dcb;
325   tMCA_OPEN open;
326 
327   MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid,
328                   p_tbl->cb_idx);
329   p_tbl->state = MCA_TC_ST_OPEN;
330 
331   open.peer_mtu = p_tbl->peer_mtu;
332   open.lcid = p_tbl->lcid;
333   /* use param to indicate the role of connection.
334    * MCA_ACP, if ACP */
335   open.param = MCA_INT;
336   if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) {
337     open.param = MCA_ACP;
338   }
339 
340   /* if control channel, notify ccb that the channel is open */
341   if (p_tbl->tcid == MCA_CTRL_TCID) {
342     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
343     tMCA_CCB_EVT mca_ccb_evt;
344     mca_ccb_evt.open = open;
345     mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, &mca_ccb_evt);
346   } else {
347     /* must be data channel, notify dcb that the channel is open */
348     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
349 
350     /* put lcid in event data */
351     if (p_dcb != NULL) {
352       tMCA_DCB_EVT mca_dcb_evt;
353       mca_dcb_evt.open = open;
354       mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, &mca_dcb_evt);
355     }
356   }
357 }
358 
359 /*******************************************************************************
360  *
361  * Function         mca_tc_cong_ind
362  *
363  * Description      This function is called by the L2CAP interface layer when
364  *                  L2CAP calls the congestion callback.  It looks up the CCB
365  *                  or DCB for the channel and sends it a congestion event.
366  *                  The is_congested parameter is the same value passed by
367  *                  the L2CAP callback function.
368  *
369  *
370  * Returns          Nothing.
371  *
372  ******************************************************************************/
mca_tc_cong_ind(tMCA_TC_TBL * p_tbl,bool is_congested)373 void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested) {
374   tMCA_CCB* p_ccb;
375   tMCA_DCB* p_dcb;
376 
377   MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
378                   p_tbl->cb_idx);
379 
380   /* if control channel, notify ccb of congestion */
381   if (p_tbl->tcid == MCA_CTRL_TCID) {
382     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
383     tMCA_CCB_EVT mca_ccb_evt;
384     mca_ccb_evt.llcong = is_congested;
385     mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, &mca_ccb_evt);
386   } else {
387     /* notify dcb that channel open */
388     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
389     if (p_dcb != NULL) {
390       tMCA_DCB_EVT mca_dcb_evt;
391       mca_dcb_evt.llcong = is_congested;
392       mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, &mca_dcb_evt);
393     }
394   }
395 }
396 
397 /*******************************************************************************
398  *
399  * Function         mca_tc_data_ind
400  *
401  * Description      This function is called by the L2CAP interface layer when
402  *                  incoming data is received from L2CAP.  It looks up the CCB
403  *                  or DCB for the channel and routes the data accordingly.
404  *
405  * Returns          Nothing.
406  *
407  ******************************************************************************/
mca_tc_data_ind(tMCA_TC_TBL * p_tbl,BT_HDR * p_buf)408 void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf) {
409   tMCA_CCB* p_ccb;
410   tMCA_DCB* p_dcb;
411   uint8_t event = MCA_CCB_MSG_RSP_EVT;
412   uint8_t* p;
413   uint8_t rej_rsp_code = MCA_RSP_SUCCESS;
414 
415   MCA_TRACE_DEBUG("%s: tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
416                   p_tbl->cb_idx);
417 
418   /* if control channel, handle control message */
419   if (p_tbl->tcid == MCA_CTRL_TCID) {
420     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
421     if (p_ccb) {
422       p = (uint8_t*)(p_buf + 1) + p_buf->offset;
423       /* all the request opcode has bit 0 set. response code has bit 0 clear */
424       if ((*p) & 0x01) event = MCA_CCB_MSG_REQ_EVT;
425 
426       if (*p < MCA_NUM_STANDARD_OPCODE) {
427         if (p_buf->len != mca_std_msg_len[*p]) {
428           MCA_TRACE_ERROR("%s: opcode 0x%02x required len: %d, got len: %d",
429                           __func__, *p, mca_std_msg_len[*p], p_buf->len);
430           rej_rsp_code = MCA_RSP_BAD_PARAM;
431         }
432       } else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) {
433         MCA_TRACE_ERROR("%s: unsupported SYNC opcode: 0x%02x len:%d", __func__,
434                         *p, p_buf->len);
435         /* reject unsupported request */
436         rej_rsp_code = MCA_RSP_NO_SUPPORT;
437       } else {
438         MCA_TRACE_ERROR("%s: bad opcode: 0x%02x len:%d", __func__, *p,
439                         p_buf->len);
440         /* reject unsupported request */
441         rej_rsp_code = MCA_RSP_BAD_OPCODE;
442       }
443 
444       p_buf->layer_specific = rej_rsp_code;
445       /* forward the request/response to state machine */
446       mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT*)p_buf);
447     } /* got a valid ccb */
448     else
449       osi_free(p_buf);
450   }
451   /* else send event to dcb */
452   else {
453     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
454     if (p_dcb != NULL) {
455       mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT*)p_buf);
456     } else
457       osi_free(p_buf);
458   }
459 }
460 
461 /*******************************************************************************
462  *
463  * Function         mca_rcb_alloc
464  *
465  * Description      This function allocates a registration control block.
466  *                  If no free RCB is available, it returns NULL.
467  *
468  * Returns          tMCA_RCB *
469  *
470  ******************************************************************************/
mca_rcb_alloc(tMCA_REG * p_reg)471 tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg) {
472   int i;
473   tMCA_RCB* p_rcb = NULL;
474 
475   for (i = 0; i < MCA_NUM_REGS; i++) {
476     if (mca_cb.rcb[i].p_cback == NULL) {
477       p_rcb = &mca_cb.rcb[i];
478       memcpy(&p_rcb->reg, p_reg, sizeof(tMCA_REG));
479       break;
480     }
481   }
482   return p_rcb;
483 }
484 
485 /*******************************************************************************
486  *
487  * Function         mca_rcb_dealloc
488  *
489  * Description      This function deallocates the RCB with the given handle.
490  *
491  * Returns          void.
492  *
493  ******************************************************************************/
mca_rcb_dealloc(tMCA_HANDLE handle)494 void mca_rcb_dealloc(tMCA_HANDLE handle) {
495   int i;
496   bool done = true;
497   tMCA_RCB* p_rcb;
498   tMCA_CCB* p_ccb;
499 
500   if (handle && (handle <= MCA_NUM_REGS)) {
501     handle--;
502     p_rcb = &mca_cb.rcb[handle];
503     if (p_rcb->p_cback) {
504       p_ccb = &mca_cb.ccb[handle * MCA_NUM_LINKS];
505       /* check if all associated CCB are disconnected */
506       for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb++) {
507         if (p_ccb->p_rcb) {
508           done = false;
509           mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
510         }
511       }
512 
513       if (done) {
514         memset(p_rcb, 0, sizeof(tMCA_RCB));
515         MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
516       }
517     }
518   }
519 }
520 
521 /*******************************************************************************
522  *
523  * Function         mca_rcb_to_handle
524  *
525  * Description      This function converts a pointer to an RCB to
526  *                  a handle (tMCA_HANDLE).  It returns the handle.
527  *
528  * Returns          void.
529  *
530  ******************************************************************************/
mca_rcb_to_handle(tMCA_RCB * p_rcb)531 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb) {
532   return (uint8_t)(p_rcb - mca_cb.rcb + 1);
533 }
534 
535 /*******************************************************************************
536  *
537  * Function         mca_rcb_by_handle
538  *
539  * Description      This function finds the RCB for a handle (tMCA_HANDLE).
540  *                  It returns a pointer to the RCB.  If no RCB matches the
541  *                  handle it returns NULL.
542  *
543  * Returns          tMCA_RCB *
544  *
545  ******************************************************************************/
mca_rcb_by_handle(tMCA_HANDLE handle)546 tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle) {
547   tMCA_RCB* p_rcb = NULL;
548 
549   if (handle && (handle <= MCA_NUM_REGS) && mca_cb.rcb[handle - 1].p_cback) {
550     p_rcb = &mca_cb.rcb[handle - 1];
551   }
552   return p_rcb;
553 }
554 
555 /*******************************************************************************
556  *
557  * Function         mca_is_valid_dep_id
558  *
559  * Description      This function checks if the given dep_id is valid.
560  *
561  * Returns          true, if this is a valid local dep_id
562  *
563  ******************************************************************************/
mca_is_valid_dep_id(tMCA_RCB * p_rcb,tMCA_DEP dep)564 bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep) {
565   bool valid = false;
566   if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
567     valid = true;
568   }
569   return valid;
570 }
571