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