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