avct_l2c.cc revision 911d1ae03efec2d54c3b1b605589d790d1745488
176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/****************************************************************************** 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2003-2012 Broadcom Corporation 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Licensed under the Apache License, Version 2.0 (the "License"); 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * you may not use this file except in compliance with the License. 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You may obtain a copy of the License at: 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * http://www.apache.org/licenses/LICENSE-2.0 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Unless required by applicable law or agreed to in writing, software 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * distributed under the License is distributed on an "AS IS" BASIS, 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * See the License for the specific language governing permissions and 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * limitations under the License. 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ******************************************************************************/ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/****************************************************************************** 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This AVCTP module interfaces to L2CAP 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ******************************************************************************/ 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "avct_api.h" 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "avct_int.h" 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bt_target.h" 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bt_types.h" 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bt_utils.h" 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "l2c_api.h" 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "l2cdefs.h" 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "osi/include/osi.h" 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Configuration flags. */ 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define AVCT_L2C_CFG_IND_DONE (1 << 0) 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define AVCT_L2C_CFG_CFM_DONE (1 << 1) 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* callback function declarations */ 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t id); 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result); 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed); 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result); 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested); 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf); 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* L2CAP callback function structure */ 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst tL2CAP_APPL_INFO avct_l2c_appl = { 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_connect_ind_cback, 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_connect_cfm_cback, 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL, 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_config_ind_cback, 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_config_cfm_cback, 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_disconnect_ind_cback, 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_disconnect_cfm_cback, 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL, 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_data_ind_cback, 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman avct_l2c_congestion_ind_cback, 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL /* tL2CA_TX_COMPLETE_CB */ 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/******************************************************************************* 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Function avct_l2c_is_passive 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description check is the CCB associated with the given LCB was created 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * as passive 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns true, if the given LCB is created as AVCT_PASSIVE 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ******************************************************************************/ 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) { 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bool is_passive = false; 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control); 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (p_ccb->cc.control & AVCT_PASSIVE) { 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman is_passive = true; 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return is_passive; 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 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(BD_ADDR 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 avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result); 201 } 202 } else if (p_lcb->conflict_lcid == lcid) { 203 /* we must be in AVCT_CH_CFG state for the ch_lcid channel */ 204 AVCT_TRACE_DEBUG( 205 "avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", 206 p_lcb->ch_state, p_lcb->conflict_lcid); 207 if (result == L2CAP_CONN_OK) { 208 /* just in case the peer also accepts our connection - Send L2CAP 209 * disconnect req */ 210 L2CA_DisconnectReq(lcid); 211 } 212 p_lcb->conflict_lcid = 0; 213 } 214 AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state); 215 } 216} 217 218/******************************************************************************* 219 * 220 * Function avct_l2c_config_cfm_cback 221 * 222 * Description This is the L2CAP config confirm callback function. 223 * 224 * 225 * Returns void 226 * 227 ******************************************************************************/ 228void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { 229 tAVCT_LCB* p_lcb; 230 231 /* look up lcb for this channel */ 232 p_lcb = avct_lcb_by_lcid(lcid); 233 if (p_lcb != NULL) { 234 AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d", 235 lcid, p_lcb->ch_state, p_cfg->result); 236 /* if in correct state */ 237 if (p_lcb->ch_state == AVCT_CH_CFG) { 238 /* if result successful */ 239 if (p_cfg->result == L2CAP_CFG_OK) { 240 /* update flags */ 241 p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE; 242 243 /* if configuration complete */ 244 if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) { 245 p_lcb->ch_state = AVCT_CH_OPEN; 246 avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); 247 } 248 } 249 /* else failure */ 250 else { 251 AVCT_TRACE_DEBUG( 252 "ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", 253 p_lcb->ch_state); 254 /* store result value */ 255 p_lcb->ch_result = p_cfg->result; 256 257 /* Send L2CAP disconnect req */ 258 L2CA_DisconnectReq(lcid); 259 } 260 } 261 AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state); 262 } 263} 264 265/******************************************************************************* 266 * 267 * Function avct_l2c_config_ind_cback 268 * 269 * Description This is the L2CAP config indication callback function. 270 * 271 * 272 * Returns void 273 * 274 ******************************************************************************/ 275void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { 276 tAVCT_LCB* p_lcb; 277 278 /* look up lcb for this channel */ 279 p_lcb = avct_lcb_by_lcid(lcid); 280 if (p_lcb != NULL) { 281 AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, 282 p_lcb->ch_state); 283 /* store the mtu in tbl */ 284 if (p_cfg->mtu_present) { 285 p_lcb->peer_mtu = p_cfg->mtu; 286 } else { 287 p_lcb->peer_mtu = L2CAP_DEFAULT_MTU; 288 } 289 290 /* send L2CAP configure response */ 291 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO)); 292 p_cfg->result = L2CAP_CFG_OK; 293 L2CA_ConfigRsp(lcid, p_cfg); 294 295 /* if first config ind */ 296 if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) { 297 /* update flags */ 298 p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE; 299 300 /* if configuration complete */ 301 if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) { 302 p_lcb->ch_state = AVCT_CH_OPEN; 303 avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); 304 } 305 } 306 AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state); 307 } 308} 309 310/******************************************************************************* 311 * 312 * Function avct_l2c_disconnect_ind_cback 313 * 314 * Description This is the L2CAP disconnect indication callback function. 315 * 316 * 317 * Returns void 318 * 319 ******************************************************************************/ 320void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) { 321 tAVCT_LCB* p_lcb; 322 uint16_t result = AVCT_RESULT_FAIL; 323 324 /* look up lcb for this channel */ 325 p_lcb = avct_lcb_by_lcid(lcid); 326 if (p_lcb != NULL) { 327 AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, 328 p_lcb->ch_state); 329 if (ack_needed) { 330 /* send L2CAP disconnect response */ 331 L2CA_DisconnectRsp(lcid); 332 } 333 334 avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result); 335 AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state); 336 } 337} 338 339/******************************************************************************* 340 * 341 * Function avct_l2c_disconnect_cfm_cback 342 * 343 * Description This is the L2CAP disconnect confirm callback function. 344 * 345 * 346 * Returns void 347 * 348 ******************************************************************************/ 349void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) { 350 tAVCT_LCB* p_lcb; 351 uint16_t res; 352 353 /* look up lcb for this channel */ 354 p_lcb = avct_lcb_by_lcid(lcid); 355 if (p_lcb != NULL) { 356 AVCT_TRACE_DEBUG( 357 "avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", lcid, 358 p_lcb->ch_state, result); 359 /* result value may be previously stored */ 360 res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result; 361 p_lcb->ch_result = 0; 362 363 avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&res); 364 AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state); 365 } 366} 367 368/******************************************************************************* 369 * 370 * Function avct_l2c_congestion_ind_cback 371 * 372 * Description This is the L2CAP congestion indication callback function. 373 * 374 * 375 * Returns void 376 * 377 ******************************************************************************/ 378void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) { 379 tAVCT_LCB* p_lcb; 380 381 AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid); 382 /* look up lcb for this channel */ 383 p_lcb = avct_lcb_by_lcid(lcid); 384 if (p_lcb != NULL) { 385 avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT*)&is_congested); 386 } 387} 388 389/******************************************************************************* 390 * 391 * Function avct_l2c_data_ind_cback 392 * 393 * Description This is the L2CAP data indication callback function. 394 * 395 * 396 * Returns void 397 * 398 ******************************************************************************/ 399void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) { 400 tAVCT_LCB* p_lcb; 401 402 AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid); 403 /* look up lcb for this channel */ 404 p_lcb = avct_lcb_by_lcid(lcid); 405 if (p_lcb != NULL) { 406 avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf); 407 } else /* prevent buffer leak */ 408 { 409 AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer"); 410 osi_free(p_buf); 411 } 412} 413