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