• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */);
78 }
79 
80 /*******************************************************************************
81  *
82  * Function         RFCOMM_ConnectInd
83  *
84  * Description      This is a callback function called by L2CAP when
85  *                  L2CA_ConnectInd received.  Allocate multiplexer control
86  *                  block and dispatch the event to it.
87  *
88  ******************************************************************************/
RFCOMM_ConnectInd(const RawAddress & bd_addr,uint16_t lcid,UNUSED_ATTR uint16_t psm,uint8_t id)89 void RFCOMM_ConnectInd(const RawAddress& bd_addr, uint16_t lcid,
90                        UNUSED_ATTR uint16_t psm, uint8_t id) {
91   tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(bd_addr, false);
92 
93   if ((p_mcb) && (p_mcb->state != RFC_MX_STATE_IDLE)) {
94     /* if this is collision case */
95     if ((p_mcb->is_initiator) && (p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) {
96       p_mcb->pending_lcid = lcid;
97       p_mcb->pending_id = id;
98 
99       /* wait random timeout (2 - 12) to resolve collision */
100       /* if peer gives up then local device rejects incoming connection and
101        * continues as initiator */
102       /* if timeout, local device disconnects outgoing connection and continues
103        * as acceptor */
104       RFCOMM_TRACE_DEBUG(
105           "RFCOMM_ConnectInd start timer for collision, initiator's "
106           "LCID(0x%x), acceptor's LCID(0x%x)",
107           p_mcb->lcid, p_mcb->pending_lcid);
108 
109       rfc_timer_start(
110           p_mcb,
111           (uint16_t)(bluetooth::common::time_get_os_boottime_ms() % 10 + 2));
112       return;
113     } else {
114       /* we cannot accept connection request from peer at this state */
115       /* don't update lcid */
116       p_mcb = nullptr;
117     }
118   } else {
119     /* store mcb even if null */
120     rfc_save_lcid_mcb(p_mcb, lcid);
121   }
122 
123   if (p_mcb == nullptr) {
124     L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
125     return;
126   }
127   p_mcb->lcid = lcid;
128 
129   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &id);
130 }
131 
132 /*******************************************************************************
133  *
134  * Function         RFCOMM_ConnectCnf
135  *
136  * Description      This is a callback function called by L2CAP when
137  *                  L2CA_ConnectCnf received.  Save L2CAP handle and dispatch
138  *                  event to the FSM.
139  *
140  ******************************************************************************/
RFCOMM_ConnectCnf(uint16_t lcid,uint16_t result)141 void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) {
142   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
143 
144   if (!p_mcb) {
145     RFCOMM_TRACE_ERROR("RFCOMM_ConnectCnf LCID:0x%x", lcid);
146     return;
147   }
148 
149   if (p_mcb->pending_lcid) {
150     /* if peer rejects our connect request but peer's connect request is pending
151      */
152     if (result != L2CAP_CONN_OK) {
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 (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
169         uint8_t handle = p_mcb->port_handles[i];
170         if (handle != 0) {
171           p_mcb->port_handles[i] = 0;
172           p_mcb->port_handles[i + 1] = handle;
173           rfc_cb.port.port[handle - 1].dlci += 1;
174           RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", handle,
175                              i, rfc_cb.port.port[handle - 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  ******************************************************************************/
RFCOMM_ConfigInd(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)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  ******************************************************************************/
RFCOMM_ConfigCnf(uint16_t lcid,tL2CAP_CFG_INFO * p_cfg)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  ******************************************************************************/
RFCOMM_QoSViolationInd(UNUSED_ATTR const RawAddress & bd_addr)249 void RFCOMM_QoSViolationInd(UNUSED_ATTR const RawAddress& 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  ******************************************************************************/
RFCOMM_DisconnectInd(uint16_t lcid,bool is_conf_needed)259 void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) {
260   VLOG(1) << __func__ << ": lcid=" << loghex(lcid)
261           << ", is_conf_needed=" << is_conf_needed;
262   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
263   if (is_conf_needed) {
264     L2CA_DisconnectRsp(lcid);
265   }
266   if (!p_mcb) {
267     LOG(WARNING) << __func__ << ": no mcb for lcid " << loghex(lcid);
268     return;
269   }
270   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr);
271 }
272 
273 /*******************************************************************************
274  *
275  * Function         RFCOMM_BufDataInd
276  *
277  * Description      This is a callback function called by L2CAP when
278  *                  data RFCOMM frame is received.  Parse the frames, check
279  *                  the checksum and dispatch event to multiplexer or port
280  *                  state machine depending on the frame destination.
281  *
282  ******************************************************************************/
RFCOMM_BufDataInd(uint16_t lcid,BT_HDR * p_buf)283 void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) {
284   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
285 
286   if (!p_mcb) {
287     LOG(WARNING) << __func__ << ": Cannot find RFCOMM multiplexer for lcid "
288                  << loghex(lcid);
289     osi_free(p_buf);
290     return;
291   }
292 
293   uint8_t event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
294 
295   /* If the frame did not pass validation just ignore it */
296   if (event == RFC_EVENT_BAD_FRAME) {
297     LOG(WARNING) << __func__ << ": Bad RFCOMM frame from lcid=" << loghex(lcid)
298                  << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
299     osi_free(p_buf);
300     return;
301   }
302 
303   if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
304     RFCOMM_TRACE_DEBUG("%s: handle multiplexer event %d, p_mcb=%p", __func__,
305                        event, p_mcb);
306     /* Take special care of the Multiplexer Control Messages */
307     if (event == RFC_EVENT_UIH) {
308       rfc_process_mx_message(p_mcb, p_buf);
309       return;
310     }
311 
312     /* Other multiplexer events go to state machine */
313     rfc_mx_sm_execute(p_mcb, event, nullptr);
314     osi_free(p_buf);
315     return;
316   }
317 
318   /* The frame was received on the data channel DLCI, verify that DLC exists */
319   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci);
320   if (p_port == nullptr || !p_port->rfc.p_mcb) {
321     /* If this is a SABME on new port, check if any app is waiting for it */
322     if (event != RFC_EVENT_SABME) {
323       LOG(WARNING) << __func__
324                    << ": no for none-SABME event, lcid=" << loghex(lcid)
325                    << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
326       if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) ||
327           (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) {
328         LOG(ERROR) << __func__
329                    << ": Disconnecting RFCOMM, lcid=" << loghex(lcid)
330                    << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
331         rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
332       }
333       osi_free(p_buf);
334       return;
335     }
336 
337     p_port = port_find_dlci_port(rfc_cb.rfc.rx_frame.dlci);
338     if (p_port == nullptr) {
339       LOG(ERROR) << __func__ << ":Disconnecting RFCOMM, no port for dlci "
340                  << +rfc_cb.rfc.rx_frame.dlci << ", lcid=" << loghex(lcid)
341                  << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
342       rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true);
343       osi_free(p_buf);
344       return;
345     }
346     RFCOMM_TRACE_DEBUG("%s: port_handles[dlci=%d]:%d->%d, p_mcb=%p", __func__,
347                        rfc_cb.rfc.rx_frame.dlci,
348                        p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci],
349                        p_port->handle);
350     p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci] = p_port->handle;
351     p_port->rfc.p_mcb = p_mcb;
352   }
353 
354   if (event == RFC_EVENT_UIH) {
355     RFCOMM_TRACE_DEBUG("%s: Handling UIH event, buf_len=%u, credit=%u",
356                        __func__, p_buf->len, rfc_cb.rfc.rx_frame.credit);
357     if (p_buf->len > 0) {
358       rfc_port_sm_execute(p_port, event, p_buf);
359     } else {
360       osi_free(p_buf);
361     }
362 
363     if (rfc_cb.rfc.rx_frame.credit != 0) {
364       rfc_inc_credit(p_port, rfc_cb.rfc.rx_frame.credit);
365     }
366 
367     return;
368   }
369   rfc_port_sm_execute(p_port, event, nullptr);
370   osi_free(p_buf);
371 }
372 
373 /*******************************************************************************
374  *
375  * Function         RFCOMM_CongestionStatusInd
376  *
377  * Description      This is a callback function called by L2CAP when
378  *                  data RFCOMM L2CAP congestion status changes
379  *
380  ******************************************************************************/
RFCOMM_CongestionStatusInd(uint16_t lcid,bool is_congested)381 void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) {
382   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
383 
384   if (!p_mcb) {
385     RFCOMM_TRACE_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
386     return;
387   } else {
388     RFCOMM_TRACE_EVENT("RFCOMM_CongestionStatusInd LCID:0x%x", lcid);
389   }
390   rfc_process_l2cap_congestion(p_mcb, is_congested);
391 }
392 
393 /*******************************************************************************
394  *
395  * Function         rfc_find_lcid_mcb
396  *
397  * Description      This function returns MCB block supporting local cid
398  *
399  ******************************************************************************/
rfc_find_lcid_mcb(uint16_t lcid)400 tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid) {
401   if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) {
402     RFCOMM_TRACE_ERROR("rfc_find_lcid_mcb LCID:0x%x", lcid);
403     return nullptr;
404   } else {
405     tRFC_MCB* p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID];
406     if (p_mcb != nullptr) {
407       if (p_mcb->lcid != lcid) {
408         LOG(WARNING) << __func__ << "LCID reused lcid=:" << loghex(lcid)
409                      << ", current_lcid=" << loghex(p_mcb->lcid);
410         return nullptr;
411       }
412     }
413     return p_mcb;
414   }
415 }
416 
417 /*******************************************************************************
418  *
419  * Function         rfc_save_lcid_mcb
420  *
421  * Description      This function returns MCB block supporting local cid
422  *
423  ******************************************************************************/
rfc_save_lcid_mcb(tRFC_MCB * p_mcb,uint16_t lcid)424 void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) {
425   if (lcid < L2CAP_BASE_APPL_CID) {
426     LOG(ERROR) << __func__ << ": LCID " << lcid << " is too small";
427     return;
428   }
429   auto mcb_index = static_cast<size_t>(lcid - L2CAP_BASE_APPL_CID);
430   if (mcb_index >= MAX_L2CAP_CHANNELS) {
431     LOG(ERROR) << __func__ << ": LCID " << lcid << " is too large";
432     return;
433   }
434   rfc_cb.rfc.p_rfc_lcid_mcb[mcb_index] = p_mcb;
435 }
436