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