OSDN Git Service

Remove casts to unions to avoid unaligned accesses
[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           tAVCT_LCB_EVT avct_lcb_evt;
201           avct_lcb_evt.result = result;
202           avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
203         }
204       }
205     } else if (p_lcb->conflict_lcid == lcid) {
206       /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
207       AVCT_TRACE_DEBUG(
208           "avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x",
209           p_lcb->ch_state, p_lcb->conflict_lcid);
210       if (result == L2CAP_CONN_OK) {
211         /* just in case the peer also accepts our connection - Send L2CAP
212          * disconnect req */
213         L2CA_DisconnectReq(lcid);
214       }
215       p_lcb->conflict_lcid = 0;
216     }
217     AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
218   }
219 }
220
221 /*******************************************************************************
222  *
223  * Function         avct_l2c_config_cfm_cback
224  *
225  * Description      This is the L2CAP config confirm callback function.
226  *
227  *
228  * Returns          void
229  *
230  ******************************************************************************/
231 void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
232   tAVCT_LCB* p_lcb;
233
234   /* look up lcb for this channel */
235   p_lcb = avct_lcb_by_lcid(lcid);
236   if (p_lcb != NULL) {
237     AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
238                      lcid, p_lcb->ch_state, p_cfg->result);
239     /* if in correct state */
240     if (p_lcb->ch_state == AVCT_CH_CFG) {
241       /* if result successful */
242       if (p_cfg->result == L2CAP_CFG_OK) {
243         /* update flags */
244         p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
245
246         /* if configuration complete */
247         if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
248           p_lcb->ch_state = AVCT_CH_OPEN;
249           avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
250         }
251       }
252       /* else failure */
253       else {
254         AVCT_TRACE_DEBUG(
255             "ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ",
256             p_lcb->ch_state);
257         /* store result value */
258         p_lcb->ch_result = p_cfg->result;
259
260         /* Send L2CAP disconnect req */
261         L2CA_DisconnectReq(lcid);
262       }
263     }
264     AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
265   }
266 }
267
268 /*******************************************************************************
269  *
270  * Function         avct_l2c_config_ind_cback
271  *
272  * Description      This is the L2CAP config indication callback function.
273  *
274  *
275  * Returns          void
276  *
277  ******************************************************************************/
278 void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
279   tAVCT_LCB* p_lcb;
280
281   /* look up lcb for this channel */
282   p_lcb = avct_lcb_by_lcid(lcid);
283   if (p_lcb != NULL) {
284     AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid,
285                      p_lcb->ch_state);
286     /* store the mtu in tbl */
287     if (p_cfg->mtu_present) {
288       p_lcb->peer_mtu = p_cfg->mtu;
289     } else {
290       p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
291     }
292
293     /* send L2CAP configure response */
294     memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
295     p_cfg->result = L2CAP_CFG_OK;
296     L2CA_ConfigRsp(lcid, p_cfg);
297
298     /* if first config ind */
299     if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
300       /* update flags */
301       p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
302
303       /* if configuration complete */
304       if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
305         p_lcb->ch_state = AVCT_CH_OPEN;
306         avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
307       }
308     }
309     AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
310   }
311 }
312
313 /*******************************************************************************
314  *
315  * Function         avct_l2c_disconnect_ind_cback
316  *
317  * Description      This is the L2CAP disconnect indication callback function.
318  *
319  *
320  * Returns          void
321  *
322  ******************************************************************************/
323 void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
324   tAVCT_LCB* p_lcb;
325   uint16_t result = AVCT_RESULT_FAIL;
326
327   /* look up lcb for this channel */
328   p_lcb = avct_lcb_by_lcid(lcid);
329   if (p_lcb != NULL) {
330     AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid,
331                      p_lcb->ch_state);
332     if (ack_needed) {
333       /* send L2CAP disconnect response */
334       L2CA_DisconnectRsp(lcid);
335     }
336
337     tAVCT_LCB_EVT avct_lcb_evt;
338     avct_lcb_evt.result = result;
339     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
340     AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
341   }
342 }
343
344 /*******************************************************************************
345  *
346  * Function         avct_l2c_disconnect_cfm_cback
347  *
348  * Description      This is the L2CAP disconnect confirm callback function.
349  *
350  *
351  * Returns          void
352  *
353  ******************************************************************************/
354 void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
355   tAVCT_LCB* p_lcb;
356   uint16_t res;
357
358   /* look up lcb for this channel */
359   p_lcb = avct_lcb_by_lcid(lcid);
360   if (p_lcb != NULL) {
361     AVCT_TRACE_DEBUG(
362         "avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", lcid,
363         p_lcb->ch_state, result);
364     /* result value may be previously stored */
365     res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
366     p_lcb->ch_result = 0;
367
368     tAVCT_LCB_EVT avct_lcb_evt;
369     avct_lcb_evt.result = res;
370     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
371     AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
372   }
373 }
374
375 /*******************************************************************************
376  *
377  * Function         avct_l2c_congestion_ind_cback
378  *
379  * Description      This is the L2CAP congestion indication callback function.
380  *
381  *
382  * Returns          void
383  *
384  ******************************************************************************/
385 void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
386   tAVCT_LCB* p_lcb;
387
388   AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
389   /* look up lcb for this channel */
390   p_lcb = avct_lcb_by_lcid(lcid);
391   if (p_lcb != NULL) {
392     tAVCT_LCB_EVT avct_lcb_evt;
393     avct_lcb_evt.cong = is_congested;
394     avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, &avct_lcb_evt);
395   }
396 }
397
398 /*******************************************************************************
399  *
400  * Function         avct_l2c_data_ind_cback
401  *
402  * Description      This is the L2CAP data indication callback function.
403  *
404  *
405  * Returns          void
406  *
407  ******************************************************************************/
408 void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
409   tAVCT_LCB* p_lcb;
410
411   AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
412   /* look up lcb for this channel */
413   p_lcb = avct_lcb_by_lcid(lcid);
414   if (p_lcb != NULL) {
415     avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf);
416   } else /* prevent buffer leak */
417   {
418     AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
419     osi_free(p_buf);
420   }
421 }