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