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 <assert.h>
26 #include <string.h>
27
28 #include "bt_target.h"
29 #include "bt_common.h"
30 #include "mca_api.h"
31 #include "mca_defs.h"
32 #include "mca_int.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 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
149 MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
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 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
190 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
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 if (p_dcb)
269 {
270 p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
271 fcs = p_dcb->p_chnl_cfg->fcs;
272 }
273 }
274 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
275 p_cfg->mtu_present = TRUE;
276 p_cfg->mtu = p_tbl->my_mtu;
277 p_cfg->fcr_present = TRUE;
278 memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
279 if (fcs & MCA_FCS_PRESNT_MASK)
280 {
281 p_cfg->fcs_present = TRUE;
282 p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
283 }
284 }
285
286 /*******************************************************************************
287 **
288 ** Function mca_tc_close_ind
289 **
290 ** Description This function is called by the L2CAP interface when the
291 ** L2CAP channel is closed. It looks up the CCB or DCB for
292 ** the channel and sends it a close event. The reason
293 ** parameter is the same value passed by the L2CAP
294 ** callback function.
295 **
296 ** Returns Nothing.
297 **
298 *******************************************************************************/
mca_tc_close_ind(tMCA_TC_TBL * p_tbl,UINT16 reason)299 void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, UINT16 reason)
300 {
301 tMCA_CCB *p_ccb;
302 tMCA_DCB *p_dcb;
303 tMCA_CLOSE close;
304
305 close.param = MCA_ACP;
306 close.reason = reason;
307 close.lcid = p_tbl->lcid;
308
309 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__,
310 p_tbl->tcid, p_tbl->cb_idx, p_tbl->state);
311
312 /* Check if the transport channel is in use */
313 if (p_tbl->state == MCA_TC_ST_UNUSED)
314 return;
315
316 /* clear mca_tc_tbl entry */
317 if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT)
318 close.param = MCA_INT;
319 p_tbl->cfg_flags = 0;
320 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
321
322 /* if control channel, notify ccb that channel close */
323 if (p_tbl->tcid == MCA_CTRL_TCID)
324 {
325 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
326 mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
327 }
328 /* notify dcb that channel close */
329 else
330 {
331 /* look up dcb */
332 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
333 if (p_dcb != NULL)
334 {
335 mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
336 }
337 }
338 p_tbl->state = MCA_TC_ST_UNUSED;
339 }
340
341 /*******************************************************************************
342 **
343 ** Function mca_tc_open_ind
344 **
345 ** Description This function is called by the L2CAP interface when
346 ** the L2CAP channel is opened. It looks up the CCB or DCB
347 ** for the channel and sends it an open event.
348 **
349 ** Returns Nothing.
350 **
351 *******************************************************************************/
mca_tc_open_ind(tMCA_TC_TBL * p_tbl)352 void mca_tc_open_ind(tMCA_TC_TBL *p_tbl)
353 {
354 tMCA_CCB *p_ccb;
355 tMCA_DCB *p_dcb;
356 tMCA_OPEN open;
357
358 MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
359 p_tbl->state = MCA_TC_ST_OPEN;
360
361 open.peer_mtu = p_tbl->peer_mtu;
362 open.lcid = p_tbl->lcid;
363 /* use param to indicate the role of connection.
364 * MCA_ACP, if ACP */
365 open.param = MCA_INT;
366 if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP)
367 {
368 open.param = MCA_ACP;
369 }
370
371 /* if control channel, notify ccb that channel open */
372 if (p_tbl->tcid == MCA_CTRL_TCID)
373 {
374 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
375
376 mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
377 }
378 /* must be data channel, notify dcb that channel open */
379 else
380 {
381 /* look up dcb */
382 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
383
384 /* put lcid in event data */
385 if (p_dcb != NULL)
386 {
387 mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open);
388 }
389 }
390 }
391
392
393 /*******************************************************************************
394 **
395 ** Function mca_tc_cong_ind
396 **
397 ** Description This function is called by the L2CAP interface layer when
398 ** L2CAP calls the congestion callback. It looks up the CCB
399 ** or DCB for the channel and sends it a congestion event.
400 ** The is_congested parameter is the same value passed by
401 ** the L2CAP callback function.
402 **
403 **
404 ** Returns Nothing.
405 **
406 *******************************************************************************/
mca_tc_cong_ind(tMCA_TC_TBL * p_tbl,BOOLEAN is_congested)407 void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, BOOLEAN is_congested)
408 {
409 tMCA_CCB *p_ccb;
410 tMCA_DCB *p_dcb;
411
412 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
413
414 /* if control channel, notify ccb of congestion */
415 if (p_tbl->tcid == MCA_CTRL_TCID)
416 {
417 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
418 mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
419 }
420 /* notify dcb that channel open */
421 else
422 {
423 /* look up dcb by cb_idx */
424 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
425 if (p_dcb != NULL)
426 {
427 mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested);
428 }
429 }
430 }
431
432
433 /*******************************************************************************
434 **
435 ** Function mca_tc_data_ind
436 **
437 ** Description This function is called by the L2CAP interface layer when
438 ** incoming data is received from L2CAP. It looks up the CCB
439 ** or DCB for the channel and routes the data accordingly.
440 **
441 ** Returns Nothing.
442 **
443 *******************************************************************************/
mca_tc_data_ind(tMCA_TC_TBL * p_tbl,BT_HDR * p_buf)444 void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf)
445 {
446 tMCA_CCB *p_ccb;
447 tMCA_DCB *p_dcb;
448 UINT8 event = MCA_CCB_MSG_RSP_EVT;
449 UINT8 *p;
450 UINT8 rej_rsp_code = MCA_RSP_SUCCESS;
451
452 MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
453
454 /* if control channel, handle control message */
455 if (p_tbl->tcid == MCA_CTRL_TCID)
456 {
457 p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
458 if (p_ccb)
459 {
460 p = (UINT8*)(p_buf+1) + p_buf->offset;
461 /* all the request opcode has bit 0 set. response code has bit 0 clear */
462 if ((*p) & 0x01)
463 event = MCA_CCB_MSG_REQ_EVT;
464
465 if (*p < MCA_NUM_STANDARD_OPCODE)
466 {
467 if (p_buf->len != mca_std_msg_len[*p])
468 {
469 MCA_TRACE_ERROR ("$s() - opcode: %d required len: %d, got len: %d"
470 , __func__, *p, mca_std_msg_len[*p], p_buf->len);
471 rej_rsp_code = MCA_RSP_BAD_PARAM;
472 }
473 }
474 else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP))
475 {
476 MCA_TRACE_ERROR ("%s() - unsupported SYNC opcode: %d len:%d"
477 , __func__, *p, p_buf->len);
478 /* reject unsupported request */
479 rej_rsp_code = MCA_RSP_NO_SUPPORT;
480 }
481 else
482 {
483 MCA_TRACE_ERROR ("%s() - bad opcode: %d len:%d", __func__, *p, p_buf->len);
484 /* reject unsupported request */
485 rej_rsp_code = MCA_RSP_BAD_OPCODE;
486 }
487
488 p_buf->layer_specific = rej_rsp_code;
489 /* forward the request/response to state machine */
490 mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf);
491 } /* got a valid ccb */
492 else
493 osi_free(p_buf);
494 }
495 /* else send event to dcb */
496 else
497 {
498 p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
499 if (p_dcb != NULL)
500 {
501 mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf);
502 }
503 else
504 osi_free(p_buf);
505 }
506 }
507
508 /*******************************************************************************
509 **
510 ** Function mca_rcb_alloc
511 **
512 ** Description This function allocates a registration control block.
513 ** If no free RCB is available, it returns NULL.
514 **
515 ** Returns tMCA_RCB *
516 **
517 *******************************************************************************/
mca_rcb_alloc(tMCA_REG * p_reg)518 tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg)
519 {
520 int i;
521 tMCA_RCB *p_rcb = NULL;
522
523 for (i=0; i<MCA_NUM_REGS; i++)
524 {
525 if (mca_cb.rcb[i].p_cback == NULL)
526 {
527 p_rcb = &mca_cb.rcb[i];
528 memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG));
529 break;
530 }
531 }
532 return p_rcb;
533 }
534
535 /*******************************************************************************
536 **
537 ** Function mca_rcb_dealloc
538 **
539 ** Description This function deallocates the RCB with the given handle.
540 **
541 ** Returns void.
542 **
543 *******************************************************************************/
mca_rcb_dealloc(tMCA_HANDLE handle)544 void mca_rcb_dealloc(tMCA_HANDLE handle)
545 {
546 int i;
547 BOOLEAN done = TRUE;
548 tMCA_RCB *p_rcb;
549 tMCA_CCB *p_ccb;
550
551 if (handle && (handle<=MCA_NUM_REGS))
552 {
553 handle--;
554 p_rcb = &mca_cb.rcb[handle];
555 if (p_rcb->p_cback)
556 {
557 p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS];
558 /* check if all associated CCB are disconnected */
559 for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++)
560 {
561 if (p_ccb->p_rcb)
562 {
563 done = FALSE;
564 mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
565 }
566 }
567
568 if (done)
569 {
570 memset (p_rcb, 0, sizeof(tMCA_RCB));
571 MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
572 }
573 }
574 }
575 }
576
577 /*******************************************************************************
578 **
579 ** Function mca_rcb_to_handle
580 **
581 ** Description This function converts a pointer to an RCB to
582 ** a handle (tMCA_HANDLE). It returns the handle.
583 **
584 ** Returns void.
585 **
586 *******************************************************************************/
mca_rcb_to_handle(tMCA_RCB * p_rcb)587 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb)
588 {
589 return(UINT8) (p_rcb - mca_cb.rcb + 1);
590 }
591
592 /*******************************************************************************
593 **
594 ** Function mca_rcb_by_handle
595 **
596 ** Description This function finds the RCB for a handle (tMCA_HANDLE).
597 ** It returns a pointer to the RCB. If no RCB matches the
598 ** handle it returns NULL.
599 **
600 ** Returns tMCA_RCB *
601 **
602 *******************************************************************************/
mca_rcb_by_handle(tMCA_HANDLE handle)603 tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle)
604 {
605 tMCA_RCB *p_rcb = NULL;
606
607 if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback)
608 {
609 p_rcb = &mca_cb.rcb[handle-1];
610 }
611 return p_rcb;
612 }
613
614 /*******************************************************************************
615 **
616 ** Function mca_is_valid_dep_id
617 **
618 ** Description This function checks if the given dep_id is valid.
619 **
620 ** Returns TRUE, if this is a valid local dep_id
621 **
622 *******************************************************************************/
mca_is_valid_dep_id(tMCA_RCB * p_rcb,tMCA_DEP dep)623 BOOLEAN mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep)
624 {
625 BOOLEAN valid = FALSE;
626 if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
627 {
628 valid = TRUE;
629 }
630 return valid;
631 }
632