OSDN Git Service

cad4e4a16340bd2c86eb6aa7548720e8e136afa7
[android-x86/system-bt.git] / stack / avct / avct_l2c.cc
1 /******************************************************************************
2  *
3  *  Copyright (C) 2003-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 AVCTP module interfaces to L2CAP
22  *
23  ******************************************************************************/
24
25 #include <string.h>
26 #include "avct_api.h"
27 #include "avct_int.h"
28 #include "bt_target.h"
29 #include "bt_types.h"
30 #include "bt_utils.h"
31 #include "l2c_api.h"
32 #include "l2cdefs.h"
33 #include "osi/include/osi.h"
34
35 /* Configuration flags. */
36 #define AVCT_L2C_CFG_IND_DONE (1 << 0)
37 #define AVCT_L2C_CFG_CFM_DONE (1 << 1)
38
39 /* callback function declarations */
40 void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
41                                 uint16_t psm, uint8_t id);
42 void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
43 void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
44 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
45 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
46 void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
47 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
48 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
49
50 /* L2CAP callback function structure */
51 const tL2CAP_APPL_INFO avct_l2c_appl = {
52     avct_l2c_connect_ind_cback,
53     avct_l2c_connect_cfm_cback,
54     NULL,
55     avct_l2c_config_ind_cback,
56     avct_l2c_config_cfm_cback,
57     avct_l2c_disconnect_ind_cback,
58     avct_l2c_disconnect_cfm_cback,
59     NULL,
60     avct_l2c_data_ind_cback,
61     avct_l2c_congestion_ind_cback,
62     NULL /* tL2CA_TX_COMPLETE_CB */
63 };
64
65 /*******************************************************************************
66  *
67  * Function         avct_l2c_is_passive
68  *
69  * Description      check is the CCB associated with the given LCB was created
70  *                  as passive
71  *
72  * Returns          true, if the given LCB is created as AVCT_PASSIVE
73  *
74  ******************************************************************************/
75 static bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) {
76   bool is_passive = false;
77   tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
78   int i;
79
80   for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
81     if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
82       AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
83       if (p_ccb->cc.control & AVCT_PASSIVE) {
84         is_passive = true;
85         break;
86       }
87     }
88   }
89   return is_passive;
90 }
91
92 /*******************************************************************************
93  *
94  * Function         avct_l2c_connect_ind_cback
95  *
96  * Description      This is the L2CAP connect indication callback function.
97  *
98  *
99  * Returns          void
100  *
101  ******************************************************************************/
102 void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid,
103                                 UNUSED_ATTR uint16_t psm, uint8_t id) {
104   tAVCT_LCB* p_lcb;
105   uint16_t result = L2CAP_CONN_OK;
106   tL2CAP_CFG_INFO cfg;
107
108   /* do we already have a channel for this peer? */
109   p_lcb = avct_lcb_by_bd(bd_addr);
110   if (p_lcb == NULL) {
111     /* no, allocate lcb */
112     p_lcb = avct_lcb_alloc(bd_addr);
113     if (p_lcb == NULL) {
114       /* no ccb available, reject L2CAP connection */
115       result = L2CAP_CONN_NO_RESOURCES;
116     }
117   }
118   /* else we already have a channel for this peer */
119   else {
120     if (!avct_l2c_is_passive(p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) {
121       /* this LCB included CT role - reject */
122       result = L2CAP_CONN_NO_RESOURCES;
123     } else {
124       /* TG role only - accept the connection from CT. move the channel ID to
125        * the conflict list */
126       p_lcb->conflict_lcid = p_lcb->ch_lcid;
127       AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x",
128                        p_lcb->conflict_lcid);
129     }
130   }
131
132   if (p_lcb) {
133     AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
134                      lcid, result, p_lcb->ch_state);
135   }
136   /* Send L2CAP connect rsp */
137   L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
138
139   /* if result ok, proceed with connection */
140   if (result == L2CAP_CONN_OK) {
141     /* store LCID */
142     p_lcb->ch_lcid = lcid;
143
144     /* transition to configuration state */
145     p_lcb->ch_state = AVCT_CH_CFG;
146
147     /* Send L2CAP config req */
148     memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
149     cfg.mtu_present = true;
150     cfg.mtu = avct_cb.mtu;
151     L2CA_ConfigReq(lcid, &cfg);
152     AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
153   }
154
155   if (p_lcb) AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
156 }
157
158 /*******************************************************************************
159  *
160  * Function         avct_l2c_connect_cfm_cback
161  *
162  * Description      This is the L2CAP connect confirm callback function.
163  *
164  *
165  * Returns          void
166  *
167  ******************************************************************************/
168 void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
169   tAVCT_LCB* p_lcb;
170   tL2CAP_CFG_INFO cfg;
171
172   /* look up lcb for this channel */
173   p_lcb = avct_lcb_by_lcid(lcid);
174   if (p_lcb != NULL) {
175     AVCT_TRACE_DEBUG(
176         "avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, "
177         "conflict_lcid:0x%x",
178         lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
179     /* if in correct state */
180     if (p_lcb->ch_state == AVCT_CH_CONN) {
181       /* if result successful */
182       if (result == L2CAP_CONN_OK) {
183         /* set channel state */
184         p_lcb->ch_state = AVCT_CH_CFG;
185
186         /* Send L2CAP config req */
187         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
188         cfg.mtu_present = true;
189         cfg.mtu = avct_cb.mtu;
190         L2CA_ConfigReq(lcid, &cfg);
191         AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
192       }
193       /* else failure */
194       else {
195         AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x",
196                          p_lcb->conflict_lcid);
197         if (p_lcb->conflict_lcid == lcid)
198           p_lcb->conflict_lcid = 0;
199         else
200           avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
201       }
202     } else if (p_lcb->conflict_lcid == lcid) {
203       /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
204       AVCT_TRACE_DEBUG(
205           "avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x",
206           p_lcb->ch_state, p_lcb->conflict_lcid);
207       if (result == L2CAP_CONN_OK) {
208         /* just in case the peer also accepts our connection - Send L2CAP
209          * disconnect req */
210         L2CA_DisconnectReq(lcid);
211       }
212       p_lcb->conflict_lcid = 0;
213     }
214     AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
215   }
216 }
217
218 /*******************************************************************************
219  *
220  * Function         avct_l2c_config_cfm_cback
221  *
222  * Description      This is the L2CAP config confirm callback function.
223  *
224  *
225  * Returns          void
226  *
227  ******************************************************************************/
228 void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
229   tAVCT_LCB* p_lcb;
230
231   /* look up lcb for this channel */
232   p_lcb = avct_lcb_by_lcid(lcid);
233   if (p_lcb != NULL) {
234     AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
235                      lcid, p_lcb->ch_state, p_cfg->result);
236     /* if in correct state */
237     if (p_lcb->ch_state == AVCT_CH_CFG) {
238       /* if result successful */
239       if (p_cfg->result == L2CAP_CFG_OK) {
240         /* update flags */
241         p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
242
243         /* if configuration complete */
244         if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
245           p_lcb->ch_state = AVCT_CH_OPEN;
246           avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
247         }
248       }
249       /* else failure */
250       else {
251         AVCT_TRACE_DEBUG(
252             "ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ",
253             p_lcb->ch_state);
254         /* store result value */
255         p_lcb->ch_result = p_cfg->result;
256
257         /* Send L2CAP disconnect req */
258         L2CA_DisconnectReq(lcid);
259       }
260     }
261     AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
262   }
263 }
264
265 /*******************************************************************************
266  *
267  * Function         avct_l2c_config_ind_cback
268  *
269  * Description      This is the L2CAP config indication callback function.
270  *
271  *
272  * Returns          void
273  *
274  ******************************************************************************/
275 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
276   tAVCT_LCB* p_lcb;
277
278   /* look up lcb for this channel */
279   p_lcb = avct_lcb_by_lcid(lcid);
280   if (p_lcb != NULL) {
281     AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid,
282                      p_lcb->ch_state);
283     /* store the mtu in tbl */
284     if (p_cfg->mtu_present) {
285       p_lcb->peer_mtu = p_cfg->mtu;
286     } else {
287       p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
288     }
289
290     /* send L2CAP configure response */
291     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
292     p_cfg->result = L2CAP_CFG_OK;
293     L2CA_ConfigRsp(lcid, p_cfg);
294
295     /* if first config ind */
296     if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
297       /* update flags */
298       p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
299
300       /* if configuration complete */
301       if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
302         p_lcb->ch_state = AVCT_CH_OPEN;
303         avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
304       }
305     }
306     AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
307   }
308 }
309
310 /*******************************************************************************
311  *
312  * Function         avct_l2c_disconnect_ind_cback
313  *
314  * Description      This is the L2CAP disconnect indication callback function.
315  *
316  *
317  * Returns          void
318  *
319  ******************************************************************************/
320 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
321   tAVCT_LCB* p_lcb;
322   uint16_t result = AVCT_RESULT_FAIL;
323
324   /* look up lcb for this channel */
325   p_lcb = avct_lcb_by_lcid(lcid);
326   if (p_lcb != NULL) {
327     AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid,
328                      p_lcb->ch_state);
329     if (ack_needed) {
330       /* send L2CAP disconnect response */
331       L2CA_DisconnectRsp(lcid);
332     }
333
334     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
335     AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
336   }
337 }
338
339 /*******************************************************************************
340  *
341  * Function         avct_l2c_disconnect_cfm_cback
342  *
343  * Description      This is the L2CAP disconnect confirm callback function.
344  *
345  *
346  * Returns          void
347  *
348  ******************************************************************************/
349 void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
350   tAVCT_LCB* p_lcb;
351   uint16_t res;
352
353   /* look up lcb for this channel */
354   p_lcb = avct_lcb_by_lcid(lcid);
355   if (p_lcb != NULL) {
356     AVCT_TRACE_DEBUG(
357         "avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", lcid,
358         p_lcb->ch_state, result);
359     /* result value may be previously stored */
360     res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
361     p_lcb->ch_result = 0;
362
363     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&res);
364     AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
365   }
366 }
367
368 /*******************************************************************************
369  *
370  * Function         avct_l2c_congestion_ind_cback
371  *
372  * Description      This is the L2CAP congestion indication callback function.
373  *
374  *
375  * Returns          void
376  *
377  ******************************************************************************/
378 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
379   tAVCT_LCB* p_lcb;
380
381   AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
382   /* look up lcb for this channel */
383   p_lcb = avct_lcb_by_lcid(lcid);
384   if (p_lcb != NULL) {
385     avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT*)&is_congested);
386   }
387 }
388
389 /*******************************************************************************
390  *
391  * Function         avct_l2c_data_ind_cback
392  *
393  * Description      This is the L2CAP data indication callback function.
394  *
395  *
396  * Returns          void
397  *
398  ******************************************************************************/
399 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
400   tAVCT_LCB* p_lcb;
401
402   AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
403   /* look up lcb for this channel */
404   p_lcb = avct_lcb_by_lcid(lcid);
405   if (p_lcb != NULL) {
406     avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf);
407   } else /* prevent buffer leak */
408   {
409     AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
410     osi_free(p_buf);
411   }
412 }