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