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