1 /****************************************************************************** 2 * 3 * Copyright 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(const RawAddress& bd_addr, uint16_t lcid, 44 uint16_t psm, 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 const RawAddress& 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(const RawAddress& bd_addr, uint16_t lcid, 89 UNUSED_ATTR uint16_t psm, 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 RFCOMM_TRACE_DEBUG( 151 "RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", 152 p_mcb->pending_lcid); 153 154 /* remove mcb from mapping table */ 155 rfc_save_lcid_mcb(NULL, p_mcb->lcid); 156 157 p_mcb->lcid = p_mcb->pending_lcid; 158 p_mcb->is_initiator = false; 159 p_mcb->state = RFC_MX_STATE_IDLE; 160 161 /* store mcb into mapping table */ 162 rfc_save_lcid_mcb(p_mcb, p_mcb->lcid); 163 164 /* update direction bit */ 165 for (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) { 166 uint8_t idx = p_mcb->port_inx[i]; 167 if (idx != 0) { 168 p_mcb->port_inx[i] = 0; 169 p_mcb->port_inx[i + 1] = idx; 170 rfc_cb.port.port[idx - 1].dlci += 1; 171 RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", idx, i, 172 rfc_cb.port.port[idx - 1].dlci); 173 } 174 } 175 176 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id)); 177 return; 178 } else { 179 RFCOMM_TRACE_DEBUG("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", 180 p_mcb->pending_lcid); 181 182 /* Peer gave up his connection request, make sure cleaning up L2CAP 183 * channel */ 184 L2CA_ConnectRsp(p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, 185 L2CAP_CONN_NO_RESOURCES, 0); 186 187 p_mcb->pending_lcid = 0; 188 } 189 } 190 191 /* Save LCID to be used in all consecutive calls to L2CAP */ 192 p_mcb->lcid = lcid; 193 194 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_CNF, &result); 195 } 196 197 /******************************************************************************* 198 * 199 * Function RFCOMM_ConfigInd 200 * 201 * Description This is a callback function called by L2CAP when 202 * L2CA_ConfigInd received. Save parameters in the control 203 * block and dispatch event to the FSM. 204 * 205 ******************************************************************************/ 206 void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { 207 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 208 209 if (!p_mcb) { 210 RFCOMM_TRACE_ERROR("RFCOMM_ConfigInd LCID:0x%x", lcid); 211 return; 212 } 213 214 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_IND, (void*)p_cfg); 215 } 216 217 /******************************************************************************* 218 * 219 * Function RFCOMM_ConfigCnf 220 * 221 * Description This is a callback function called by L2CAP when 222 * L2CA_ConfigCnf received. Save L2CAP handle and dispatch 223 * event to the FSM. 224 * 225 ******************************************************************************/ 226 void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { 227 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 228 229 if (!p_mcb) { 230 RFCOMM_TRACE_ERROR("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid); 231 return; 232 } 233 234 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_CNF, (void*)p_cfg); 235 } 236 237 /******************************************************************************* 238 * 239 * Function RFCOMM_QoSViolationInd 240 * 241 * Description This is a callback function called by L2CAP when 242 * L2CA_QoSViolationIndInd received. Dispatch event to the 243 * FSM. 244 * 245 ******************************************************************************/ 246 void RFCOMM_QoSViolationInd(UNUSED_ATTR const RawAddress& bd_addr) {} 247 248 /******************************************************************************* 249 * 250 * Function RFCOMM_DisconnectInd 251 * 252 * Description This is a callback function called by L2CAP when 253 * L2CA_DisconnectInd received. Dispatch event to the FSM. 254 * 255 ******************************************************************************/ 256 void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) { 257 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 258 259 if (is_conf_needed) { 260 L2CA_DisconnectRsp(lcid); 261 } 262 263 if (!p_mcb) { 264 RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid); 265 return; 266 } 267 268 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr); 269 } 270 271 /******************************************************************************* 272 * 273 * Function RFCOMM_BufDataInd 274 * 275 * Description This is a callback function called by L2CAP when 276 * data RFCOMM frame is received. Parse the frames, check 277 * the checksum and dispatch event to multiplexer or port 278 * state machine depending on the frame destination. 279 * 280 ******************************************************************************/ 281 void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) { 282 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 283 284 if (!p_mcb) { 285 LOG(WARNING) << __func__ << ": Cannot find RFCOMM multiplexer for lcid " 286 << loghex(lcid); 287 osi_free(p_buf); 288 return; 289 } 290 291 uint8_t event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf); 292 293 /* If the frame did not pass validation just ignore it */ 294 if (event == RFC_EVENT_BAD_FRAME) { 295 LOG(WARNING) << __func__ << ": Bad RFCOMM frame from lcid=" << loghex(lcid) 296 << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb; 297 osi_free(p_buf); 298 return; 299 } 300 301 if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) { 302 RFCOMM_TRACE_DEBUG("%s: Handle multiplexer event %d, p_mcb=%p", __func__, 303 event, p_mcb); 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, nullptr); 312 osi_free(p_buf); 313 return; 314 } 315 316 /* The frame was received on the data channel DLCI, verify that DLC exists */ 317 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci); 318 if (p_port == nullptr || !p_port->rfc.p_mcb) { 319 /* If this is a SABME on new port, check if any app is waiting for it */ 320 if (event != RFC_EVENT_SABME) { 321 LOG(WARNING) << __func__ 322 << ": no for none-SABME event, lcid=" << loghex(lcid) 323 << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb; 324 if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) || 325 (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) { 326 LOG(ERROR) << __func__ 327 << ": Disconnecting RFCOMM, lcid=" << loghex(lcid) 328 << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb; 329 rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf); 330 } 331 osi_free(p_buf); 332 return; 333 } 334 335 p_port = port_find_dlci_port(rfc_cb.rfc.rx_frame.dlci); 336 if (p_port == nullptr) { 337 LOG(ERROR) << __func__ << ":Disconnecting RFCOMM, no port for dlci " 338 << +rfc_cb.rfc.rx_frame.dlci << ", lcid=" << loghex(lcid) 339 << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb; 340 rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true); 341 osi_free(p_buf); 342 return; 343 } 344 RFCOMM_TRACE_DEBUG("%s: port_inx[dlci=%d]:%d->%d, p_mcb=%p", __func__, 345 rfc_cb.rfc.rx_frame.dlci, 346 p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci], p_port->inx); 347 p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx; 348 p_port->rfc.p_mcb = p_mcb; 349 } 350 351 if (event == RFC_EVENT_UIH) { 352 RFCOMM_TRACE_DEBUG("%s: Handling UIH event, buf_len=%u, credit=%u", 353 __func__, p_buf->len, rfc_cb.rfc.rx_frame.credit); 354 if (p_buf->len > 0) { 355 rfc_port_sm_execute(p_port, event, p_buf); 356 } else { 357 osi_free(p_buf); 358 } 359 360 if (rfc_cb.rfc.rx_frame.credit != 0) { 361 rfc_inc_credit(p_port, rfc_cb.rfc.rx_frame.credit); 362 } 363 364 return; 365 } 366 rfc_port_sm_execute(p_port, event, nullptr); 367 osi_free(p_buf); 368 } 369 370 /******************************************************************************* 371 * 372 * Function RFCOMM_CongestionStatusInd 373 * 374 * Description This is a callback function called by L2CAP when 375 * data RFCOMM L2CAP congestion status changes 376 * 377 ******************************************************************************/ 378 void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) { 379 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); 380 381 if (!p_mcb) { 382 RFCOMM_TRACE_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid); 383 return; 384 } else { 385 RFCOMM_TRACE_EVENT("RFCOMM_CongestionStatusInd LCID:0x%x", lcid); 386 } 387 rfc_process_l2cap_congestion(p_mcb, is_congested); 388 } 389 390 /******************************************************************************* 391 * 392 * Function rfc_find_lcid_mcb 393 * 394 * Description This function returns MCB block supporting local cid 395 * 396 ******************************************************************************/ 397 tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid) { 398 if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) { 399 RFCOMM_TRACE_ERROR("rfc_find_lcid_mcb LCID:0x%x", lcid); 400 return nullptr; 401 } else { 402 tRFC_MCB* p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]; 403 if (p_mcb != nullptr) { 404 if (p_mcb->lcid != lcid) { 405 LOG(WARNING) << __func__ << "LCID reused lcid=:" << loghex(lcid) 406 << ", current_lcid=" << loghex(p_mcb->lcid); 407 return nullptr; 408 } 409 } 410 return p_mcb; 411 } 412 } 413 414 /******************************************************************************* 415 * 416 * Function rfc_save_lcid_mcb 417 * 418 * Description This function returns MCB block supporting local cid 419 * 420 ******************************************************************************/ 421 void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) { 422 if (lcid < L2CAP_BASE_APPL_CID) return; 423 rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb; 424 } 425