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