1 /******************************************************************************
2 *
3 * Copyright 2003-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 AVCTP module interfaces to L2CAP
22 *
23 ******************************************************************************/
24 #define LOG_TAG "avctp"
25
26 #include <bluetooth/log.h>
27
28 #include "avct_api.h"
29 #include "avct_int.h"
30 #include "btif/include/btif_av.h"
31 #include "internal_include/bt_target.h"
32 #include "l2c_api.h"
33 #include "l2cdefs.h"
34 #include "osi/include/allocator.h"
35 #include "osi/include/osi.h"
36 #include "stack/include/bt_hdr.h"
37 #include "types/raw_address.h"
38
39 using namespace bluetooth;
40
41 /* callback function declarations */
42 void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
43 uint16_t psm, uint8_t id);
44 void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
45 void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t result,
46 tL2CAP_CFG_INFO* p_cfg);
47 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
48 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
49 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
50 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
51 static void avct_on_l2cap_error(uint16_t lcid, uint16_t result);
52
53 /* L2CAP callback function structure */
54 const tL2CAP_APPL_INFO avct_l2c_appl = {
55 avct_l2c_connect_ind_cback,
56 avct_l2c_connect_cfm_cback,
57 avct_l2c_config_ind_cback,
58 avct_l2c_config_cfm_cback,
59 avct_l2c_disconnect_ind_cback,
60 NULL,
61 avct_l2c_data_ind_cback,
62 avct_l2c_congestion_ind_cback,
63 NULL,
64 avct_on_l2cap_error,
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 };
70
71 /*******************************************************************************
72 *
73 * Function avct_l2c_is_passive
74 *
75 * Description check is the CCB associated with the given LCB was created
76 * as passive
77 *
78 * Returns true, if the given LCB is created as AVCT_PASSIVE
79 *
80 ******************************************************************************/
avct_l2c_is_passive(tAVCT_LCB * p_lcb)81 static bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) {
82 bool is_passive = false;
83 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
84 int i;
85
86 for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
87 if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
88 log::verbose("avct_l2c_is_ct control:x{:x}", p_ccb->cc.control);
89 if (p_ccb->cc.control & AVCT_PASSIVE) {
90 is_passive = true;
91 break;
92 }
93 }
94 }
95 return is_passive;
96 }
97
98 /*******************************************************************************
99 *
100 * Function avct_l2c_connect_ind_cback
101 *
102 * Description This is the L2CAP connect indication callback function.
103 *
104 *
105 * Returns void
106 *
107 ******************************************************************************/
avct_l2c_connect_ind_cback(const RawAddress & bd_addr,uint16_t lcid,uint16_t,uint8_t id)108 void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
109 uint16_t /* psm */, uint8_t id) {
110 tAVCT_LCB* p_lcb;
111 uint16_t result = L2CAP_CONN_OK;
112
113 /* do we already have a channel for this peer? */
114 p_lcb = avct_lcb_by_bd(bd_addr);
115 if (p_lcb == NULL) {
116 /* no, allocate lcb */
117 p_lcb = avct_lcb_alloc(bd_addr);
118 if (p_lcb == NULL) {
119 /* no ccb available, reject L2CAP connection */
120 result = L2CAP_CONN_NO_RESOURCES;
121 }
122 }
123 /* else we already have a channel for this peer */
124 else {
125 if (!avct_l2c_is_passive(p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) {
126 /* this LCB included CT role - reject */
127 result = L2CAP_CONN_NO_RESOURCES;
128 } else {
129 /* TG role only - accept the connection from CT. move the channel ID to
130 * the conflict list */
131 p_lcb->conflict_lcid = p_lcb->ch_lcid;
132 log::verbose("avct_l2c_connect_ind_cback conflict_lcid:0x{:x}",
133 p_lcb->conflict_lcid);
134 }
135 }
136
137 if (p_lcb) {
138 log::verbose("avct_l2c_connect_ind_cback: 0x{:x}, res: {}, ch_state: {}",
139 lcid, result, p_lcb->ch_state);
140 }
141
142 /* If we reject the connection, send DisconnectReq */
143 if (result != L2CAP_CONN_OK) {
144 if (!L2CA_DisconnectReq(lcid)) {
145 log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}",
146 bd_addr, lcid);
147 }
148 }
149
150 /* if result ok, proceed with connection */
151 if (result == L2CAP_CONN_OK) {
152 if (btif_av_src_sink_coexist_enabled()) {
153 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
154 for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
155 if (p_ccb && p_ccb->allocated && (p_ccb->p_lcb == NULL) &&
156 (p_ccb->cc.role == AVCT_ACP)) {
157 p_ccb->p_lcb = p_lcb;
158 log::verbose(
159 "ACP bind {} ccb to lcb, alloc {}, lcb {}, role {}, pid 0x{:x}",
160 i, p_ccb->allocated, fmt::ptr(p_ccb->p_lcb), p_ccb->cc.role,
161 p_ccb->cc.pid);
162 }
163 }
164 }
165 /* store LCID */
166 p_lcb->ch_lcid = lcid;
167
168 /* transition to configuration state */
169 p_lcb->ch_state = AVCT_CH_CFG;
170 }
171
172 if (p_lcb) log::verbose("ch_state cni: {}", p_lcb->ch_state);
173 }
174
avct_on_l2cap_error(uint16_t lcid,uint16_t result)175 static void avct_on_l2cap_error(uint16_t lcid, uint16_t result) {
176 tAVCT_LCB* p_lcb = avct_lcb_by_lcid(lcid);
177 if (p_lcb == nullptr) return;
178 if (p_lcb->ch_state == AVCT_CH_CONN) {
179 log::verbose("avct_l2c_connect_cfm_cback conflict_lcid:0x{:x}",
180 p_lcb->conflict_lcid);
181 if (p_lcb->conflict_lcid == lcid) {
182 p_lcb->conflict_lcid = 0;
183 } else {
184 tAVCT_LCB_EVT avct_lcb_evt;
185 avct_lcb_evt.result = result;
186 avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
187 }
188 } else if (p_lcb->ch_state == AVCT_CH_CFG) {
189 log::verbose("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq {}",
190 p_lcb->ch_state);
191 /* store result value */
192 p_lcb->ch_result = result;
193
194 /* Send L2CAP disconnect req */
195 if (!L2CA_DisconnectReq(lcid)) {
196 log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}",
197 p_lcb->peer_addr, lcid);
198 }
199 }
200 }
201
202 /*******************************************************************************
203 *
204 * Function avct_l2c_connect_cfm_cback
205 *
206 * Description This is the L2CAP connect confirm callback function.
207 *
208 *
209 * Returns void
210 *
211 ******************************************************************************/
avct_l2c_connect_cfm_cback(uint16_t lcid,uint16_t result)212 void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
213 tAVCT_LCB* p_lcb;
214
215 /* look up lcb for this channel */
216 p_lcb = avct_lcb_by_lcid(lcid);
217 if (p_lcb != NULL) {
218 log::verbose(
219 "avct_l2c_connect_cfm_cback lcid:0x{:x} result: {} ch_state: {}, "
220 "conflict_lcid:0x{:x}",
221 lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
222 /* if in correct state */
223 if (p_lcb->ch_state == AVCT_CH_CONN) {
224 /* if result successful */
225 if (result == L2CAP_CONN_OK) {
226 /* set channel state */
227 p_lcb->ch_state = AVCT_CH_CFG;
228 }
229 /* else failure */
230 else {
231 log::error("invoked with non OK status");
232 }
233 } else if (p_lcb->conflict_lcid == lcid) {
234 /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
235 log::verbose(
236 "avct_l2c_connect_cfm_cback ch_state: {}, conflict_lcid:0x{:x}",
237 p_lcb->ch_state, p_lcb->conflict_lcid);
238 if (result == L2CAP_CONN_OK) {
239 /* just in case the peer also accepts our connection - Send L2CAP
240 * disconnect req */
241 if (!L2CA_DisconnectReq(lcid)) {
242 log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}",
243 p_lcb->peer_addr, lcid);
244 }
245 }
246 p_lcb->conflict_lcid = 0;
247 }
248 log::verbose("ch_state cnc: {}", p_lcb->ch_state);
249 }
250 }
251
252 /*******************************************************************************
253 *
254 * Function avct_l2c_config_cfm_cback
255 *
256 * Description This is the L2CAP config confirm callback function.
257 *
258 *
259 * Returns void
260 *
261 ******************************************************************************/
avct_l2c_config_cfm_cback(uint16_t lcid,uint16_t initiator,tL2CAP_CFG_INFO * p_cfg)262 void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t initiator,
263 tL2CAP_CFG_INFO* p_cfg) {
264 avct_l2c_config_ind_cback(lcid, p_cfg);
265
266 tAVCT_LCB* p_lcb;
267
268 /* look up lcb for this channel */
269 p_lcb = avct_lcb_by_lcid(lcid);
270 if (p_lcb != NULL) {
271 log::verbose("avct_l2c_config_cfm_cback: 0x{:x}, ch_state: {},", lcid,
272 p_lcb->ch_state);
273 /* if in correct state */
274 if (p_lcb->ch_state == AVCT_CH_CFG) {
275 p_lcb->ch_state = AVCT_CH_OPEN;
276 avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
277 }
278 log::verbose("ch_state cfc: {}", p_lcb->ch_state);
279 }
280 }
281
282 /*******************************************************************************
283 *
284 * Function avct_l2c_config_ind_cback
285 *
286 * Description This is the L2CAP config indication callback function.
287 *
288 *
289 * Returns void
290 *
291 ******************************************************************************/
avct_l2c_config_ind_cback(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)292 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
293 tAVCT_LCB* p_lcb;
294
295 /* look up lcb for this channel */
296 p_lcb = avct_lcb_by_lcid(lcid);
297 if (p_lcb != NULL) {
298 log::verbose("avct_l2c_config_ind_cback: 0x{:x}, ch_state: {}", lcid,
299 p_lcb->ch_state);
300 /* store the mtu in tbl */
301 if (p_cfg->mtu_present) {
302 p_lcb->peer_mtu = p_cfg->mtu;
303 } else {
304 p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
305 }
306 }
307 }
308
309 /*******************************************************************************
310 *
311 * Function avct_l2c_disconnect_ind_cback
312 *
313 * Description This is the L2CAP disconnect indication callback function.
314 *
315 *
316 * Returns void
317 *
318 ******************************************************************************/
avct_l2c_disconnect_ind_cback(uint16_t lcid,bool ack_needed)319 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
320 tAVCT_LCB* p_lcb;
321 uint16_t result = AVCT_RESULT_FAIL;
322
323 /* look up lcb for this channel */
324 p_lcb = avct_lcb_by_lcid(lcid);
325 if (p_lcb != NULL) {
326 log::verbose("avct_l2c_disconnect_ind_cback: 0x{:x}, ch_state: {}", lcid,
327 p_lcb->ch_state);
328 tAVCT_LCB_EVT avct_lcb_evt;
329 avct_lcb_evt.result = result;
330 avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
331 log::verbose("ch_state di: {}", p_lcb->ch_state);
332 }
333 }
334
avct_l2c_disconnect(uint16_t lcid,uint16_t result)335 void avct_l2c_disconnect(uint16_t lcid, uint16_t result) {
336 if (!L2CA_DisconnectReq(lcid)) {
337 log::warn("Unable to send L2CAP disconnect request cid:{}", lcid);
338 }
339
340 tAVCT_LCB* p_lcb;
341 uint16_t res;
342
343 /* look up lcb for this channel */
344 p_lcb = avct_lcb_by_lcid(lcid);
345 if (p_lcb != NULL) {
346 log::verbose("avct_l2c_disconnect_cfm_cback: 0x{:x}, ch_state: {}, res: {}",
347 lcid, p_lcb->ch_state, result);
348 /* result value may be previously stored */
349 res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
350 p_lcb->ch_result = 0;
351
352 tAVCT_LCB_EVT avct_lcb_evt;
353 avct_lcb_evt.result = res;
354 avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
355 log::verbose("ch_state dc: {}", p_lcb->ch_state);
356 }
357 }
358
359 /*******************************************************************************
360 *
361 * Function avct_l2c_congestion_ind_cback
362 *
363 * Description This is the L2CAP congestion indication callback function.
364 *
365 *
366 * Returns void
367 *
368 ******************************************************************************/
avct_l2c_congestion_ind_cback(uint16_t lcid,bool is_congested)369 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
370 tAVCT_LCB* p_lcb;
371
372 log::verbose("avct_l2c_congestion_ind_cback: 0x{:x}", lcid);
373 /* look up lcb for this channel */
374 p_lcb = avct_lcb_by_lcid(lcid);
375 if (p_lcb != NULL) {
376 tAVCT_LCB_EVT avct_lcb_evt;
377 avct_lcb_evt.cong = is_congested;
378 avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, &avct_lcb_evt);
379 }
380 }
381
382 /*******************************************************************************
383 *
384 * Function avct_l2c_data_ind_cback
385 *
386 * Description This is the L2CAP data indication callback function.
387 *
388 *
389 * Returns void
390 *
391 ******************************************************************************/
avct_l2c_data_ind_cback(uint16_t lcid,BT_HDR * p_buf)392 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
393 tAVCT_LCB* p_lcb;
394
395 log::verbose("avct_l2c_data_ind_cback: 0x{:x}", lcid);
396 /* look up lcb for this channel */
397 p_lcb = avct_lcb_by_lcid(lcid);
398 if (p_lcb != NULL) {
399 avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf);
400 } else /* prevent buffer leak */
401 {
402 log::warn("ERROR -> avct_l2c_data_ind_cback drop buffer");
403 osi_free(p_buf);
404 }
405 }
406