1 /****************************************************************************** 2 * 3 * Copyright (C) 1999-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 file contains L2CAP interface functions 22 * 23 ******************************************************************************/ 24 25 #include <stddef.h> 26 #include "bt_target.h" 27 28 #include "bt_common.h" 29 #include "osi/include/osi.h" 30 #include "osi/include/time.h" 31 32 #include "bt_utils.h" 33 #include "l2c_api.h" 34 #include "l2cdefs.h" 35 #include "port_api.h" 36 #include "port_int.h" 37 #include "rfc_int.h" 38 #include "rfcdefs.h" 39 40 /* 41 * Define Callback functions to be called by L2CAP 42 */ 43 static void RFCOMM_ConnectInd(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, 44 uint8_t id); 45 static void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t err); 46 static void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); 47 static void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); 48 static void RFCOMM_DisconnectInd(uint16_t lcid, bool is_clear); 49 static void RFCOMM_QoSViolationInd(UNUSED_ATTR BD_ADDR bd_addr); 50 static void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf); 51 static void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested); 52 53 /******************************************************************************* 54 * 55 * Function rfcomm_l2cap_if_init 56 * 57 * Description This function is called during the RFCOMM task startup 58 * to register interface functions with L2CAP. 59 * 60 ******************************************************************************/ 61 void rfcomm_l2cap_if_init(void) { 62 tL2CAP_APPL_INFO* p_l2c = &rfc_cb.rfc.reg_info; 63 64 p_l2c->pL2CA_ConnectInd_Cb = RFCOMM_ConnectInd; 65 p_l2c->pL2CA_ConnectCfm_Cb = RFCOMM_ConnectCnf; 66 p_l2c->pL2CA_ConnectPnd_Cb = NULL; 67 p_l2c->pL2CA_ConfigInd_Cb = RFCOMM_ConfigInd; 68 p_l2c->pL2CA_ConfigCfm_Cb = RFCOMM_ConfigCnf; 69 p_l2c->pL2CA_DisconnectInd_Cb = RFCOMM_DisconnectInd; 70 p_l2c->pL2CA_DisconnectCfm_Cb = NULL; 71 p_l2c->pL2CA_QoSViolationInd_Cb = RFCOMM_QoSViolationInd; 72 p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd; 73 p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd; 74 p_l2c->pL2CA_TxComplete_Cb = NULL; 75 76 L2CA_Register(BT_PSM_RFCOMM, p_l2c); 77 } 78 79 /******************************************************************************* 80 * 81 * Function RFCOMM_ConnectInd 82 * 83 * Description This is a callback function called by L2CAP when 84 * L2CA_ConnectInd received. Allocate multiplexer control 85 * block and dispatch the event to it. 86 * 87 ******************************************************************************/ 88 void RFCOMM_ConnectInd(BD_ADDR bd_addr, uint16_t lcid, UNUSED_ATTR uint16_t psm, 89 uint8_t id) { 90 tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(bd_addr, false); 91 92 if ((p_mcb) && (p_mcb->state != RFC_MX_STATE_IDLE)) { 93 /* if this is collision case */ 94 if ((p_mcb->is_initiator) && (p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) { 95 p_mcb->pending_lcid = lcid; 96 p_mcb->pending_id = id; 97 98 /* wait random timeout (2 - 12) to resolve collision */ 99 /* if peer gives up then local device rejects incoming connection and 100 * continues as initiator */ 101 /* if timeout, local device disconnects outgoing connection and continues 102 * as acceptor */ 103 RFCOMM_TRACE_DEBUG( 104 "RFCOMM_ConnectInd start timer for collision, initiator's " 105 "LCID(0x%x), acceptor's LCID(0x%x)", 106 p_mcb->lcid, p_mcb->pending_lcid); 107 108 rfc_timer_start(p_mcb, (uint16_t)(time_get_os_boottime_ms() % 10 + 2)); 109 return; 110 } else { 111 /* we cannot accept connection request from peer at this state */ 112 /* don't update lcid */ 113 p_mcb = NULL; 114 } 115 } else { 116 /* store mcb even if null */ 117 rfc_save_lcid_mcb(p_mcb, lcid); 118 } 119 120 if (p_mcb == NULL) { 121 L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0); 122 return; 123 } 124 p_mcb->lcid = lcid; 125 126 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &id); 127 } 128 129 /******************************************************************************* 130 * 131 * Function RFCOMM_ConnectCnf 132 * 133 * Description This is a callback function called by L2CAP when 134 * L2CA_ConnectCnf received. Save L2CAP handle and dispatch 135 * event to the FSM. 136 * 137 ******************************************************************************/ 138 void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) { 139 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 140 141 if (!p_mcb) { 142 RFCOMM_TRACE_ERROR("RFCOMM_ConnectCnf LCID:0x%x", lcid); 143 return; 144 } 145 146 if (p_mcb->pending_lcid) { 147 /* if peer rejects our connect request but peer's connect request is pending 148 */ 149 if (result != L2CAP_CONN_OK) { 150 uint16_t i; 151 uint8_t idx; 152 153 RFCOMM_TRACE_DEBUG( 154 "RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", 155 p_mcb->pending_lcid); 156 157 /* remove mcb from mapping table */ 158 rfc_save_lcid_mcb(NULL, p_mcb->lcid); 159 160 p_mcb->lcid = p_mcb->pending_lcid; 161 p_mcb->is_initiator = false; 162 p_mcb->state = RFC_MX_STATE_IDLE; 163 164 /* store mcb into mapping table */ 165 rfc_save_lcid_mcb(p_mcb, p_mcb->lcid); 166 167 /* update direction bit */ 168 for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) { 169 idx = p_mcb->port_inx[i]; 170 if (idx != 0) { 171 p_mcb->port_inx[i] = 0; 172 p_mcb->port_inx[i + 1] = idx; 173 rfc_cb.port.port[idx - 1].dlci += 1; 174 RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i, 175 rfc_cb.port.port[idx - 1].dlci); 176 } 177 } 178 179 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id)); 180 return; 181 } else { 182 RFCOMM_TRACE_DEBUG("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", 183 p_mcb->pending_lcid); 184 185 /* Peer gave up his connection request, make sure cleaning up L2CAP 186 * channel */ 187 L2CA_ConnectRsp(p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, 188 L2CAP_CONN_NO_RESOURCES, 0); 189 190 p_mcb->pending_lcid = 0; 191 } 192 } 193 194 /* Save LCID to be used in all consecutive calls to L2CAP */ 195 p_mcb->lcid = lcid; 196 197 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_CNF, &result); 198 } 199 200 /******************************************************************************* 201 * 202 * Function RFCOMM_ConfigInd 203 * 204 * Description This is a callback function called by L2CAP when 205 * L2CA_ConfigInd received. Save parameters in the control 206 * block and dispatch event to the FSM. 207 * 208 ******************************************************************************/ 209 void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { 210 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 211 212 if (!p_mcb) { 213 RFCOMM_TRACE_ERROR("RFCOMM_ConfigInd LCID:0x%x", lcid); 214 return; 215 } 216 217 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_IND, (void*)p_cfg); 218 } 219 220 /******************************************************************************* 221 * 222 * Function RFCOMM_ConfigCnf 223 * 224 * Description This is a callback function called by L2CAP when 225 * L2CA_ConfigCnf received. Save L2CAP handle and dispatch 226 * event to the FSM. 227 * 228 ******************************************************************************/ 229 void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { 230 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 231 232 if (!p_mcb) { 233 RFCOMM_TRACE_ERROR("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid); 234 return; 235 } 236 237 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_CNF, (void*)p_cfg); 238 } 239 240 /******************************************************************************* 241 * 242 * Function RFCOMM_QoSViolationInd 243 * 244 * Description This is a callback function called by L2CAP when 245 * L2CA_QoSViolationIndInd received. Dispatch event to the 246 * FSM. 247 * 248 ******************************************************************************/ 249 void RFCOMM_QoSViolationInd(UNUSED_ATTR BD_ADDR bd_addr) {} 250 251 /******************************************************************************* 252 * 253 * Function RFCOMM_DisconnectInd 254 * 255 * Description This is a callback function called by L2CAP when 256 * L2CA_DisconnectInd received. Dispatch event to the FSM. 257 * 258 ******************************************************************************/ 259 void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) { 260 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 261 262 if (is_conf_needed) { 263 L2CA_DisconnectRsp(lcid); 264 } 265 266 if (!p_mcb) { 267 RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid); 268 return; 269 } 270 271 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, NULL); 272 } 273 274 /******************************************************************************* 275 * 276 * Function RFCOMM_BufDataInd 277 * 278 * Description This is a callback function called by L2CAP when 279 * data RFCOMM frame is received. Parse the frames, check 280 * the checksum and dispatch event to multiplexer or port 281 * state machine depending on the frame destination. 282 * 283 ******************************************************************************/ 284 void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) { 285 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 286 tPORT* p_port; 287 uint8_t event; 288 289 if (!p_mcb) { 290 RFCOMM_TRACE_WARNING("RFCOMM_BufDataInd LCID:0x%x", lcid); 291 osi_free(p_buf); 292 return; 293 } 294 295 event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf); 296 297 /* If the frame did not pass validation just ignore it */ 298 if (event == RFC_EVENT_BAD_FRAME) { 299 osi_free(p_buf); 300 return; 301 } 302 303 if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) { 304 /* Take special care of the Multiplexer Control Messages */ 305 if (event == RFC_EVENT_UIH) { 306 rfc_process_mx_message(p_mcb, p_buf); 307 return; 308 } 309 310 /* Other multiplexer events go to state machine */ 311 rfc_mx_sm_execute(p_mcb, event, NULL); 312 osi_free(p_buf); 313 return; 314 } 315 316 /* The frame was received on the data channel DLCI, verify that DLC exists */ 317 if (((p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci)) == 318 NULL) || 319 (!p_port->rfc.p_mcb)) { 320 /* If this is a SABME on the new port, check if any appl is waiting for it 321 */ 322 if (event != RFC_EVENT_SABME) { 323 if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) || 324 (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) 325 rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf); 326 osi_free(p_buf); 327 return; 328 } 329 330 p_port = port_find_dlci_port(rfc_cb.rfc.rx_frame.dlci); 331 if (p_port == NULL) { 332 rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true); 333 osi_free(p_buf); 334 return; 335 } 336 p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx; 337 p_port->rfc.p_mcb = p_mcb; 338 } 339 340 if (event == RFC_EVENT_UIH) { 341 if (p_buf->len > 0) 342 rfc_port_sm_execute(p_port, event, p_buf); 343 else 344 osi_free(p_buf); 345 346 if (rfc_cb.rfc.rx_frame.credit != 0) 347 rfc_inc_credit(p_port, rfc_cb.rfc.rx_frame.credit); 348 349 return; 350 } 351 rfc_port_sm_execute(p_port, event, NULL); 352 osi_free(p_buf); 353 } 354 355 /******************************************************************************* 356 * 357 * Function RFCOMM_CongestionStatusInd 358 * 359 * Description This is a callback function called by L2CAP when 360 * data RFCOMM L2CAP congestion status changes 361 * 362 ******************************************************************************/ 363 void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) { 364 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 365 366 if (!p_mcb) { 367 RFCOMM_TRACE_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid); 368 return; 369 } else { 370 RFCOMM_TRACE_EVENT("RFCOMM_CongestionStatusInd LCID:0x%x", lcid); 371 } 372 rfc_process_l2cap_congestion(p_mcb, is_congested); 373 } 374 375 /******************************************************************************* 376 * 377 * Function rfc_find_lcid_mcb 378 * 379 * Description This function returns MCB block supporting local cid 380 * 381 ******************************************************************************/ 382 tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid) { 383 tRFC_MCB* p_mcb; 384 385 if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) { 386 RFCOMM_TRACE_ERROR("rfc_find_lcid_mcb LCID:0x%x", lcid); 387 return (NULL); 388 } else { 389 p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]; 390 if (p_mcb != NULL) { 391 if (p_mcb->lcid != lcid) { 392 RFCOMM_TRACE_WARNING( 393 "rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid, 394 p_mcb->lcid); 395 return (NULL); 396 } 397 } 398 } 399 return (p_mcb); 400 } 401 402 /******************************************************************************* 403 * 404 * Function rfc_save_lcid_mcb 405 * 406 * Description This function returns MCB block supporting local cid 407 * 408 ******************************************************************************/ 409 void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) { 410 if (lcid < L2CAP_BASE_APPL_CID) return; 411 rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb; 412 } 413