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 "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 */ 39 void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); 40 void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result); 41 void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); 42 void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); 43 void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed); 44 void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result); 45 void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested); 46 void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf); 47 48 /* L2CAP callback function structure */ 49 const 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 *******************************************************************************/ 73 static 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 *******************************************************************************/ 104 void 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 *******************************************************************************/ 178 void 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 *******************************************************************************/ 239 void 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 *******************************************************************************/ 289 void 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 *******************************************************************************/ 339 void 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 *******************************************************************************/ 369 void 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 *******************************************************************************/ 398 void 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 *******************************************************************************/ 420 void 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