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