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