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