1 /******************************************************************************
2 *
3 * Copyright (C) 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 <string.h>
28 #include "avct_api.h"
29 #include "avct_int.h"
30 #include "bt_target.h"
31 #include "bt_utils.h"
32 #include "l2c_api.h"
33 #include "l2cdefs.h"
34 #include "osi/include/osi.h"
35
36 /* Configuration flags. */
37 #define AVCT_L2C_CFG_IND_DONE (1 << 0)
38 #define AVCT_L2C_CFG_CFM_DONE (1 << 1)
39
40 /* AVCTP Browsing channel FCR Option:
41 * Size of the transmission window when using enhanced retransmission mode. Not
42 * used in basic and streaming modes. Range: 1 - 63
43 */
44 #define AVCT_BR_FCR_OPT_TX_WINDOW_SIZE 10
45
46 /* AVCTP Browsing channel FCR Option:
47 * Number of transmission attempts for a single I-Frame before taking
48 * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
49 * Streaming modes.
50 * Range: 0, 1-0xFF
51 * 0 - infinite retransmissions
52 * 1 - single transmission
53 */
54 #define AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT 20
55
56 /* AVCTP Browsing channel FCR Option: Retransmission Timeout
57 * The AVRCP specification set a value in the range of 300 - 2000 ms
58 * Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced
59 * retransmission mode.
60 * Range: Minimum 2000 (2 secs) when supporting PBF.
61 */
62 #define AVCT_BR_FCR_OPT_RETX_TOUT 2000
63
64 /* AVCTP Browsing channel FCR Option: Monitor Timeout
65 * The AVRCP specification set a value in the range of 300 - 2000 ms
66 * Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced
67 * retransmission mode.
68 * Range: Minimum 12000 (12 secs) when supporting PBF.
69 */
70 #define AVCT_BR_FCR_OPT_MONITOR_TOUT 12000
71
72 /* callback function declarations */
73 void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
74 uint8_t id);
75 void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result);
76 void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
77 void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
78 void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
79 void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
80 void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested);
81 void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
82
83 /* L2CAP callback function structure */
84 const tL2CAP_APPL_INFO avct_l2c_br_appl = {
85 avct_l2c_br_connect_ind_cback,
86 avct_l2c_br_connect_cfm_cback,
87 NULL,
88 avct_l2c_br_config_ind_cback,
89 avct_l2c_br_config_cfm_cback,
90 avct_l2c_br_disconnect_ind_cback,
91 avct_l2c_br_disconnect_cfm_cback,
92 NULL,
93 avct_l2c_br_data_ind_cback,
94 avct_l2c_br_congestion_ind_cback,
95 NULL /* tL2CA_TX_COMPLETE_CB */
96 };
97
98 /* Browsing channel eL2CAP default options */
99 const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def = {
100 L2CAP_FCR_ERTM_MODE, /* Mandatory for Browsing channel */
101 AVCT_BR_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
102 AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before
103 disconnecting */
104 AVCT_BR_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
105 AVCT_BR_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
106 L2CAP_DEFAULT_ERM_MPS /* MPS segment size */
107 };
108
109 /*******************************************************************************
110 *
111 * Function avct_l2c_br_connect_ind_cback
112 *
113 * Description This is the L2CAP connect indication callback function.
114 *
115 *
116 * Returns void
117 *
118 ******************************************************************************/
avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr,uint16_t lcid,UNUSED_ATTR uint16_t psm,uint8_t id)119 void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
120 UNUSED_ATTR uint16_t psm, uint8_t id) {
121 tAVCT_LCB* p_lcb;
122 uint16_t result = L2CAP_CONN_NO_RESOURCES;
123 tL2CAP_CFG_INFO cfg;
124 tAVCT_BCB* p_bcb;
125 tL2CAP_ERTM_INFO ertm_info;
126
127 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
128 cfg.mtu_present = true;
129
130 p_lcb = avct_lcb_by_bd(bd_addr);
131 if (p_lcb != NULL) {
132 /* control channel exists */
133 p_bcb = avct_bcb_by_lcb(p_lcb);
134 memcpy(p_bcb->peer_addr, bd_addr, BD_ADDR_LEN);
135
136 if (p_bcb->allocated == 0) {
137 /* browsing channel does not exist yet and the browsing channel is
138 * registered
139 * - accept connection */
140 p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */
141
142 result = L2CAP_CONN_OK;
143 cfg.mtu = avct_cb.mtu_br;
144
145 cfg.fcr_present = true;
146 cfg.fcr = avct_l2c_br_fcr_opts_def;
147 }
148 }
149 /* else no control channel yet, reject */
150
151 /* Set the FCR options: Browsing channel mandates ERTM */
152 ertm_info.preferred_mode = cfg.fcr.mode;
153 ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
154 ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
155 ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
156 ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
157 ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
158
159 /* Send L2CAP connect rsp */
160 L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, 0, &ertm_info);
161
162 /* if result ok, proceed with connection */
163 if (result == L2CAP_CONN_OK) {
164 /* store LCID */
165 p_bcb->ch_lcid = lcid;
166
167 /* transition to configuration state */
168 p_bcb->ch_state = AVCT_CH_CFG;
169
170 /* Send L2CAP config req */
171 L2CA_ConfigReq(lcid, &cfg);
172 }
173 }
174
175 /*******************************************************************************
176 *
177 * Function avct_l2c_br_connect_cfm_cback
178 *
179 * Description This is the L2CAP connect confirm callback function.
180 *
181 *
182 * Returns void
183 *
184 ******************************************************************************/
avct_l2c_br_connect_cfm_cback(uint16_t lcid,uint16_t result)185 void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result) {
186 tAVCT_BCB* p_lcb;
187 tL2CAP_CFG_INFO cfg;
188
189 /* look up lcb for this channel */
190 p_lcb = avct_bcb_by_lcid(lcid);
191 if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CONN)) return;
192
193 if (result != L2CAP_CONN_OK) {
194 /* failure */
195 avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
196 return;
197 }
198
199 /* result is successful */
200 /* set channel state */
201 p_lcb->ch_state = AVCT_CH_CFG;
202
203 /* Send L2CAP config req */
204 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
205
206 cfg.mtu_present = true;
207 cfg.mtu = avct_cb.mtu_br;
208
209 cfg.fcr_present = true;
210 cfg.fcr = avct_l2c_br_fcr_opts_def;
211
212 L2CA_ConfigReq(lcid, &cfg);
213 }
214
215 /*******************************************************************************
216 *
217 * Function avct_l2c_br_config_cfm_cback
218 *
219 * Description This is the L2CAP config confirm callback function.
220 *
221 *
222 * Returns void
223 *
224 ******************************************************************************/
avct_l2c_br_config_cfm_cback(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)225 void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
226 tAVCT_BCB* p_lcb;
227
228 /* look up lcb for this channel */
229 p_lcb = avct_bcb_by_lcid(lcid);
230 if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CFG)) return;
231
232 /* if result successful */
233 if (p_cfg->result == L2CAP_CFG_OK) {
234 /* update flags */
235 p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
236
237 /* if configuration complete */
238 if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
239 p_lcb->ch_state = AVCT_CH_OPEN;
240 avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
241 }
242 }
243 /* else failure */
244 else {
245 /* store result value */
246 p_lcb->ch_result = p_cfg->result;
247
248 /* Send L2CAP disconnect req */
249 L2CA_DisconnectReq(lcid);
250 }
251 }
252
253 /*******************************************************************************
254 *
255 * Function avct_l2c_br_config_ind_cback
256 *
257 * Description This is the L2CAP config indication callback function.
258 *
259 *
260 * Returns void
261 *
262 ******************************************************************************/
avct_l2c_br_config_ind_cback(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)263 void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
264 tAVCT_BCB* p_lcb;
265 uint16_t max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE;
266
267 /* Don't include QoS nor flush timeout in the response since we
268 currently always accept these values. Note: fcr_present is left
269 untouched since l2cap negotiates this internally
270 */
271 p_cfg->flush_to_present = false;
272 p_cfg->qos_present = false;
273
274 /* look up lcb for this channel */
275 p_lcb = avct_bcb_by_lcid(lcid);
276 if (p_lcb == NULL) return;
277
278 /* store the mtu in tbl */
279 p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
280 if (p_cfg->mtu_present) {
281 p_lcb->peer_mtu = p_cfg->mtu;
282 }
283
284 if (p_lcb->peer_mtu > max_mtu) {
285 p_lcb->peer_mtu = p_cfg->mtu = max_mtu;
286
287 /* Must tell the peer what the adjusted value is */
288 p_cfg->mtu_present = true;
289 } else /* Don't include in the response */
290 p_cfg->mtu_present = false;
291
292 AVCT_TRACE_DEBUG("%s peer_mtu:%d use:%d", __func__, p_lcb->peer_mtu, max_mtu);
293
294 if (p_lcb->peer_mtu >= AVCT_MIN_BROWSE_MTU)
295 p_cfg->result = L2CAP_CFG_OK;
296 else {
297 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
298 p_cfg->mtu_present = true;
299 p_cfg->mtu = AVCT_MIN_BROWSE_MTU;
300 }
301
302 /* send L2CAP configure response */
303 L2CA_ConfigRsp(lcid, p_cfg);
304
305 if (p_cfg->result != L2CAP_CFG_OK) {
306 return;
307 }
308
309 /* if first config ind */
310 if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
311 /* update flags */
312 p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
313
314 /* if configuration complete */
315 if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
316 p_lcb->ch_state = AVCT_CH_OPEN;
317 avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
318 }
319 }
320 }
321
322 /*******************************************************************************
323 *
324 * Function avct_l2c_br_disconnect_ind_cback
325 *
326 * Description This is the L2CAP disconnect indication callback function.
327 *
328 *
329 * Returns void
330 *
331 ******************************************************************************/
avct_l2c_br_disconnect_ind_cback(uint16_t lcid,bool ack_needed)332 void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
333 tAVCT_BCB* p_lcb;
334 uint16_t result = AVCT_RESULT_FAIL;
335
336 /* look up lcb for this channel */
337 p_lcb = avct_bcb_by_lcid(lcid);
338 if (p_lcb == NULL) return;
339
340 if (ack_needed) {
341 /* send L2CAP disconnect response */
342 L2CA_DisconnectRsp(lcid);
343 }
344
345 avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
346 }
347
348 /*******************************************************************************
349 *
350 * Function avct_l2c_br_disconnect_cfm_cback
351 *
352 * Description This is the L2CAP disconnect confirm callback function.
353 *
354 *
355 * Returns void
356 *
357 ******************************************************************************/
avct_l2c_br_disconnect_cfm_cback(uint16_t lcid,uint16_t result)358 void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
359 tAVCT_BCB* p_lcb;
360 uint16_t res;
361
362 /* look up lcb for this channel */
363 p_lcb = avct_bcb_by_lcid(lcid);
364 if (p_lcb == NULL) return;
365
366 /* result value may be previously stored */
367 res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
368 p_lcb->ch_result = 0;
369
370 avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&res);
371 }
372
373 /*******************************************************************************
374 *
375 * Function avct_l2c_br_congestion_ind_cback
376 *
377 * Description This is the L2CAP congestion indication callback function.
378 *
379 *
380 * Returns void
381 *
382 ******************************************************************************/
avct_l2c_br_congestion_ind_cback(uint16_t lcid,bool is_congested)383 void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested) {
384 tAVCT_BCB* p_lcb;
385
386 /* look up lcb for this channel */
387 p_lcb = avct_bcb_by_lcid(lcid);
388 if (p_lcb == NULL) return;
389
390 avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT*)&is_congested);
391 }
392
393 /*******************************************************************************
394 *
395 * Function avct_l2c_br_data_ind_cback
396 *
397 * Description This is the L2CAP data indication callback function.
398 *
399 *
400 * Returns void
401 *
402 ******************************************************************************/
avct_l2c_br_data_ind_cback(uint16_t lcid,BT_HDR * p_buf)403 void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
404 tAVCT_BCB* p_lcb;
405 tAVCT_LCB_EVT evt_data;
406
407 /* look up lcb for this channel */
408 p_lcb = avct_bcb_by_lcid(lcid);
409 if (p_lcb == NULL) {
410 /* prevent buffer leak */
411 osi_free(p_buf);
412 return;
413 }
414
415 evt_data.p_buf = p_buf;
416 avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, &evt_data);
417 }
418