• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2008-2016 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  *  Name:           avct_l2c_br.cc
22  *
23  *  Description:    This AVCTP module interfaces to L2CAP
24  *
25  *****************************************************************************/
26 
27 #include "avct_api.h"
28 #include "avct_int.h"
29 #include "bt_target.h"
30 #include "l2c_api.h"
31 #include "l2cdefs.h"
32 #include "osi/include/osi.h"
33 
34 /* callback function declarations */
35 void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
36                                    uint16_t psm, uint8_t id);
37 void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result);
38 void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t result,
39                                   tL2CAP_CFG_INFO* p_cfg);
40 void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
41 void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
42 void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested);
43 void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
44 void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result);
45 
46 /* L2CAP callback function structure */
47 const tL2CAP_APPL_INFO avct_l2c_br_appl = {
48     avct_l2c_br_connect_ind_cback,    avct_l2c_br_connect_cfm_cback,
49     avct_l2c_br_config_ind_cback,     avct_l2c_br_config_cfm_cback,
50     avct_l2c_br_disconnect_ind_cback, avct_l2c_br_data_ind_cback,
51     avct_l2c_br_congestion_ind_cback, NULL,
52     avct_br_on_l2cap_error,           NULL,
53     NULL,                             NULL
54 };
55 
56 /*******************************************************************************
57  *
58  * Function         avct_l2c_br_connect_ind_cback
59  *
60  * Description      This is the L2CAP connect indication callback function.
61  *
62  *
63  * Returns          void
64  *
65  ******************************************************************************/
avct_l2c_br_connect_ind_cback(const RawAddress & bd_addr,uint16_t lcid,UNUSED_ATTR uint16_t psm,uint8_t id)66 void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
67                                    UNUSED_ATTR uint16_t psm, uint8_t id) {
68   tAVCT_LCB* p_lcb;
69   uint16_t result = L2CAP_CONN_NO_RESOURCES;
70   tAVCT_BCB* p_bcb;
71   tL2CAP_ERTM_INFO ertm_info;
72 
73   p_lcb = avct_lcb_by_bd(bd_addr);
74   if (p_lcb != NULL) {
75     /* control channel exists */
76     p_bcb = avct_bcb_by_lcb(p_lcb);
77     p_bcb->peer_addr = bd_addr;
78 
79     if (p_bcb->allocated == 0) {
80       /* browsing channel does not exist yet and the browsing channel is
81        * registered
82        * - accept connection */
83       p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */
84 
85       result = L2CAP_CONN_OK;
86     }
87   }
88   /* else no control channel yet, reject */
89 
90   /* Set the FCR options: Browsing channel mandates ERTM */
91   ertm_info.preferred_mode = L2CAP_FCR_ERTM_MODE;
92 
93   /* If we reject the connection, send DisconnectReq */
94   if (result != L2CAP_CONN_OK) {
95     L2CA_DisconnectReq(lcid);
96   }
97 
98   /* if result ok, proceed with connection */
99   if (result == L2CAP_CONN_OK) {
100     /* store LCID */
101     p_bcb->ch_lcid = lcid;
102 
103     /* transition to configuration state */
104     p_bcb->ch_state = AVCT_CH_CFG;
105   }
106 }
107 
avct_br_on_l2cap_error(uint16_t lcid,uint16_t result)108 void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result) {
109   tAVCT_BCB* p_lcb = avct_bcb_by_lcid(lcid);
110   if (p_lcb == nullptr) return;
111 
112   /* store result value */
113   p_lcb->ch_result = result;
114 
115   /* Send L2CAP disconnect req */
116   avct_l2c_br_disconnect(lcid, 0);
117 }
118 
119 /*******************************************************************************
120  *
121  * Function         avct_l2c_br_connect_cfm_cback
122  *
123  * Description      This is the L2CAP connect confirm callback function.
124  *
125  *
126  * Returns          void
127  *
128  ******************************************************************************/
avct_l2c_br_connect_cfm_cback(uint16_t lcid,uint16_t result)129 void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result) {
130   tAVCT_BCB* p_lcb;
131 
132   /* look up lcb for this channel */
133   p_lcb = avct_bcb_by_lcid(lcid);
134   if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CONN)) return;
135 
136   if (result != L2CAP_CONN_OK) {
137     LOG(ERROR) << __func__ << ": invoked with non OK status";
138     return;
139   }
140 
141   /* result is successful */
142   /* set channel state */
143   p_lcb->ch_state = AVCT_CH_CFG;
144 }
145 
146 /*******************************************************************************
147  *
148  * Function         avct_l2c_br_config_cfm_cback
149  *
150  * Description      This is the L2CAP config confirm callback function.
151  *
152  *
153  * Returns          void
154  *
155  ******************************************************************************/
avct_l2c_br_config_cfm_cback(uint16_t lcid,uint16_t initiator,tL2CAP_CFG_INFO * p_cfg)156 void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t initiator,
157                                   tL2CAP_CFG_INFO* p_cfg) {
158   avct_l2c_br_config_ind_cback(lcid, p_cfg);
159 
160   tAVCT_BCB* p_lcb;
161 
162   /* look up lcb for this channel */
163   p_lcb = avct_bcb_by_lcid(lcid);
164   if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CFG)) return;
165 
166   p_lcb->ch_state = AVCT_CH_OPEN;
167   avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
168 }
169 
170 /*******************************************************************************
171  *
172  * Function         avct_l2c_br_config_ind_cback
173  *
174  * Description      This is the L2CAP config indication callback function.
175  *
176  *
177  * Returns          void
178  *
179  ******************************************************************************/
avct_l2c_br_config_ind_cback(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)180 void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
181   tAVCT_BCB* p_lcb;
182   uint16_t max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE;
183 
184   /* look up lcb for this channel */
185   p_lcb = avct_bcb_by_lcid(lcid);
186   if (p_lcb == NULL) return;
187 
188   /* store the mtu in tbl */
189   p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
190   if (p_cfg->mtu_present) {
191     p_lcb->peer_mtu = p_cfg->mtu;
192   }
193 
194   if (p_lcb->peer_mtu > max_mtu) {
195     p_lcb->peer_mtu = max_mtu;
196   }
197 
198   AVCT_TRACE_DEBUG("%s peer_mtu:%d use:%d", __func__, p_lcb->peer_mtu, max_mtu);
199 }
200 
201 /*******************************************************************************
202  *
203  * Function         avct_l2c_br_disconnect_ind_cback
204  *
205  * Description      This is the L2CAP disconnect indication callback function.
206  *
207  *
208  * Returns          void
209  *
210  ******************************************************************************/
avct_l2c_br_disconnect_ind_cback(uint16_t lcid,bool ack_needed)211 void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
212   tAVCT_BCB* p_lcb;
213   uint16_t result = AVCT_RESULT_FAIL;
214 
215   /* look up lcb for this channel */
216   p_lcb = avct_bcb_by_lcid(lcid);
217   if (p_lcb == NULL) return;
218 
219   tAVCT_LCB_EVT avct_lcb_evt;
220   avct_lcb_evt.result = result;
221   avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
222 }
223 
avct_l2c_br_disconnect(uint16_t lcid,uint16_t result)224 void avct_l2c_br_disconnect(uint16_t lcid, uint16_t result) {
225   L2CA_DisconnectReq(lcid);
226 
227   tAVCT_BCB* p_lcb;
228   uint16_t res;
229 
230   /* look up lcb for this channel */
231   p_lcb = avct_bcb_by_lcid(lcid);
232   if (p_lcb == NULL) return;
233 
234   /* result value may be previously stored */
235   res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
236   p_lcb->ch_result = 0;
237 
238   tAVCT_LCB_EVT avct_lcb_evt;
239   avct_lcb_evt.result = res;
240   avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
241 }
242 
243 /*******************************************************************************
244  *
245  * Function         avct_l2c_br_congestion_ind_cback
246  *
247  * Description      This is the L2CAP congestion indication callback function.
248  *
249  *
250  * Returns          void
251  *
252  ******************************************************************************/
avct_l2c_br_congestion_ind_cback(uint16_t lcid,bool is_congested)253 void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested) {
254   tAVCT_BCB* p_lcb;
255 
256   /* look up lcb for this channel */
257   p_lcb = avct_bcb_by_lcid(lcid);
258   if (p_lcb == NULL) return;
259 
260   tAVCT_LCB_EVT avct_lcb_evt;
261   avct_lcb_evt.cong = is_congested;
262   avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, &avct_lcb_evt);
263 }
264 
265 /*******************************************************************************
266  *
267  * Function         avct_l2c_br_data_ind_cback
268  *
269  * Description      This is the L2CAP data indication callback function.
270  *
271  *
272  * Returns          void
273  *
274  ******************************************************************************/
avct_l2c_br_data_ind_cback(uint16_t lcid,BT_HDR * p_buf)275 void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
276   tAVCT_BCB* p_lcb;
277   tAVCT_LCB_EVT evt_data;
278 
279   /* look up lcb for this channel */
280   p_lcb = avct_bcb_by_lcid(lcid);
281   if (p_lcb == NULL) {
282     /* prevent buffer leak */
283     osi_free(p_buf);
284     return;
285   }
286 
287   evt_data.p_buf = p_buf;
288   avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, &evt_data);
289 }
290