• 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 at L2CAP Interface.
22  *
23  ******************************************************************************/
24 #include <string.h>
25 
26 #include "bt_target.h"
27 #include "bt_utils.h"
28 #include "btm_api.h"
29 #include "btm_int.h"
30 #include "mca_api.h"
31 #include "mca_defs.h"
32 #include "mca_int.h"
33 #include "osi/include/osi.h"
34 
35 /* L2CAP callback function structure */
36 const tL2CAP_APPL_INFO mca_l2c_int_appl = {NULL,
37                                            mca_l2c_connect_cfm_cback,
38                                            NULL,
39                                            mca_l2c_config_ind_cback,
40                                            mca_l2c_config_cfm_cback,
41                                            mca_l2c_disconnect_ind_cback,
42                                            mca_l2c_disconnect_cfm_cback,
43                                            NULL,
44                                            mca_l2c_data_ind_cback,
45                                            mca_l2c_congestion_ind_cback,
46                                            NULL};
47 
48 /* Control channel eL2CAP default options */
49 const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = {
50     L2CAP_FCR_ERTM_MODE,          /* Mandatory for MCAP */
51     MCA_FCR_OPT_TX_WINDOW_SIZE,   /* Tx window size */
52     MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before
53                                      disconnecting */
54     MCA_FCR_OPT_RETX_TOUT,        /* Retransmission timeout (2 secs) */
55     MCA_FCR_OPT_MONITOR_TOUT,     /* Monitor timeout (12 secs) */
56     MCA_FCR_OPT_MPS_SIZE          /* MPS segment size */
57 };
58 
59 /*******************************************************************************
60  *
61  * Function         mca_sec_check_complete_term
62  *
63  * Description      The function called when Security Manager finishes
64  *                  verification of the service side connection
65  *
66  * Returns          void
67  *
68  ******************************************************************************/
mca_sec_check_complete_term(const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)69 static void mca_sec_check_complete_term(const RawAddress* bd_addr,
70                                         UNUSED_ATTR tBT_TRANSPORT transport,
71                                         void* p_ref_data, uint8_t res) {
72   tMCA_TC_TBL* p_tbl = (tMCA_TC_TBL*)p_ref_data;
73   tL2CAP_CFG_INFO cfg;
74   tL2CAP_ERTM_INFO ertm_info;
75 
76   MCA_TRACE_DEBUG("mca_sec_check_complete_term res: %d", res);
77 
78   if (res == BTM_SUCCESS) {
79     MCA_TRACE_DEBUG("lcid:x%x id:x%x", p_tbl->lcid, p_tbl->id);
80     /* Set the FCR options: control channel mandates ERTM */
81     ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
82     ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
83     ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
84     ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
85     ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
86     ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
87     /* Send response to the L2CAP layer. */
88     L2CA_ErtmConnectRsp(*bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK,
89                         L2CAP_CONN_OK, &ertm_info);
90 
91     /* transition to configuration state */
92     p_tbl->state = MCA_TC_ST_CFG;
93 
94     /* Send L2CAP config req */
95     mca_set_cfg_by_tbl(&cfg, p_tbl);
96     L2CA_ConfigReq(p_tbl->lcid, &cfg);
97   } else {
98     L2CA_ConnectRsp(*bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK,
99                     L2CAP_CONN_OK);
100     mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
101   }
102 }
103 
104 /*******************************************************************************
105  *
106  * Function         mca_sec_check_complete_orig
107  *
108  * Description      The function called when Security Manager finishes
109  *                  verification of the service side connection
110  *
111  * Returns          void
112  *
113  ******************************************************************************/
mca_sec_check_complete_orig(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)114 static void mca_sec_check_complete_orig(UNUSED_ATTR const RawAddress* bd_addr,
115                                         UNUSED_ATTR tBT_TRANSPORT transport,
116                                         void* p_ref_data, uint8_t res) {
117   tMCA_TC_TBL* p_tbl = (tMCA_TC_TBL*)p_ref_data;
118   tL2CAP_CFG_INFO cfg;
119 
120   MCA_TRACE_DEBUG("mca_sec_check_complete_orig res: %d", res);
121 
122   if (res == BTM_SUCCESS) {
123     /* set channel state */
124     p_tbl->state = MCA_TC_ST_CFG;
125 
126     /* Send L2CAP config req */
127     mca_set_cfg_by_tbl(&cfg, p_tbl);
128     L2CA_ConfigReq(p_tbl->lcid, &cfg);
129   } else {
130     L2CA_DisconnectReq(p_tbl->lcid);
131     mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
132   }
133 }
134 /*******************************************************************************
135  *
136  * Function         mca_l2c_cconn_ind_cback
137  *
138  * Description      This is the L2CAP connect indication callback function.
139  *
140  * Returns          void
141  *
142  ******************************************************************************/
mca_l2c_cconn_ind_cback(const RawAddress & bd_addr,uint16_t lcid,uint16_t psm,uint8_t id)143 void mca_l2c_cconn_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
144                              uint16_t psm, uint8_t id) {
145   tMCA_HANDLE handle = mca_handle_by_cpsm(psm);
146   tMCA_CCB* p_ccb;
147   tMCA_TC_TBL* p_tbl = NULL;
148   uint16_t result = L2CAP_CONN_NO_RESOURCES;
149   tBTM_STATUS rc;
150   tL2CAP_ERTM_INFO ertm_info, *p_ertm_info = NULL;
151   tL2CAP_CFG_INFO cfg;
152 
153   MCA_TRACE_EVENT("mca_l2c_cconn_ind_cback: lcid:x%x psm:x%x id:x%x", lcid, psm,
154                   id);
155 
156   /* do we already have a control channel for this peer? */
157   p_ccb = mca_ccb_by_bd(handle, bd_addr);
158   if (p_ccb == NULL) {
159     /* no, allocate ccb */
160     p_ccb = mca_ccb_alloc(handle, bd_addr);
161     if (p_ccb != NULL) {
162       /* allocate and set up entry */
163       p_ccb->lcid = lcid;
164       p_tbl = mca_tc_tbl_calloc(p_ccb);
165       p_tbl->id = id;
166       p_tbl->cfg_flags = MCA_L2C_CFG_CONN_ACP;
167       /* proceed with connection */
168       /* Check the security */
169       rc = btm_sec_mx_access_request(bd_addr, psm, false, BTM_SEC_PROTO_MCA, 0,
170                                      &mca_sec_check_complete_term, p_tbl);
171       if (rc == BTM_CMD_STARTED) {
172         /* Set the FCR options: control channel mandates ERTM */
173         ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
174         ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
175         ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
176         ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
177         ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
178         ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
179         p_ertm_info = &ertm_info;
180         result = L2CAP_CONN_PENDING;
181       } else
182         result = L2CAP_CONN_OK;
183     }
184 
185     /*  deal with simultaneous control channel connect case */
186   }
187   /* else reject their connection */
188 
189   if (!p_tbl || (p_tbl->state != MCA_TC_ST_CFG)) {
190     /* Send L2CAP connect rsp */
191     L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
192 
193     /* if result ok, proceed with connection and send L2CAP
194        config req */
195     if (result == L2CAP_CONN_OK) {
196       /* set channel state */
197       p_tbl->state = MCA_TC_ST_CFG;
198 
199       /* Send L2CAP config req */
200       mca_set_cfg_by_tbl(&cfg, p_tbl);
201       L2CA_ConfigReq(p_tbl->lcid, &cfg);
202     }
203   }
204 }
205 
206 /*******************************************************************************
207  *
208  * Function         mca_l2c_dconn_ind_cback
209  *
210  * Description      This is the L2CAP connect indication callback function.
211  *
212  *
213  * Returns          void
214  *
215  ******************************************************************************/
mca_l2c_dconn_ind_cback(const RawAddress & bd_addr,uint16_t lcid,uint16_t psm,uint8_t id)216 void mca_l2c_dconn_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
217                              uint16_t psm, uint8_t id) {
218   tMCA_HANDLE handle = mca_handle_by_dpsm(psm);
219   tMCA_CCB* p_ccb;
220   tMCA_DCB* p_dcb;
221   tMCA_TC_TBL* p_tbl = NULL;
222   uint16_t result;
223   tL2CAP_CFG_INFO cfg;
224   tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info;
225   const tMCA_CHNL_CFG* p_chnl_cfg;
226 
227   MCA_TRACE_EVENT("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm);
228 
229   if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */
230       (p_ccb->status ==
231        MCA_CCB_STAT_PENDING) && /* this CCB is expecting a MDL */
232       (p_ccb->p_tx_req &&
233        (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
234     /* found the associated dcb in listening mode */
235     /* proceed with connection */
236     p_dcb->lcid = lcid;
237     p_tbl = mca_tc_tbl_dalloc(p_dcb);
238     p_tbl->id = id;
239     p_tbl->cfg_flags = MCA_L2C_CFG_CONN_ACP;
240     p_chnl_cfg = p_dcb->p_chnl_cfg;
241     /* assume that control channel has verified the security requirement */
242     /* Set the FCR options: control channel mandates ERTM */
243     ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
244     ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
245     ertm_info.user_rx_buf_size = p_chnl_cfg->user_rx_buf_size;
246     ertm_info.user_tx_buf_size = p_chnl_cfg->user_tx_buf_size;
247     ertm_info.fcr_rx_buf_size = p_chnl_cfg->fcr_rx_buf_size;
248     ertm_info.fcr_tx_buf_size = p_chnl_cfg->fcr_tx_buf_size;
249     p_ertm_info = &ertm_info;
250     result = L2CAP_CONN_OK;
251   } else {
252     /* else we're not listening for traffic channel; reject
253      * (this error code is specified by MCAP spec) */
254     result = L2CAP_CONN_NO_RESOURCES;
255   }
256 
257   /* Send L2CAP connect rsp */
258   L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, result, p_ertm_info);
259 
260   /* if result ok, proceed with connection */
261   if (result == L2CAP_CONN_OK) {
262     /* transition to configuration state */
263     p_tbl->state = MCA_TC_ST_CFG;
264 
265     /* Send L2CAP config req */
266     mca_set_cfg_by_tbl(&cfg, p_tbl);
267     L2CA_ConfigReq(lcid, &cfg);
268   }
269 }
270 
271 /*******************************************************************************
272  *
273  * Function         mca_l2c_connect_cfm_cback
274  *
275  * Description      This is the L2CAP connect confirm callback function.
276  *
277  *
278  * Returns          void
279  *
280  ******************************************************************************/
mca_l2c_connect_cfm_cback(uint16_t lcid,uint16_t result)281 void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
282   tMCA_TC_TBL* p_tbl;
283   tL2CAP_CFG_INFO cfg;
284   tMCA_CCB* p_ccb;
285 
286   MCA_TRACE_DEBUG("mca_l2c_connect_cfm_cback lcid: x%x, result: %d", lcid,
287                   result);
288   /* look up info for this channel */
289   p_tbl = mca_tc_tbl_by_lcid(lcid);
290   if (p_tbl != NULL) {
291     MCA_TRACE_DEBUG("p_tbl state: %d, tcid: %d", p_tbl->state, p_tbl->tcid);
292     /* if in correct state */
293     if (p_tbl->state == MCA_TC_ST_CONN) {
294       /* if result successful */
295       if (result == L2CAP_CONN_OK) {
296         if (p_tbl->tcid != 0) {
297           /* set channel state */
298           p_tbl->state = MCA_TC_ST_CFG;
299 
300           /* Send L2CAP config req */
301           mca_set_cfg_by_tbl(&cfg, p_tbl);
302           L2CA_ConfigReq(lcid, &cfg);
303         } else {
304           p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
305           if (p_ccb == NULL) {
306             result = L2CAP_CONN_NO_RESOURCES;
307           } else {
308             /* set channel state */
309             p_tbl->state = MCA_TC_ST_SEC_INT;
310             p_tbl->lcid = lcid;
311             p_tbl->cfg_flags = MCA_L2C_CFG_CONN_INT;
312 
313             /* Check the security */
314             btm_sec_mx_access_request(p_ccb->peer_addr, p_ccb->ctrl_vpsm, true,
315                                       BTM_SEC_PROTO_MCA, p_tbl->tcid,
316                                       &mca_sec_check_complete_orig, p_tbl);
317           }
318         }
319       }
320 
321       /* failure; notify adaption that channel closed */
322       if (result != L2CAP_CONN_OK) {
323         p_tbl->cfg_flags |= MCA_L2C_CFG_DISCN_INT;
324         mca_tc_close_ind(p_tbl, result);
325       }
326     }
327   }
328 }
329 
330 /*******************************************************************************
331  *
332  * Function         mca_l2c_config_cfm_cback
333  *
334  * Description      This is the L2CAP config confirm callback function.
335  *
336  *
337  * Returns          void
338  *
339  ******************************************************************************/
mca_l2c_config_cfm_cback(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)340 void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
341   tMCA_TC_TBL* p_tbl;
342 
343   /* look up info for this channel */
344   p_tbl = mca_tc_tbl_by_lcid(lcid);
345   if (p_tbl != NULL) {
346     /* if in correct state */
347     if (p_tbl->state == MCA_TC_ST_CFG) {
348       /* if result successful */
349       if (p_cfg->result == L2CAP_CONN_OK) {
350         /* update cfg_flags */
351         p_tbl->cfg_flags |= MCA_L2C_CFG_CFM_DONE;
352 
353         /* if configuration complete */
354         if (p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) {
355           mca_tc_open_ind(p_tbl);
356         }
357       }
358       /* else failure */
359       else {
360         /* Send L2CAP disconnect req */
361         L2CA_DisconnectReq(lcid);
362       }
363     }
364   }
365 }
366 
367 /*******************************************************************************
368  *
369  * Function         mca_l2c_config_ind_cback
370  *
371  * Description      This is the L2CAP config indication callback function.
372  *
373  *
374  * Returns          void
375  *
376  ******************************************************************************/
mca_l2c_config_ind_cback(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)377 void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
378   tMCA_TC_TBL* p_tbl;
379   uint16_t result = L2CAP_CFG_OK;
380 
381   /* look up info for this channel */
382   p_tbl = mca_tc_tbl_by_lcid(lcid);
383   if (p_tbl != NULL) {
384     /* store the mtu in tbl */
385     if (p_cfg->mtu_present) {
386       p_tbl->peer_mtu = p_cfg->mtu;
387       if (p_tbl->peer_mtu < MCA_MIN_MTU) {
388         result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
389       }
390     } else {
391       p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
392     }
393     MCA_TRACE_DEBUG("peer_mtu: %d, lcid: x%x mtu_present:%d", p_tbl->peer_mtu,
394                     lcid, p_cfg->mtu_present);
395 
396     /* send L2CAP configure response */
397     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
398     p_cfg->result = result;
399     L2CA_ConfigRsp(lcid, p_cfg);
400 
401     /* if first config ind */
402     if ((p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) == 0) {
403       /* update cfg_flags */
404       p_tbl->cfg_flags |= MCA_L2C_CFG_IND_DONE;
405 
406       /* if configuration complete */
407       if (p_tbl->cfg_flags & MCA_L2C_CFG_CFM_DONE) {
408         mca_tc_open_ind(p_tbl);
409       }
410     }
411   }
412 }
413 
414 /*******************************************************************************
415  *
416  * Function         mca_l2c_disconnect_ind_cback
417  *
418  * Description      This is the L2CAP disconnect indication callback function.
419  *
420  *
421  * Returns          void
422  *
423  ******************************************************************************/
mca_l2c_disconnect_ind_cback(uint16_t lcid,bool ack_needed)424 void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
425   tMCA_TC_TBL* p_tbl;
426   uint16_t reason = L2CAP_DISC_TIMEOUT;
427 
428   MCA_TRACE_DEBUG("mca_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d", lcid,
429                   ack_needed);
430   /* look up info for this channel */
431   p_tbl = mca_tc_tbl_by_lcid(lcid);
432   if (p_tbl != NULL) {
433     if (ack_needed) {
434       /* send L2CAP disconnect response */
435       L2CA_DisconnectRsp(lcid);
436     }
437 
438     p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_ACP;
439     if (ack_needed) reason = L2CAP_DISC_OK;
440     mca_tc_close_ind(p_tbl, reason);
441   }
442 }
443 
444 /*******************************************************************************
445  *
446  * Function         mca_l2c_disconnect_cfm_cback
447  *
448  * Description      This is the L2CAP disconnect confirm callback function.
449  *
450  *
451  * Returns          void
452  *
453  ******************************************************************************/
mca_l2c_disconnect_cfm_cback(uint16_t lcid,uint16_t result)454 void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
455   tMCA_TC_TBL* p_tbl;
456 
457   MCA_TRACE_DEBUG("mca_l2c_disconnect_cfm_cback lcid: x%x, result: %d", lcid,
458                   result);
459   /* look up info for this channel */
460   p_tbl = mca_tc_tbl_by_lcid(lcid);
461   if (p_tbl != NULL) {
462     p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_INT;
463     mca_tc_close_ind(p_tbl, result);
464   }
465 }
466 
467 /*******************************************************************************
468  *
469  * Function         mca_l2c_congestion_ind_cback
470  *
471  * Description      This is the L2CAP congestion indication callback function.
472  *
473  *
474  * Returns          void
475  *
476  ******************************************************************************/
mca_l2c_congestion_ind_cback(uint16_t lcid,bool is_congested)477 void mca_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
478   tMCA_TC_TBL* p_tbl;
479 
480   /* look up info for this channel */
481   p_tbl = mca_tc_tbl_by_lcid(lcid);
482   if (p_tbl != NULL) {
483     mca_tc_cong_ind(p_tbl, is_congested);
484   }
485 }
486 
487 /*******************************************************************************
488  *
489  * Function         mca_l2c_data_ind_cback
490  *
491  * Description      This is the L2CAP data indication callback function.
492  *
493  *
494  * Returns          void
495  *
496  ******************************************************************************/
mca_l2c_data_ind_cback(uint16_t lcid,BT_HDR * p_buf)497 void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
498   tMCA_TC_TBL* p_tbl;
499 
500   /* look up info for this channel */
501   p_tbl = mca_tc_tbl_by_lcid(lcid);
502   if (p_tbl != NULL) {
503     mca_tc_data_ind(p_tbl, p_buf);
504   } else /* prevent buffer leak */
505     osi_free(p_buf);
506 }
507 
508 /*******************************************************************************
509  *
510  * Function         mca_l2c_open_req
511  *
512  * Description      This function calls L2CA_ConnectReq() to initiate a L2CAP
513  *                  channel.
514  *
515  * Returns          void.
516  *
517  ******************************************************************************/
mca_l2c_open_req(const RawAddress & bd_addr,uint16_t psm,const tMCA_CHNL_CFG * p_chnl_cfg)518 uint16_t mca_l2c_open_req(const RawAddress& bd_addr, uint16_t psm,
519                           const tMCA_CHNL_CFG* p_chnl_cfg) {
520   tL2CAP_ERTM_INFO ertm_info;
521 
522   if (p_chnl_cfg) {
523     ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
524     ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
525     ertm_info.user_rx_buf_size = p_chnl_cfg->user_rx_buf_size;
526     ertm_info.user_tx_buf_size = p_chnl_cfg->user_tx_buf_size;
527     ertm_info.fcr_rx_buf_size = p_chnl_cfg->fcr_rx_buf_size;
528     ertm_info.fcr_tx_buf_size = p_chnl_cfg->fcr_tx_buf_size;
529   } else {
530     ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
531     ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
532     ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
533     ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
534     ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
535     ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
536   }
537   return L2CA_ErtmConnectReq(psm, bd_addr, &ertm_info);
538 }
539