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