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