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