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