zoukankan      html  css  js  c++  java
  • bluedroid源代码分析之ACL包发送和接收(一)

    很多其它内容请參照我的个人网站: http://stackvoid.com/

    ACL 链路在 Bluetooth 中很重要,一些重要的应用如 A2DP, 基于 RFCOMM 的应用,BNEP等都要建立 ACL 链路,发送/接收ACL 包。今天跟大家一起来分析 ACL 包发送/接收流程,以及涉及到的重要 command/event。


    ACL包发送

    以下的图(点击大图)是各种应用层使用 L2CAP 的 API:L2CA_DataWrite 发送数据流的过程,此API继续往下走,我仅分析了正常数据流的走向(临时没有考虑别的情况)。

    ACL_01


    应用层数据到 L2CAP 的入口

    我们如果一个听音乐的场景,Mike跟大家一起分析音乐数据流 AVDTP 下面层的传送。

    在 AVDTP 中,全部的功能想发送 Data,必须调用 avdt_ad_write_req 这个函数。Mike 就从这个函数入手分析。

     1 //当CCB或SCB给l2cap的 Channel 发送数据时。他们终于都会使用到L2CAP的 API:L2CA_Data_Write
     2 UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
     3 {
     4     UINT8   tcid;
     5 
     6     /* get tcid from type, scb */
     7     tcid = avdt_ad_type_to_tcid(type, p_scb);
     8 
     9 
    10     return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
    11 }
    12 //L2CA_DataWrite的返回形式有三种,各自是:
    13 //1. L2CAP_DW_SUCCESS:此数据写成功
    14 //2.L2CAP_DW_CONGESTED:写数据成功,可是当前信道拥堵
    15 //3.L2CAP_DW_FAILED:写数据失败
    16 UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data)
    17 {
    18     L2CAP_TRACE_API2 ("L2CA_DataWrite()  CID: 0x%04x  Len: %d", cid, p_data->len);
    19     return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
    20 }

    当我们的音乐数据流到达 l2c_data_write 这个函数时,标志数据流正式进入到L2CAP层。 我们在以下的源代码中深入分析 l2c_data_write 这个函数。

    l2c_data_write 这个函数做的事情主要有:

    1. 依据參数 cid(Channel ID) 找到 相应的 ccb(Channel Control Block), 找不到返回 L2CAP_DW_FAILED
    2. 假设測试者 打开 TESTER 这个宏,发送随意数据,当数据大小 大于 MTU 最大值,也会返回 L2CAP_DW_FAILED
    3. 通过检查 p_ccb->cong_sent 字段,TRUE。则说明当前 Channel 已经拥挤,此时L2CAP的这个Channel不在接收数据,返回 L2CAP_DW_FAILED
    4. 以上三个条件都通过。说明数据可发送。将数据通过 l2c_csm_execute 继续处理。

      进入 l2c_csm_execute 函数,标志着这笔数据已经成功交给 l2CAP 来处理。与上层已经没有关系了。

    5. l2c_csm_execute 函数运行结束后,再次检查 p_ccb->cong_sent 字段,看看当前的 Channel 是否拥挤,假设拥挤则告诉上层 L2CAP_DW_CONGESTED,否则返回 L2CAP_DW_SUCCESS,表示数据已经成功发送。

      1 //返回的数据跟上面的 L2CA_DataWrite 作用同样
      2 UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flags)
      3 {
      4     tL2C_CCB        *p_ccb;
      5 
      6     //遍历l2cb.ccb_pool。通过Channel ID找到相应的Channel Control Block
      7     //l2cu_find_ccb_by_cid 见以下源代码凝视
      8     if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
      9     {
     10         L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
     11         GKI_freebuf (p_data);
     12         return (L2CAP_DW_FAILED);
     13     }
     14 
     15 #ifndef TESTER /* Tester may send any amount of data. otherwise sending message
     16                   bigger than mtu size of peer is a violation of protocol */
     17     if (p_data->len > p_ccb->peer_cfg.mtu)
     18     {
     19         L2CAP_TRACE_WARNING1 ("L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size", cid);
     20         GKI_freebuf (p_data);
     21         return (L2CAP_DW_FAILED);
     22     }
     23 #endif
     24 
     25     /* channel based, packet based flushable or non-flushable */
     26     //Bluedroid中默认的是 L2CAP_FLUSHABLE_CH_BASED
     27     //这个 layer_specific 在 数据发送的 l2c_link_send_to_lower 中表示 ACL包分包 个数
     28     p_data->layer_specific = flags;
     29 
     30     //发现本 Channel 已经拥堵,直接返回L2CAP_DW_FAILED 告诉上层等会再发数据
     31     //当几个应用 共用 此 Channel 可能会出现这样的情况
     32     if (p_ccb->cong_sent)
     33     {
     34         L2CAP_TRACE_ERROR3 ("L2CAP - CID: 0x%04x cannot send, already congested  xmit_hold_q.count: %u  buff_quota: %u",
     35                             p_ccb->local_cid, p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
     36 
     37         GKI_freebuf (p_data);
     38         return (L2CAP_DW_FAILED);
     39     }
     40     //毫无疑问啦,这个函数就是我们继续须要分析的函数
     41     l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);
     42 
     43     //已经将上层的这笔数据发送完,假设此 Channel 拥挤了(之前发送这笔包还没拥挤)
     44     //返回 L2CAP_DW_CONGESTED 告诉上层当前信道拥挤,你要给我L2CAP层发数据,是不发下来的
     45     if (p_ccb->cong_sent)
     46         return (L2CAP_DW_CONGESTED);
     47 
     48     //成功发送。而且此时 Channel 并不拥挤
     49     return (L2CAP_DW_SUCCESS);
     50 }
     51 
     52 //通过 Channel ID 找到 Channel Control Block
     53 tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid)
     54 {
     55     tL2C_CCB    *p_ccb = NULL;
     56 #if (L2CAP_UCD_INCLUDED == TRUE)
     57     UINT8 xx;
     58 #endif
     59 
     60     if (local_cid >= L2CAP_BASE_APPL_CID) //大于或等于 0x0040 说明不是 Fixed Channel
     61     {
     62         /* find the associated CCB by "index" */
     63         local_cid -= L2CAP_BASE_APPL_CID;
     64 
     65         if (local_cid >= MAX_L2CAP_CHANNELS)
     66             return NULL;
     67 
     68         p_ccb = l2cb.ccb_pool + local_cid; //直接通过地址偏移找到
     69 
     70         /* make sure the CCB is in use */
     71         if (!p_ccb->in_use)
     72         {
     73             p_ccb = NULL;
     74         }
     75         /* make sure it's for the same LCB */
     76         else if (p_lcb && p_lcb != p_ccb->p_lcb)
     77         {
     78             p_ccb = NULL;
     79         }
     80     }
     81 #if (L2CAP_UCD_INCLUDED == TRUE) //默认是关闭的,既然从上层来的都是 数据包了,我觉得不会用到 Fixed Channel
     82     else
     83     {
     84         /* searching fixed channel */
     85         p_ccb = l2cb.ccb_pool;
     86         for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
     87         {
     88             if ((p_ccb->local_cid == local_cid)
     89               &&(p_ccb->in_use)
     90               &&(p_lcb == p_ccb->p_lcb))
     91                 break;
     92             else
     93                 p_ccb++;
     94         }
     95         if ( xx >= MAX_L2CAP_CHANNELS )
     96             return NULL;
     97     }
     98 #endif
     99 
    100     return (p_ccb);
    101 }

    下一篇博客我们来看看 L2CAP 层的处理。


    很多其它内容请參照我的个人网站: http://stackvoid.com/

  • 相关阅读:
    修复PLSQL Developer 与 Office 2010的集成导出Excel 功能
    Using svn in CLI with Batch
    mysql 备份数据库 mysqldump
    Red Hat 5.8 CentOS 6.5 共用 输入法
    HP 4411s Install Red Hat Enterprise Linux 5.8) Wireless Driver
    变更RHEL(Red Hat Enterprise Linux 5.8)更新源使之自动更新
    RedHat 5.6 问题简记
    Weblogic 9.2和10.3 改密码 一站完成
    ExtJS Tab里放Grid高度自适应问题,官方Perfect方案。
    文件和目录之utime函数
  • 原文地址:https://www.cnblogs.com/llguanli/p/6854887.html
Copyright © 2011-2022 走看看