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 */ 38 void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); 39 void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result); 40 void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); 41 void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); 42 void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed); 43 void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result); 44 void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested); 45 void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf); 46 47 /* L2CAP callback function structure */ 48 const 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 *******************************************************************************/ 72 static 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 *******************************************************************************/ 103 void 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 *******************************************************************************/ 176 void 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 *******************************************************************************/ 237 void 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 *******************************************************************************/ 287 void 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 *******************************************************************************/ 337 void 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 *******************************************************************************/ 367 void 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 *******************************************************************************/ 396 void 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 *******************************************************************************/ 418 void 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