avct_l2c.cc revision 911d1ae03efec2d54c3b1b605589d790d1745488
176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/******************************************************************************
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Copyright (C) 2003-2012 Broadcom Corporation
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Licensed under the Apache License, Version 2.0 (the "License");
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  you may not use this file except in compliance with the License.
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  You may obtain a copy of the License at:
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  http://www.apache.org/licenses/LICENSE-2.0
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Unless required by applicable law or agreed to in writing, software
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  distributed under the License is distributed on an "AS IS" BASIS,
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  See the License for the specific language governing permissions and
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  limitations under the License.
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ******************************************************************************/
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/******************************************************************************
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  This AVCTP module interfaces to L2CAP
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ******************************************************************************/
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "avct_api.h"
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "avct_int.h"
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bt_target.h"
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bt_types.h"
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bt_utils.h"
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "l2c_api.h"
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "l2cdefs.h"
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "osi/include/osi.h"
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Configuration flags. */
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define AVCT_L2C_CFG_IND_DONE (1 << 0)
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define AVCT_L2C_CFG_CFM_DONE (1 << 1)
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* callback function declarations */
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                uint8_t id);
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* L2CAP callback function structure */
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst tL2CAP_APPL_INFO avct_l2c_appl = {
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_connect_ind_cback,
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_connect_cfm_cback,
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    NULL,
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_config_ind_cback,
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_config_cfm_cback,
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_disconnect_ind_cback,
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_disconnect_cfm_cback,
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    NULL,
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_data_ind_cback,
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    avct_l2c_congestion_ind_cback,
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    NULL /* tL2CA_TX_COMPLETE_CB */
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*******************************************************************************
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Function         avct_l2c_is_passive
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description      check is the CCB associated with the given LCB was created
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *                  as passive
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns          true, if the given LCB is created as AVCT_PASSIVE
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ******************************************************************************/
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) {
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  bool is_passive = false;
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  int i;
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (p_ccb->cc.control & AVCT_PASSIVE) {
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        is_passive = true;
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        break;
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return is_passive;
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
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 ******************************************************************************/
102void avct_l2c_connect_ind_cback(BD_ADDR 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 ******************************************************************************/
168void 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 ******************************************************************************/
228void 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 ******************************************************************************/
275void 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 ******************************************************************************/
320void 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 ******************************************************************************/
349void 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 ******************************************************************************/
378void 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 ******************************************************************************/
399void 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}
413