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