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 API implementation file for the Multi-Channel Adaptation
22 * Protocol (MCAP).
23 *
24 ******************************************************************************/
25 #include <assert.h>
26 #include <string.h>
27
28 #include "bt_target.h"
29 #include "btm_api.h"
30 #include "btm_int.h"
31 #include "mca_api.h"
32 #include "mca_defs.h"
33 #include "mca_int.h"
34
35 #include "btu.h"
36
37
38 /*******************************************************************************
39 **
40 ** Function mca_process_timeout
41 **
42 ** Description This function is called by BTU when an MCA timer
43 ** expires.
44 **
45 ** This function is for use internal to the stack only.
46 **
47 ** Returns void
48 **
49 *******************************************************************************/
mca_process_timeout(TIMER_LIST_ENT * p_tle)50 void mca_process_timeout(TIMER_LIST_ENT *p_tle)
51 {
52 if(p_tle->event == BTU_TTYPE_MCA_CCB_RSP)
53 {
54 p_tle->event = 0;
55 mca_ccb_event ((tMCA_CCB *) p_tle->param, MCA_CCB_RSP_TOUT_EVT, NULL);
56 }
57 }
58
59 /*******************************************************************************
60 **
61 ** Function MCA_Init
62 **
63 ** Description Initialize MCAP main control block.
64 ** This function is called at stack start up.
65 **
66 ** Returns void
67 **
68 *******************************************************************************/
MCA_Init(void)69 void MCA_Init(void)
70 {
71 memset(&mca_cb, 0, sizeof(tMCA_CB));
72
73 #if defined(MCA_INITIAL_TRACE_LEVEL)
74 mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
75 #else
76 mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
77 #endif
78 }
79
80 /*******************************************************************************
81 **
82 ** Function MCA_SetTraceLevel
83 **
84 ** Description This function sets the debug trace level for MCA.
85 ** If 0xff is passed, the current trace level is returned.
86 **
87 ** Input Parameters:
88 ** level: The level to set the MCA tracing to:
89 ** 0xff-returns the current setting.
90 ** 0-turns off tracing.
91 ** >= 1-Errors.
92 ** >= 2-Warnings.
93 ** >= 3-APIs.
94 ** >= 4-Events.
95 ** >= 5-Debug.
96 **
97 ** Returns The new trace level or current trace level if
98 ** the input parameter is 0xff.
99 **
100 *******************************************************************************/
MCA_SetTraceLevel(UINT8 level)101 UINT8 MCA_SetTraceLevel (UINT8 level)
102 {
103 if (level != 0xFF)
104 mca_cb.trace_level = level;
105
106 return (mca_cb.trace_level);
107 }
108
109 /*******************************************************************************
110 **
111 ** Function MCA_Register
112 **
113 ** Description This function registers an MCAP implementation.
114 ** It is assumed that the control channel PSM and data channel
115 ** PSM are not used by any other instances of the stack.
116 ** If the given p_reg->ctrl_psm is 0, this handle is INT only.
117 **
118 ** Returns 0, if failed. Otherwise, the MCA handle.
119 **
120 *******************************************************************************/
MCA_Register(tMCA_REG * p_reg,tMCA_CTRL_CBACK * p_cback)121 tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback)
122 {
123 tMCA_RCB *p_rcb;
124 tMCA_HANDLE handle = 0;
125 tL2CAP_APPL_INFO l2c_cacp_appl;
126 tL2CAP_APPL_INFO l2c_dacp_appl;
127
128 assert(p_reg != NULL );
129 assert(p_cback != NULL );
130
131 MCA_TRACE_API ("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm, p_reg->data_psm);
132
133 if ( (p_rcb = mca_rcb_alloc (p_reg)) != NULL)
134 {
135 if (p_reg->ctrl_psm)
136 {
137 if (L2C_INVALID_PSM(p_reg->ctrl_psm) || L2C_INVALID_PSM(p_reg->data_psm))
138 {
139 MCA_TRACE_ERROR ("INVALID_PSM");
140 return 0;
141 }
142
143 l2c_cacp_appl = *(tL2CAP_APPL_INFO *)&mca_l2c_int_appl;
144 l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
145 l2c_dacp_appl = *(tL2CAP_APPL_INFO *)&l2c_cacp_appl;
146 l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
147 l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
148 if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO *) &l2c_cacp_appl) &&
149 L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO *) &l2c_dacp_appl))
150 {
151 /* set security level */
152 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_CTRL, p_reg->sec_mask,
153 p_reg->ctrl_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
154
155 /* in theory, we do not need this one for data_psm
156 * If we don't, L2CAP rejects with security block (3),
157 * which is different reject code from what MCAP spec suggests.
158 * we set this one, so mca_l2c_dconn_ind_cback can reject /w no resources (4) */
159 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_reg->sec_mask,
160 p_reg->data_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
161 }
162 else
163 {
164 MCA_TRACE_ERROR ("Failed to register to L2CAP");
165 return 0;
166 }
167 }
168 else
169 p_rcb->reg.data_psm = 0;
170 handle = mca_rcb_to_handle (p_rcb);
171 p_rcb->p_cback = p_cback;
172 p_rcb->reg.rsp_tout = p_reg->rsp_tout;
173 }
174 return handle;
175 }
176
177
178 /*******************************************************************************
179 **
180 ** Function MCA_Deregister
181 **
182 ** Description This function is called to deregister an MCAP implementation.
183 ** Before this function can be called, all control and data
184 ** channels must be removed with MCA_DisconnectReq and MCA_CloseReq.
185 **
186 ** Returns void
187 **
188 *******************************************************************************/
MCA_Deregister(tMCA_HANDLE handle)189 void MCA_Deregister(tMCA_HANDLE handle)
190 {
191 tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
192
193 MCA_TRACE_API ("MCA_Deregister: %d", handle);
194 if (p_rcb && p_rcb->reg.ctrl_psm)
195 {
196 L2CA_Deregister(p_rcb->reg.ctrl_psm);
197 L2CA_Deregister(p_rcb->reg.data_psm);
198 btm_sec_clr_service_by_psm (p_rcb->reg.ctrl_psm);
199 btm_sec_clr_service_by_psm (p_rcb->reg.data_psm);
200 }
201 mca_rcb_dealloc(handle);
202 }
203
204
205 /*******************************************************************************
206 **
207 ** Function MCA_CreateDep
208 **
209 ** Description Create a data endpoint. If the MDEP is created successfully,
210 ** the MDEP ID is returned in *p_dep. After a data endpoint is
211 ** created, an application can initiate a connection between this
212 ** endpoint and an endpoint on a peer device.
213 **
214 ** Returns MCA_SUCCESS if successful, otherwise error.
215 **
216 *******************************************************************************/
MCA_CreateDep(tMCA_HANDLE handle,tMCA_DEP * p_dep,tMCA_CS * p_cs)217 tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs)
218 {
219 tMCA_RESULT result = MCA_BAD_HANDLE;
220 int i;
221 tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
222 tMCA_CS *p_depcs;
223
224 assert(p_dep != NULL );
225 assert(p_cs != NULL );
226 assert(p_cs->p_data_cback != NULL );
227
228 MCA_TRACE_API ("MCA_CreateDep: %d", handle);
229 if (p_rcb)
230 {
231 if (p_cs->max_mdl > MCA_NUM_MDLS)
232 {
233 MCA_TRACE_ERROR ("max_mdl: %d is too big", p_cs->max_mdl );
234 result = MCA_BAD_PARAMS;
235 }
236 else
237 {
238 p_depcs = p_rcb->dep;
239 if (p_cs->type == MCA_TDEP_ECHO)
240 {
241 if (p_depcs->p_data_cback)
242 {
243 MCA_TRACE_ERROR ("Already has ECHO MDEP");
244 return MCA_NO_RESOURCES;
245 }
246 memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
247 *p_dep = 0;
248 result = MCA_SUCCESS;
249 }
250 else
251 {
252 result = MCA_NO_RESOURCES;
253 /* non-echo MDEP starts from 1 */
254 p_depcs++;
255 for (i=1; i<MCA_NUM_DEPS; i++, p_depcs++)
256 {
257 if (p_depcs->p_data_cback == NULL)
258 {
259 memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
260 /* internally use type as the mdep id */
261 p_depcs->type = i;
262 *p_dep = i;
263 result = MCA_SUCCESS;
264 break;
265 }
266 }
267 }
268 }
269 }
270 return result;
271 }
272
273
274 /*******************************************************************************
275 **
276 ** Function MCA_DeleteDep
277 **
278 ** Description Delete a data endpoint. This function is called when
279 ** the implementation is no longer using a data endpoint.
280 ** If this function is called when the endpoint is connected
281 ** the connection is closed and the data endpoint
282 ** is removed.
283 **
284 ** Returns MCA_SUCCESS if successful, otherwise error.
285 **
286 *******************************************************************************/
MCA_DeleteDep(tMCA_HANDLE handle,tMCA_DEP dep)287 tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep)
288 {
289 tMCA_RESULT result = MCA_BAD_HANDLE;
290 tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
291 tMCA_DCB *p_dcb;
292 int i, max;
293 tMCA_CS *p_depcs;
294
295 MCA_TRACE_API ("MCA_DeleteDep: %d dep:%d", handle, dep);
296 if (p_rcb)
297 {
298 if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
299 {
300 result = MCA_SUCCESS;
301 p_rcb->dep[dep].p_data_cback = NULL;
302 p_depcs = &(p_rcb->dep[dep]);
303 i = handle - 1;
304 max = MCA_NUM_MDLS*MCA_NUM_LINKS;
305 p_dcb = &mca_cb.dcb[i*max];
306 /* make sure no MDL exists for this MDEP */
307 for (i=0; i<max; i++, p_dcb++)
308 {
309 if (p_dcb->state && p_dcb->p_cs == p_depcs)
310 {
311 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
312 }
313 }
314 }
315 }
316 return result;
317 }
318
319 /*******************************************************************************
320 **
321 ** Function MCA_ConnectReq
322 **
323 ** Description This function initiates an MCAP control channel connection
324 ** to the peer device. When the connection is completed, an
325 ** MCA_CONNECT_IND_EVT is reported to the application via its
326 ** control callback function.
327 ** This control channel is identified by the tMCA_CL.
328 ** If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is
329 ** reported. The security mask parameter overrides the outgoing
330 ** security mask set in MCA_Register().
331 **
332 ** Returns MCA_SUCCESS if successful, otherwise error.
333 **
334 *******************************************************************************/
MCA_ConnectReq(tMCA_HANDLE handle,BD_ADDR bd_addr,UINT16 ctrl_psm,UINT16 sec_mask)335 tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
336 UINT16 ctrl_psm, UINT16 sec_mask)
337 {
338 tMCA_RESULT result = MCA_BAD_HANDLE;
339 tMCA_CCB *p_ccb;
340 tMCA_TC_TBL *p_tbl;
341
342 MCA_TRACE_API ("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
343 if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
344 p_ccb = mca_ccb_alloc(handle, bd_addr);
345 else
346 {
347 MCA_TRACE_ERROR ("control channel already exists");
348 return MCA_BUSY;
349 }
350
351 if (p_ccb)
352 {
353 p_ccb->ctrl_vpsm = L2CA_Register (ctrl_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
354 result = MCA_NO_RESOURCES;
355 if (p_ccb->ctrl_vpsm)
356 {
357 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
358 p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
359 p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
360 if (p_ccb->lcid)
361 {
362 p_tbl = mca_tc_tbl_calloc(p_ccb);
363 if (p_tbl)
364 {
365 p_tbl->state = MCA_TC_ST_CONN;
366 p_ccb->sec_mask = sec_mask;
367 result = MCA_SUCCESS;
368 }
369 }
370 }
371 if (result != MCA_SUCCESS)
372 mca_ccb_dealloc (p_ccb, NULL);
373 }
374 return result;
375 }
376
377
378 /*******************************************************************************
379 **
380 ** Function MCA_DisconnectReq
381 **
382 ** Description This function disconnect an MCAP control channel
383 ** to the peer device.
384 ** If associated data channel exists, they are disconnected.
385 ** When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
386 ** reported to the application via its control callback function.
387 **
388 ** Returns MCA_SUCCESS if successful, otherwise error.
389 **
390 *******************************************************************************/
MCA_DisconnectReq(tMCA_CL mcl)391 tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl)
392 {
393 tMCA_RESULT result = MCA_BAD_HANDLE;
394 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
395
396 MCA_TRACE_API ("MCA_DisconnectReq: %d ", mcl);
397 if (p_ccb)
398 {
399 result = MCA_SUCCESS;
400 mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
401 }
402 return result;
403 }
404
405
406 /*******************************************************************************
407 **
408 ** Function MCA_CreateMdl
409 **
410 ** Description This function sends a CREATE_MDL request to the peer device.
411 ** When the response is received, a MCA_CREATE_CFM_EVT is reported
412 ** with the given MDL ID.
413 ** If the response is successful, a data channel is open
414 ** with the given p_chnl_cfg
415 ** If p_chnl_cfg is NULL, the data channel is not initiated until
416 ** MCA_DataChnlCfg is called to provide the p_chnl_cfg.
417 ** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
418 ** is reported. This data channel is identified as tMCA_DL.
419 **
420 ** Returns MCA_SUCCESS if successful, otherwise error.
421 **
422 *******************************************************************************/
MCA_CreateMdl(tMCA_CL mcl,tMCA_DEP dep,UINT16 data_psm,UINT16 mdl_id,UINT8 peer_dep_id,UINT8 cfg,const tMCA_CHNL_CFG * p_chnl_cfg)423 tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
424 UINT16 mdl_id, UINT8 peer_dep_id,
425 UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg)
426 {
427 tMCA_RESULT result = MCA_BAD_HANDLE;
428 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
429 tMCA_CCB_MSG *p_evt_data;
430 tMCA_DCB *p_dcb;
431
432 MCA_TRACE_API ("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep, mdl_id, peer_dep_id);
433 if (p_ccb)
434 {
435 if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
436 {
437 MCA_TRACE_ERROR ("pending req");
438 return MCA_BUSY;
439 }
440
441 if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id)))
442 {
443 MCA_TRACE_ERROR ("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id, mdl_id);
444 return MCA_BAD_PARAMS;
445 }
446
447 if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
448 {
449 MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id);
450 return MCA_BAD_MDL_ID;
451 }
452
453 p_dcb = mca_dcb_alloc(p_ccb, dep);
454 result = MCA_NO_RESOURCES;
455 if (p_dcb)
456 {
457 /* save the info required by dcb connection */
458 p_dcb->p_chnl_cfg = p_chnl_cfg;
459 p_dcb->mdl_id = mdl_id;
460 p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
461 if (p_evt_data)
462 {
463 if (!p_ccb->data_vpsm)
464 p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
465 if (p_ccb->data_vpsm)
466 {
467 p_evt_data->dcb_idx = mca_dcb_to_hdl (p_dcb);
468 p_evt_data->mdep_id = peer_dep_id;
469 p_evt_data->mdl_id = mdl_id;
470 p_evt_data->param = cfg;
471 p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ;
472 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
473 p_evt_data->hdr.layer_specific = FALSE;
474 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
475 return MCA_SUCCESS;
476 }
477 else
478 GKI_freebuf (p_evt_data);
479 }
480 mca_dcb_dealloc(p_dcb, NULL);
481 }
482 }
483 return result;
484 }
485
486
487 /*******************************************************************************
488 **
489 ** Function MCA_CreateMdlRsp
490 **
491 ** Description This function sends a CREATE_MDL response to the peer device
492 ** in response to a received MCA_CREATE_IND_EVT.
493 ** If the rsp_code is successful, a data channel is open
494 ** with the given p_chnl_cfg
495 ** When the data channel is open successfully, a MCA_OPEN_IND_EVT
496 ** is reported. This data channel is identified as tMCA_DL.
497 **
498 ** Returns MCA_SUCCESS if successful, otherwise error.
499 **
500 *******************************************************************************/
MCA_CreateMdlRsp(tMCA_CL mcl,tMCA_DEP dep,UINT16 mdl_id,UINT8 cfg,UINT8 rsp_code,const tMCA_CHNL_CFG * p_chnl_cfg)501 tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
502 UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code,
503 const tMCA_CHNL_CFG *p_chnl_cfg)
504 {
505 tMCA_RESULT result = MCA_BAD_HANDLE;
506 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
507 tMCA_CCB_MSG evt_data;
508 tMCA_DCB *p_dcb;
509
510 MCA_TRACE_API ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code);
511 assert(p_chnl_cfg != NULL );
512 if (p_ccb)
513 {
514 if (p_ccb->cong)
515 {
516 MCA_TRACE_ERROR ("congested");
517 return MCA_BUSY;
518 }
519 if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep )
520 && (p_ccb->p_rx_msg->mdl_id == mdl_id) && (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ))
521 {
522 result = MCA_SUCCESS;
523 evt_data.dcb_idx = 0;
524 if (rsp_code == MCA_RSP_SUCCESS)
525 {
526 p_dcb = mca_dcb_alloc(p_ccb, dep);
527 if (p_dcb)
528 {
529 evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
530 p_dcb->p_chnl_cfg = p_chnl_cfg;
531 p_dcb->mdl_id = mdl_id;
532 }
533 else
534 {
535 rsp_code = MCA_RSP_MDEP_BUSY;
536 result = MCA_NO_RESOURCES;
537 }
538 }
539
540 if (result == MCA_SUCCESS)
541 {
542 evt_data.mdl_id = mdl_id;
543 evt_data.param = cfg;
544 evt_data.rsp_code = rsp_code;
545 evt_data.op_code = MCA_OP_MDL_CREATE_RSP;
546 mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
547 }
548 }
549 else
550 {
551 MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_CreateMdlRsp with the given parameters" );
552 result = MCA_BAD_PARAMS;
553 }
554 }
555 return result;
556 }
557
558 /*******************************************************************************
559 **
560 ** Function MCA_CloseReq
561 **
562 ** Description Close a data channel. When the channel is closed, an
563 ** MCA_CLOSE_CFM_EVT is sent to the application via the
564 ** control callback function for this handle.
565 **
566 ** Returns MCA_SUCCESS if successful, otherwise error.
567 **
568 *******************************************************************************/
MCA_CloseReq(tMCA_DL mdl)569 tMCA_RESULT MCA_CloseReq(tMCA_DL mdl)
570 {
571 tMCA_RESULT result = MCA_BAD_HANDLE;
572 tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
573
574 MCA_TRACE_API ("MCA_CloseReq: %d ", mdl);
575 if (p_dcb)
576 {
577 result = MCA_SUCCESS;
578 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
579 }
580 return result;
581 }
582
583
584 /*******************************************************************************
585 **
586 ** Function MCA_ReconnectMdl
587 **
588 ** Description This function sends a RECONNECT_MDL request to the peer device.
589 ** When the response is received, a MCA_RECONNECT_CFM_EVT is reported.
590 ** If p_chnl_cfg is NULL, the data channel is not initiated until
591 ** MCA_DataChnlCfg is called to provide the p_chnl_cfg.
592 ** If the response is successful, a data channel is open.
593 ** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
594 ** is reported.
595 **
596 ** Returns MCA_SUCCESS if successful, otherwise error.
597 **
598 *******************************************************************************/
MCA_ReconnectMdl(tMCA_CL mcl,tMCA_DEP dep,UINT16 data_psm,UINT16 mdl_id,const tMCA_CHNL_CFG * p_chnl_cfg)599 tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
600 UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg)
601 {
602 tMCA_RESULT result = MCA_BAD_HANDLE;
603 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
604 tMCA_CCB_MSG *p_evt_data;
605 tMCA_DCB *p_dcb;
606
607 MCA_TRACE_API ("MCA_ReconnectMdl: %d ", mcl);
608 assert(p_chnl_cfg != NULL );
609 if (p_ccb)
610 {
611 if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
612 {
613 MCA_TRACE_ERROR ("pending req");
614 return MCA_BUSY;
615 }
616
617 if (!MCA_IS_VALID_MDL_ID(mdl_id))
618 {
619 MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id);
620 return MCA_BAD_PARAMS;
621 }
622
623 if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
624 {
625 MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id);
626 return MCA_BAD_MDL_ID;
627 }
628
629 p_dcb = mca_dcb_alloc(p_ccb, dep);
630 result = MCA_NO_RESOURCES;
631 if (p_dcb)
632 {
633 p_dcb->p_chnl_cfg = p_chnl_cfg;
634 p_dcb->mdl_id = mdl_id;
635 p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
636 if (p_evt_data)
637 {
638 if (!p_ccb->data_vpsm)
639 p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
640 p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
641 p_evt_data->mdl_id = mdl_id;
642 p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ;
643 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
644 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
645 return MCA_SUCCESS;
646 }
647 mca_dcb_dealloc(p_dcb, NULL);
648 }
649 }
650 return result;
651 }
652
653
654 /*******************************************************************************
655 **
656 ** Function MCA_ReconnectMdlRsp
657 **
658 ** Description This function sends a RECONNECT_MDL response to the peer device
659 ** in response to a MCA_RECONNECT_IND_EVT event.
660 ** If the response is successful, a data channel is open.
661 ** When the data channel is open successfully, a MCA_OPEN_IND_EVT
662 ** is reported.
663 **
664 ** Returns MCA_SUCCESS if successful, otherwise error.
665 **
666 *******************************************************************************/
MCA_ReconnectMdlRsp(tMCA_CL mcl,tMCA_DEP dep,UINT16 mdl_id,UINT8 rsp_code,const tMCA_CHNL_CFG * p_chnl_cfg)667 tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
668 UINT16 mdl_id, UINT8 rsp_code,
669 const tMCA_CHNL_CFG *p_chnl_cfg)
670 {
671 tMCA_RESULT result = MCA_BAD_HANDLE;
672 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
673 tMCA_CCB_MSG evt_data;
674 tMCA_DCB *p_dcb;
675
676 MCA_TRACE_API ("MCA_ReconnectMdlRsp: %d ", mcl);
677 assert(p_chnl_cfg != NULL );
678 if (p_ccb)
679 {
680 if (p_ccb->cong)
681 {
682 MCA_TRACE_ERROR ("congested");
683 return MCA_BUSY;
684 }
685 if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
686 (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ))
687 {
688 result = MCA_SUCCESS;
689 evt_data.dcb_idx = 0;
690 if (rsp_code == MCA_RSP_SUCCESS)
691 {
692 p_dcb = mca_dcb_alloc(p_ccb, dep);
693 if (p_dcb)
694 {
695 evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
696 p_dcb->p_chnl_cfg = p_chnl_cfg;
697 p_dcb->mdl_id = mdl_id;
698 }
699 else
700 {
701 MCA_TRACE_ERROR ("Out of MDL for this MDEP");
702 rsp_code = MCA_RSP_MDEP_BUSY;
703 result = MCA_NO_RESOURCES;
704 }
705 }
706
707 evt_data.mdl_id = mdl_id;
708 evt_data.rsp_code = rsp_code;
709 evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP;
710 mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
711 }
712 else
713 {
714 MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_ReconnectMdlRsp with the given parameters" );
715 result = MCA_BAD_PARAMS;
716 }
717 }
718 return result;
719 }
720
721
722 /*******************************************************************************
723 **
724 ** Function MCA_DataChnlCfg
725 **
726 ** Description This function initiates a data channel connection toward the
727 ** connected peer device.
728 ** When the data channel is open successfully, a MCA_OPEN_CFM_EVT
729 ** is reported. This data channel is identified as tMCA_DL.
730 **
731 ** Returns MCA_SUCCESS if successful, otherwise error.
732 **
733 *******************************************************************************/
MCA_DataChnlCfg(tMCA_CL mcl,const tMCA_CHNL_CFG * p_chnl_cfg)734 tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg)
735 {
736 tMCA_RESULT result = MCA_BAD_HANDLE;
737 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
738 tMCA_DCB *p_dcb;
739 tMCA_TC_TBL *p_tbl;
740
741 MCA_TRACE_API ("MCA_DataChnlCfg: %d ", mcl);
742 assert(p_chnl_cfg != NULL );
743 if (p_ccb)
744 {
745 result = MCA_NO_RESOURCES;
746 if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
747 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
748 {
749 MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status);
750 return result;
751 }
752
753 p_dcb->p_chnl_cfg = p_chnl_cfg;
754 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
755 p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
756 p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
757 if (p_dcb->lcid)
758 {
759 p_tbl = mca_tc_tbl_dalloc(p_dcb);
760 if (p_tbl)
761 {
762 p_tbl->state = MCA_TC_ST_CONN;
763 result = MCA_SUCCESS;
764 }
765 }
766 }
767 return result;
768 }
769
770
771 /*******************************************************************************
772 **
773 ** Function MCA_Abort
774 **
775 ** Description This function sends a ABORT_MDL request to the peer device.
776 ** When the response is received, a MCA_ABORT_CFM_EVT is reported.
777 **
778 ** Returns MCA_SUCCESS if successful, otherwise error.
779 **
780 *******************************************************************************/
MCA_Abort(tMCA_CL mcl)781 tMCA_RESULT MCA_Abort(tMCA_CL mcl)
782 {
783 tMCA_RESULT result = MCA_BAD_HANDLE;
784 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
785 tMCA_CCB_MSG *p_evt_data;
786 tMCA_DCB *p_dcb;
787
788 MCA_TRACE_API ("MCA_Abort: %d", mcl);
789 if (p_ccb)
790 {
791 result = MCA_NO_RESOURCES;
792 /* verify that we are waiting for data channel to come up with the given mdl */
793 if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
794 ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
795 {
796 MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status);
797 return result;
798 }
799
800 if (p_ccb->cong)
801 {
802 MCA_TRACE_ERROR ("congested");
803 return MCA_BUSY;
804 }
805
806 result = MCA_NO_RESOURCES;
807 p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
808 if (p_evt_data)
809 {
810 result = MCA_SUCCESS;
811 p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ;
812 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
813 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
814 }
815
816 }
817 return result;
818 }
819
820
821 /*******************************************************************************
822 **
823 ** Function MCA_Delete
824 **
825 ** Description This function sends a DELETE_MDL request to the peer device.
826 ** When the response is received, a MCA_DELETE_CFM_EVT is reported.
827 **
828 ** Returns MCA_SUCCESS if successful, otherwise error.
829 **
830 *******************************************************************************/
MCA_Delete(tMCA_CL mcl,UINT16 mdl_id)831 tMCA_RESULT MCA_Delete(tMCA_CL mcl, UINT16 mdl_id)
832 {
833 tMCA_RESULT result = MCA_BAD_HANDLE;
834 tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
835 tMCA_CCB_MSG *p_evt_data;
836
837 MCA_TRACE_API ("MCA_Delete: %d ", mcl);
838 if (p_ccb)
839 {
840 if (p_ccb->cong)
841 {
842 MCA_TRACE_ERROR ("congested");
843 return MCA_BUSY;
844 }
845 if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID))
846 {
847 MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id);
848 return MCA_BAD_PARAMS;
849 }
850 p_evt_data = (tMCA_CCB_MSG *)GKI_getbuf (sizeof(tMCA_CCB_MSG));
851 if (p_evt_data)
852 {
853 result = MCA_SUCCESS;
854 p_evt_data->mdl_id = mdl_id;
855 p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ;
856 p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
857 mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
858 }
859 else
860 result = MCA_NO_RESOURCES;
861 }
862 return result;
863 }
864
865 /*******************************************************************************
866 **
867 ** Function MCA_WriteReq
868 **
869 ** Description Send a data packet to the peer device.
870 **
871 ** The application passes the packet using the BT_HDR structure.
872 ** The offset field must be equal to or greater than L2CAP_MIN_OFFSET.
873 ** This allows enough space in the buffer for the L2CAP header.
874 **
875 ** The memory pointed to by p_pkt must be a GKI buffer
876 ** allocated by the application. This buffer will be freed
877 ** by the protocol stack; the application must not free
878 ** this buffer.
879 **
880 ** Returns MCA_SUCCESS if successful, otherwise error.
881 **
882 *******************************************************************************/
MCA_WriteReq(tMCA_DL mdl,BT_HDR * p_pkt)883 tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt)
884 {
885 tMCA_RESULT result = MCA_BAD_HANDLE;
886 tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
887 tMCA_DCB_EVT evt_data;
888
889 MCA_TRACE_API ("MCA_WriteReq: %d ", mdl);
890 if (p_dcb)
891 {
892 if (p_dcb->cong)
893 {
894 result = MCA_BUSY;
895 }
896 else
897 {
898 evt_data.p_pkt = p_pkt;
899 result = MCA_SUCCESS;
900 mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
901 }
902 }
903 return result;
904 }
905
906 /*******************************************************************************
907 **
908 ** Function MCA_GetL2CapChannel
909 **
910 ** Description Get the L2CAP CID used by the given data channel handle.
911 **
912 ** Returns L2CAP channel ID if successful, otherwise 0.
913 **
914 *******************************************************************************/
MCA_GetL2CapChannel(tMCA_DL mdl)915 UINT16 MCA_GetL2CapChannel (tMCA_DL mdl)
916 {
917 UINT16 lcid = 0;
918 tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
919
920 MCA_TRACE_API ("MCA_GetL2CapChannel: %d ", mdl);
921 if (p_dcb)
922 lcid = p_dcb->lcid;
923 return lcid;
924 }
925
926