当前位置:   article > 正文

bluedroid acl 发送和接受_bluedroid acl disconnect

bluedroid acl disconnect

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


ACL包发送

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

ACL_01


应用层数据到 L2CAP 的入口

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

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

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



下面我们来看看 L2CAP 层的处理

上一节讲了数据流入口,本文分析L2CAP的处理函数。

L2CAP层的处理

我们的音乐数据,通过 L2CAP 入口函数 l2c_data_write 的层层“考验”,已经顺利进入到 L2CAP 里了,下面我们来看看 L2CAP 层具体是怎么处理数据的。

首先我们进入了 L2CAP 层的状态机。

  1. 1 void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
  2. 2 {
  3. 3 switch (p_ccb->chnl_state)
  4. 4 {
  5. 5 case CST_CLOSED:
  6. 6 l2c_csm_closed (p_ccb, event, p_data);
  7. 7 break;
  8. 8
  9. 9 case CST_ORIG_W4_SEC_COMP:
  10. 10 l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
  11. 11 break;
  12. 12
  13. 13 case CST_TERM_W4_SEC_COMP:
  14. 14 l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
  15. 15 break;
  16. 16
  17. 17 case CST_W4_L2CAP_CONNECT_RSP:
  18. 18 l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
  19. 19 break;
  20. 20
  21. 21 case CST_W4_L2CA_CONNECT_RSP:
  22. 22 l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
  23. 23 break;
  24. 24
  25. 25 case CST_CONFIG:
  26. 26 l2c_csm_config (p_ccb, event, p_data);
  27. 27 break;
  28. 28
  29. 29 case CST_OPEN:
  30. 30 l2c_csm_open (p_ccb, event, p_data);
  31. 31 break;
  32. 32
  33. 33 case CST_W4_L2CAP_DISCONNECT_RSP:
  34. 34 l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
  35. 35 break;
  36. 36
  37. 37 case CST_W4_L2CA_DISCONNECT_RSP:
  38. 38 l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
  39. 39 break;
  40. 40
  41. 41 default:
  42. 42 break;
  43. 43 }
  44. 44 }

具体的 Channel 状态信息如下

  1. 1 typedef enum
  2. 2 {
  3. 3 CST_CLOSED, /* Channel is in clodes state */
  4. 4 CST_ORIG_W4_SEC_COMP, /* Originator waits security clearence */
  5. 5 CST_TERM_W4_SEC_COMP, /* Acceptor waits security clearence */
  6. 6 CST_W4_L2CAP_CONNECT_RSP, /* Waiting for peer conenct response */
  7. 7 CST_W4_L2CA_CONNECT_RSP, /* Waiting for upper layer connect rsp */
  8. 8 CST_CONFIG, /* Negotiating configuration */
  9. 9 CST_OPEN, /* Data transfer state */
  10. 10 CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */
  11. 11 CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */
  12. 12 } tL2C_CHNL_STATE;

l2c_csm_execute 函数通过 p_ccb 中的 chnl_state 字段,来确定接下来数据包的走向。如下图所示:

ACL Data

  1. CST_CLOSED 状态:这个 case 处理 Channel 处于 CLOSED 状态的事件。这个状态仅仅存在于 L2CAP 的 Link 初始建立过程中。

  2. 如果发现事件是 L2CEVT_LP_DISCONNECT_IND,则当前 Link 已经断开,则释放当前 Channel的 ccb;

  3. 若事件是 L2CEVT_LP_CONNECT_CFM,则置 p_ccb->chnl_state 为 CST_ORIG_W4_SEC_COMP 状态,下面会接着介绍这个。
  4. 如果是 L2CEVT_LP_CONNECT_CFM_NEG 则说明当前 Link 失败,
  5. 如果是 L2CEVT_SEC_COMP 则说明 Security 已经清除成功。
  6. 若是 L2CEVT_L2CA_CONNECT_REQ 则说明 来自上层的 connect 请求,如果当前处于 sniff 状态,要先取消 sniff。
  7. L2CEVT_SEC_COMP_NEG 说明 Security 失败,清除当前 CCB,返回
  8. L2CEVT_L2CAP_CONNECT_REQ 说明是 Peer connect request,既然成功连接了,结束掉 timer
  9. L2CEVT_L2CA_DATA_WRITE,如果我们的数据从上层经过这里,并且是 CST_CLOSED,由于当前的 Channel 没有建立好,并且上层已经将数据丢给L2CAP了,只能将数据丢弃处理了(数据流不能逆向)。
  10. L2CEVT_L2CA_DISCONNECT_REQ,上层想断开链接,会使用这个 Event来处理。

  11. CST_ORIG_W4_SEC_COMP 状态:Originator(我的理解是 发起 link 建立的应用)等待 security 的间隙,这个间隙需要处理的事件。跟 CST_CLOSED 差不多,源码很容易读,这里不再次做分析。注意,如果是 L2CEVT_SEC_COMP 事件(跟安全相关),会把 p_ccb->chnl_state 置为 CST_W4_L2CAP_CONNECT_RSP

  12. CST_TERM_W4_SEC_COMP状态:Acceptor(接收者)等待 security 的间隙,源码易读,不再详细展开分析,注意一个事件 L2CEVT_SEC_COMP 的处理,会将 p_ccb->chnl_state 置为 CST_W4_L2CA_CONNECT_RSP
  13. CST_W4_L2CAP_CONNECT_RSP: 经过 2 或 3 这个关于安全链接的步骤,当然要等待 Peer connect的回应(Response)。分为 获取 peer connect的 confirm、pending、rejected connection等信息,作进一步的判断。
  14. CST_CONFIG:商讨配置的过程。
  15. CST_OPEN:Channel 处于 OPEN 状态,我们可以发送上层传过来的数据,我们的音乐数据就是从这个 case 里发出去的。
  16. CST_W4_L2CAP_DISCONNECT_RSP:等待 peer(对方设备)断开链接的 Response
  17. CST_W4_L2CA_DISCONNECT_RSP:等待上层 disc rsp

分析了这么一大堆,我们的听音乐那那笔数据包,走的是 CST_OPEN 这个case,因为别的几个 case 在link 建立完成时就走完了。

我们的音乐数据包走的是 CST_OPEN 这个 case,这个 case 调用的是 l2c_csm_open 这个函数,接下来我们继续分析这个函数。

我们的音乐数据包在函数 l2c_csm_open 中流转,经过各种选择和判断,最后走的是 L2CEVT_L2CA_DATA_WRITE 这个 case。这个 case 调用了 l2c_enqueue_peer_data 让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。l2c_link_check_send_pkts 这个函数发送数据包。下面我们会继续分析这两个函数。

  1. 1 //l2c_csm_open 处理 Channel 处于 OPEN 状态下的各种 Event
  2. 2 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
  3. 3 {
  4. 4 UINT16 local_cid = p_ccb->local_cid;
  5. 5 tL2CAP_CFG_INFO *p_cfg;
  6. 6 tL2C_CHNL_STATE tempstate;
  7. 7 UINT8 tempcfgdone;
  8. 8 UINT8 cfg_result;
  9. 9
  10. 10 #if (BT_TRACE_VERBOSE == TRUE)
  11. 11 L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
  12. 12 #else
  13. 13 L2CAP_TRACE_EVENT1 ("L2CAP - st: OPEN evt: %d", event);
  14. 14 #endif
  15. 15
  16. 16 #if (L2CAP_UCD_INCLUDED == TRUE) //默认 UCD 是关闭的
  17. 17 if ( local_cid == L2CAP_CONNECTIONLESS_CID )
  18. 18 {
  19. 19 /* check if this event can be processed by UCD */
  20. 20 if ( l2c_ucd_process_event (p_ccb, event, p_data) )
  21. 21 {
  22. 22 /* The event is processed by UCD state machine */
  23. 23 return;
  24. 24 }
  25. 25 }
  26. 26 #endif
  27. 27
  28. 28 switch (event)
  29. 29 {
  30. 30 case L2CEVT_LP_DISCONNECT_IND: //Link 都断开连接了,自然 Channel也没有存在的必要了,各种清除 CCB 的工作
  31. 31 L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
  32. 32 l2cu_release_ccb (p_ccb);//释放 当前的 CCB
  33. 33 if (p_ccb->p_rcb)
  34. 34 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
  35. 35 break;
  36. 36
  37. 37 case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */
  38. 38 /* Tell upper layer. If service guaranteed, then clear the channel */
  39. 39 if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
  40. 40 (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
  41. 41 break;
  42. 42
  43. 43 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
  44. 44 p_cfg = (tL2CAP_CFG_INFO *)p_data;
  45. 45
  46. 46 tempstate = p_ccb->chnl_state;
  47. 47 tempcfgdone = p_ccb->config_done;
  48. 48 p_ccb->chnl_state = CST_CONFIG; //如果数据流中的数据是 L2CEVT_L2CAP_CONFIG_REQ,当然要转到 CST_CONFIG中继续处理
  49. 49 p_ccb->config_done &= ~CFG_DONE_MASK;
  50. 50 //启动一个 timer ,一段时间后,查看 cfg 的状态
  51. 51 //如果配置处于 L2CAP_PEER_CFG_UNACCEPTABLE,继续尝试配置
  52. 52 //如果配置处于断开状态,那当前 Channel 直接断开连接。
  53. 53 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
  54. 54
  55. 55 if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
  56. 56 {
  57. 57 (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
  58. 58 }
  59. 59
  60. 60 /* Error in config parameters: reset state and config flag */
  61. 61 else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
  62. 62 {
  63. 63 btu_stop_timer(&p_ccb->timer_entry);
  64. 64 p_ccb->chnl_state = tempstate;
  65. 65 p_ccb->config_done = tempcfgdone;
  66. 66 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
  67. 67 }
  68. 68 else /* L2CAP_PEER_CFG_DISCONNECT */
  69. 69 {
  70. 70 /* Disconnect if channels are incompatible
  71. 71 * Note this should not occur if reconfigure
  72. 72 * since this should have never passed original config.
  73. 73 */
  74. 74 l2cu_disconnect_chnl (p_ccb);
  75. 75 }
  76. 76 break;
  77. 77
  78. 78 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
  79. 79 // btla-specific ++
  80. 80 /* Make sure we are not in sniff mode */
  81. 81 #if BTM_PWR_MGR_INCLUDED == TRUE
  82. 82 {
  83. 83 tBTM_PM_PWR_MD settings;
  84. 84 settings.mode = BTM_PM_MD_ACTIVE;
  85. 85 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
  86. 86 }
  87. 87 #else
  88. 88 BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
  89. 89 #endif
  90. 90 // btla-specific --
  91. 91
  92. 92 p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP; //Peer 发送 Disconnect,我们要对此发 Response
  93. 93 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
  94. 94 L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
  95. 95 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
  96. 96 break;
  97. 97
  98. 98 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
  99. 99 //收到 Peer 传来的数据,当然要把这个数据通过回调送到上层应用去
  100. 100 //pL2CA_DataInd_Cb 中定义了回调,交给上层处理收到的数据
  101. 101 (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
  102. 102 break;
  103. 103
  104. 104 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
  105. 105 /* Make sure we are not in sniff mode */
  106. 106 #if BTM_PWR_MGR_INCLUDED == TRUE
  107. 107 {
  108. 108 tBTM_PM_PWR_MD settings;
  109. 109 settings.mode = BTM_PM_MD_ACTIVE;
  110. 110 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
  111. 111 }
  112. 112 #else
  113. 113 BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
  114. 114 #endif
  115. 115
  116. 116 l2cu_send_peer_disc_req (p_ccb);
  117. 117 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
  118. 118 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
  119. 119 break;
  120. 120
  121. 121 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ //mike mark l2c
  122. 122 //上层将数据发送给下层
  123. 123 //我们的音乐数据就是走这个 case(为什么?看整个函数的参数就明白了)
  124. 124 //首先将数据入队,下面会展开分析这个函数
  125. 125 l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
  126. 126 //最终调用 l2c_link_check_send_pkts 来发送我们的音乐数据包
  127. 127 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
  128. 128 break;
  129. 129
  130. 130 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
  131. 131 p_ccb->chnl_state = CST_CONFIG;
  132. 132 p_ccb->config_done &= ~CFG_DONE_MASK;
  133. 133 l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
  134. 134 l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
  135. 135 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
  136. 136 break;
  137. 137
  138. 138 case L2CEVT_TIMEOUT:
  139. 139 /* Process the monitor/retransmission time-outs in flow control/retrans mode */
  140. 140 if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
  141. 141 l2c_fcr_proc_tout (p_ccb);
  142. 142 break;
  143. 143
  144. 144 case L2CEVT_ACK_TIMEOUT:
  145. 145 l2c_fcr_proc_ack_tout (p_ccb);
  146. 146 break;
  147. 147 }
  148. 148 }



OK,我们下篇将分析数据包入队列的函数。


本文讲的是 Bluedroid 中数据包在 L2CAP 层入队列的一系列函数源码分析。

l2c_enqueue_peer_data 函数的主要作用是将我们的音乐数据包入数据发送队列以及处理 FCR segmentation 和当前 Channel 是否拥堵的检测,我们来详细读一下他的源码。其主要做了这么几件事:1. 组装好 p_buf 并入 当前 CCB 的 xmit_hold_q 队列。2. 检查当前 Channel 拥堵情况。3. 当前 Link 支持 RR,则检查当前ACL数据包所在 Channel 的权限,如果当前 CCB 中的权限高于 RR,则把 RR 中的权限设置为跟 CCB 相同。4. 若 Link 上没有发送窗口,则将 l2cb.check_round_robin 置为TRUE,下一次需要 RR

  1. 1 void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
  2. 2 {
  3. 3 UINT8 *p;
  4. 4
  5. 5 if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
  6. 6 {
  7. 7 p_buf->event = 0;
  8. 8 }
  9. 9 else
  10. 10 {
  11. 11 /* Save the channel ID for faster counting */
  12. 12 p_buf->event = p_ccb->local_cid;
  13. 13
  14. 14 /* Step back to add the L2CAP header */
  15. 15 p_buf->offset -= L2CAP_PKT_OVERHEAD;
  16. 16 p_buf->len += L2CAP_PKT_OVERHEAD;
  17. 17
  18. 18 /* Set the pointer to the beginning of the data */
  19. 19 p = (UINT8 *)(p_buf + 1) + p_buf->offset;
  20. 20
  21. 21 /* Now the L2CAP header */
  22. 22 UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
  23. 23 UINT16_TO_STREAM (p, p_ccb->remote_cid);
  24. 24 }
  25. 25
  26. 26 GKI_enqueue (&p_ccb->xmit_hold_q, p_buf);//真正将组装好的 p_buf 入队
  27. 27
  28. 28 l2cu_check_channel_congestion (p_ccb); //检测当前 Channel 拥堵情况,下面会继续分析这个函数
  29. 29
  30. 30 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
  31. 31 /* if new packet is higher priority than serving ccb and it is not overrun */
  32. 32 if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority ) //当前数据包所在Channel的权限
  33. 33 &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
  34. 34 {
  35. 35 /* send out higher priority packet */
  36. 36 p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;//当前要发送的数据的Channel,设置为ccb_priority,比原来权限要高。
  37. 37 }
  38. 38 #endif
  39. 39
  40. 40 //如果当前 link 上的 link_xmit_quota ==0(link上的发送窗口为0),那么有必要做一次 RR
  41. 41 if (p_ccb->p_lcb->link_xmit_quota == 0)
  42. 42 l2cb.check_round_robin = TRUE;
  43. 43 }
  44. 44
  45. 45 //check if any change in congestion status
  46. 46
  47. 47 void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
  48. 48 {
  49. 49 UINT16 q_count = p_ccb->xmit_hold_q.count; //当前 CCB 中 发送数据队列中数据包的总数
  50. 50
  51. 51 #if (L2CAP_UCD_INCLUDED == TRUE)
  52. 52 if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
  53. 53 {
  54. 54 q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
  55. 55 }
  56. 56 #endif
  57. 57
  58. 58 /* If the CCB queue limit is subject to a quota, check for congestion */
  59. 59
  60. 60 /* if this channel has outgoing traffic */
  61. 61 if ((p_ccb->p_rcb)&&(p_ccb->buff_quota != 0))
  62. 62 {
  63. 63 /* If this channel was congested */
  64. 64 if ( p_ccb->cong_sent ) //当前 Channel 的这个字段为TRUE,是否真正拥堵,我们要继续判断
  65. 65 {
  66. 66 /* If the channel is not congested now, tell the app */
  67. 67 //p_ccb->buff_quota = quota_per_weighted_chnls[HCI_ACL_POOL_ID] * p_ccb->tx_data_rate
  68. 68 //在函数 l2c_link_adjust_chnl_allocation 中配置此值
  69. 69 if (q_count <= (p_ccb->buff_quota / 2))//q_count为 CCB 中的xmit_hold_q
  70. 70 {
  71. 71 p_ccb->cong_sent = FALSE; //当前CCB中的 xmit_hold_q 小于 buffer_quota 值的一半,就认为已经不拥堵了
  72. 72 if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
  73. 73 {
  74. 74 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u",
  75. 75 p_ccb->local_cid, q_count, p_ccb->buff_quota);
  76. 76
  77. 77 /* Prevent recursive calling */
  78. 78 l2cb.is_cong_cback_context = TRUE;
  79. 79 (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE);
  80. 80 l2cb.is_cong_cback_context = FALSE;
  81. 81 }
  82. 82 #if (L2CAP_UCD_INCLUDED == TRUE)
  83. 83 else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )//无连接的 CID
  84. 84 {
  85. 85 if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
  86. 86 {
  87. 87 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
  88. 88 p_ccb->p_lcb->ucd_out_sec_pending_q.count,
  89. 89 p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
  90. 90 p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE );
  91. 91 }
  92. 92 }
  93. 93 #endif
  94. 94 }
  95. 95 }
  96. 96 else
  97. 97 {
  98. 98 /* If this channel was not congested but it is congested now, tell the app */
  99. 99 if (q_count > p_ccb->buff_quota) //此时仍然处于拥堵状态
  100. 100 {
  101. 101 p_ccb->cong_sent = TRUE;
  102. 102 if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
  103. 103 {
  104. 104 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
  105. 105 p_ccb->local_cid, q_count, p_ccb->buff_quota);
  106. 106
  107. 107 (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
  108. 108 }
  109. 109 #if (L2CAP_UCD_INCLUDED == TRUE)
  110. 110 else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
  111. 111 {
  112. 112 if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
  113. 113 {
  114. 114 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
  115. 115 p_ccb->p_lcb->ucd_out_sec_pending_q.count,
  116. 116 p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
  117. 117 p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE );
  118. 118 }
  119. 119 }
  120. 120 #endif
  121. 121 }
  122. 122 }
  123. 123 }
  124. 124 }

本文分析 L2CAP 底层的数据包发送函数。

ACL02

l2c_link_check_send_pkts (tL2C_LCB p_lcb, tL2C_CCB p_ccb, BT_HDR *p_buf) 函数的主要作用是:

  1. 如果 p_buf 不为 null,p_ccb 为null(在signaling状态中,信道是Fixed的) 说明这个 ACL 包是这类 L2CAP 的 command:command reject、configuration request、connection request、connection response、connection response neg、configuration response、configuration reject、disconnect response、echo request、echo response、info request、info response、disconnect request,或者说明这个 ACL 包是 S_frame(Supervisory Frame), 目前 Bluedroid 中只有这两种情况;然后把这个包放到 p_lcb->link_xmit_data_q 中,注意是当前 Link 上的 link_xmit_data_q,跟 CCB 中的 xmit_hold_q 队列是完全不同的两个队列。
  2. 检查 l2cb.is_cong_cback_context 字段,如果为 TRUE,说明当前 Link 拥堵,当前发送过程结束,注意,这时候 ACL 包都已经进入队列了,都在等待发送(即在此调用本函数)。
  3. 若 p_lcb 不为 null 或 p_lcb->link_xmit_quota 不为0:
    • 首先检查 p_lcb 的 partial_segment_being_sent(为TRUE,说明 Segment还没发完,底层来保证,所以当前函数返回)
    • p_lcb 的 link_state 不为 LST_CONNECTED,说明当前 Link 异常,当前函数返回
    • L2C_LINK_CHECK_POWER_MODE 默认是关闭的,关于电源管理的,暂时不分析
    • 步骤 1 分析知道,我们现在发送的是 当前 Link 上的 link_xmit_data_q 队列里的包,对于 BR/EDR来说,如果条件 l2cb.controller_xmit_window 不为 0(否则没有窗口发送数据包了)并且 p_lcb->sent_not_acked < p_lcb->link_xmit_quota(没回复的包一定要小于当前Link最大发送值),不成立,那么在这里轮询,直到有了发送窗口并且 sent_not_acked < link_xmit_quota 才将数据包交给 l2c_link_send_to_lower 函数做进一步处理。
    • 这时,Link 上的数据包已经发送了,若 single_write(断开前最后CCB中的数据处理标志)为false,我们要继续去看看当前 Link 上的每个 Channel 上的 Queue 中有没有数据包,一旦找到一个 p_buf 数据包,就发送(不会循环找,找到了就返回)

OK,上面流程 1 -> 3 是一个单独的流程, 处理一些 L2CAP command 或 Response 的发送情况。

下面偶在来分析另外一个 case,这三个参数全部为非空的情况,这种情况只在 L2CAP 发送 disconnect request 命令时出现(关闭当前 Link 要确保对应上层应用的 CCB 中的数据要发完),主要作用是:

  1. 在函数 l2cu_send_peer_disc_req 中我们看到 CCB 中的数据包直接从 CCB 的 xmit_hold_q 中出队列,设置 ACL 包头就直接交给 l2c_link_check_send_pkts(p_ccb->p_lcb, p_ccb, p_buf2)发送了。
  2. 看到 l2c_link_check_send_pkts 的三个参数均不为 null,说明我们把当前的 CCB 中 xmit_hold_q 的数据包 当成 Link 上的 link_xmit_data_q 发送出去了(相当于优先发送了),single_write 是一个标志位,代表当前数据包由 CCB -> LCB 代替发送。由于判断了 single_write 这个标志位,程序不会再去 CCB 中找数据包了。

还有一种 case 是全部为空的情况,这是触发了 RR 机制所致,正常情况还有发送窗口的情况下,会遍历每个 Link ,然后先发当前 Link上的 Queue里的数据发送出去,然后再发送 CCB 中 Queue 的数据。

OK,这个函数还剩最后一个 case,就是正常情况下,我们听音乐的数据流发送的情况,这是最常见的一种情况,调用形式为 l2c_link_check_send_pkts (p_lcb, NULL, NULL)。

  1. 判断当前 Link 是否拥堵。
  2. 首先看看 Link 上的 link_xmit_data_q 队列有没有数据,有的话发送
  3. 如果 link_xmit_data_q 没有数据,在看看 Link 上的 CCB,通过 CCB 的链表,找到 CCB 上的队列,一直找,直到找到一个 数据包,发送之。
  4. 注意:上层在发送数据包,仅仅是调用一下这个函数,至于 是不是这个数据包,那不一定;反正每次上层调用都会发送一个,上层发下来的包总会发出去的。
  1. 1 void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
  2. 2 {
  3. 3 int xx;
  4. 4 BOOLEAN single_write = FALSE; //最后 Link Disc 用来把 CCB 中的数据包放到 Link 上的队列发,速度加快
  5. 5 L2CAP_TRACE_DEBUG0("mike: in func-- l2c_link_check_send_pkts");
  6. 6 /* Save the channel ID for faster counting */
  7. 7 if (p_buf) //一般数据包都为空,只有发送 L2CAP 发送 command/response 或 发送 S-Frame 才用到
  8. 8 {
  9. 9 if (p_ccb != NULL) //这个 case 就是 当前 Link 即将断开的情况了
  10. 10 {
  11. 11 p_buf->event = p_ccb->local_cid;
  12. 12 single_write = TRUE; //见上面注释
  13. 13 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_buf p_ccb not null");
  14. 14 }
  15. 15 else
  16. 16 p_buf->event = 0;
  17. 17
  18. 18 p_buf->layer_specific = 0;
  19. 19 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_buf->layer_specific=0");
  20. 20 GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf); //把这个数据包放到 当前 link 上的 link_xmit_data_q队列中
  21. 21
  22. 22 if (p_lcb->link_xmit_quota == 0){
  23. 23 l2cb.check_round_robin = TRUE; // 没有发送窗口了,需要 RR 看看有没有别的数据包可以发送的
  24. 24 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_lcb->link_xmit_quota");
  25. 25 }
  26. 26 }
  27. 27
  28. 28 /* If this is called from uncongested callback context break recursive calling.
  29. 29 ** This LCB will be served when receiving number of completed packet event.
  30. 30 */
  31. 31 if (l2cb.is_cong_cback_context){//当前 Link 拥堵了,不发送数据包直接返回,几乎不会发生
  32. 32 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- l2cd.is_cong_cback_context");
  33. 33 return;
  34. 34 }
  35. 35 /* If we are in a scenario where there are not enough buffers for each link to
  36. 36 ** have at least 1, then do a round-robin for all the LCBs
  37. 37 */
  38. 38 if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
  39. 39 {
  40. 40 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- (p_lcb == NULL) ||(p_lcb->link_xmit_quota == 0)");
  41. 41 if (p_lcb == NULL)
  42. 42 p_lcb = l2cb.lcb_pool;
  43. 43 else if (!single_write)
  44. 44 p_lcb++;
  45. 45
  46. 46 /* Loop through, starting at the next */
  47. 47 //哎呀,没有足够发送窗口了,在所有的 Link 上做一次 RR
  48. 48 for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
  49. 49 {
  50. 50 L2CAP_TRACE_DEBUG1("mike: l2c_link_check_send_pkts--Loop through: xx = %d",xx);
  51. 51 /* If controller window is full, nothing to do */
  52. 52 if ( (l2cb.controller_xmit_window == 0
  53. 53 #if (BLE_INCLUDED == TRUE)
  54. 54 && !p_lcb->is_ble_link
  55. 55 #endif
  56. 56 )
  57. 57 #if (BLE_INCLUDED == TRUE)
  58. 58 || (p_lcb->is_ble_link && l2cb.controller_le_xmit_window == 0 )
  59. 59 #endif
  60. 60 || (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
  61. 61 break;
  62. 62
  63. 63 /* Check for wraparound */
  64. 64 if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
  65. 65 p_lcb = &l2cb.lcb_pool[0];
  66. 66
  67. 67 if ( (!p_lcb->in_use)
  68. 68 || (p_lcb->partial_segment_being_sent)
  69. 69 || (p_lcb->link_state != LST_CONNECTED)
  70. 70 || (p_lcb->link_xmit_quota != 0)
  71. 71 || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
  72. 72 continue;
  73. 73
  74. 74 //首先从 当前 Link 上的 link_xmit_data_q 中取出数据包并发送
  75. 75 if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
  76. 76 {
  77. 77 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--if ((p_buf = (BT_HDR*)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)");
  78. 78 l2c_link_send_to_lower (p_lcb, p_buf);
  79. 79 }
  80. 80 else if (single_write) //如果是 single_write 设置为 TRUE,说明数据包 已经在 link_xmit_data_q 发送了,没必要在执行下面的 code 了
  81. 81 {
  82. 82 /* If only doing one write, break out */
  83. 83 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--single write is true then break");
  84. 84 break;
  85. 85 }
  86. 86 //Link 上的 Queue 中没有东西可以发送,查找 CCB 中的 Queue,直到找到一个为止。
  87. 87 else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
  88. 88 {
  89. 89 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--(p_buf=l2cu_get_next_buffer_to_send (p_lcb)) != NULL");
  90. 90 l2c_link_send_to_lower (p_lcb, p_buf);
  91. 91 }
  92. 92 }
  93. 93
  94. 94 /* If we finished without using up our quota, no need for a safety check */
  95. 95 #if (BLE_INCLUDED == TRUE)
  96. 96 if ( ((l2cb.controller_xmit_window > 0 && !p_lcb->is_ble_link) ||
  97. 97 (l2cb.controller_le_xmit_window > 0 && p_lcb->is_ble_link))
  98. 98 && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
  99. 99 #else
  100. 100 if ( (l2cb.controller_xmit_window > 0)
  101. 101 && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
  102. 102
  103. 103 #endif
  104. 104 l2cb.check_round_robin = FALSE;
  105. 105 }
  106. 106 else /* if this is not round-robin service */
  107. 107 {
  108. 108 /* If a partial segment is being sent, can't send anything else */
  109. 109 if ( (p_lcb->partial_segment_being_sent)
  110. 110 || (p_lcb->link_state != LST_CONNECTED)
  111. 111 || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
  112. 112 return;
  113. 113
  114. 114 /* See if we can send anything from the link queue */
  115. 115 #if (BLE_INCLUDED == TRUE)
  116. 116 while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
  117. 117 (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
  118. 118 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
  119. 119 #else
  120. 120 while ( (l2cb.controller_xmit_window != 0)
  121. 121 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
  122. 122 #endif
  123. 123 {
  124. 124 if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)//发送Link上的数据包
  125. 125 break;
  126. 126
  127. 127 if (!l2c_link_send_to_lower (p_lcb, p_buf))
  128. 128 break;
  129. 129 }
  130. 130
  131. 131 if (!single_write)//确保不是在 链路 disc 状态下
  132. 132 {
  133. 133 /* See if we can send anything for any channel */
  134. 134 #if (BLE_INCLUDED == TRUE)
  135. 135 while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
  136. 136 (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
  137. 137 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
  138. 138 #else
  139. 139 while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
  140. 140 #endif
  141. 141 {
  142. 142 if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)//找到一个数据包来发送
  143. 143 break;
  144. 144
  145. 145 if (!l2c_link_send_to_lower (p_lcb, p_buf))
  146. 146 break;
  147. 147 }
  148. 148 }
  149. 149
  150. 150 /* There is a special case where we have readjusted the link quotas and */
  151. 151 /* this link may have sent anything but some other link sent packets so */
  152. 152 /* so we may need a timer to kick off this link's transmissions. */
  153. 153 if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
  154. 154 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--a timer to kick off this link's transmissions");
  155. 155 btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
  156. 156 }
  157. 157
  158. 158 }

最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:

  1. 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
  2. 如果当前数据包 p_buf 的长度大于 ACL 包的最大值,先看看能分成几个分包(为了求的几个窗口能容下),然后窗口值减掉这些分包个数,然后将整个数据包交给 L2C_LINK_SEND_ACL_DATA (大于ACL包长度),具体分包发送由 H5(串口) 部分来负责。
  1. 1 /*******************************************************************************
  2. 2 **
  3. 3 ** Function l2c_link_send_to_lower
  4. 4 **
  5. 5 ** Description This function queues the buffer for HCI transmission
  6. 6 **
  7. 7 ** Returns TRUE for success, FALSE for fail
  8. 8 **
  9. 9 *******************************************************************************/
  10. 10 static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
  11. 11 {
  12. 12 UINT16 num_segs;
  13. 13 UINT16 xmit_window, acl_data_size;
  14. 14 L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower");
  15. 15 #if (BLE_INCLUDED == TRUE)
  16. 16 if ((!p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_acl_pkt_size)) ||
  17. 17 (p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size)))
  18. 18 #else
  19. 19 if (p_buf->len <= btu_cb.hcit_acl_pkt_size) //一般都是走这条路径,p_buf一般不会超过 ACL 长度最大值
  20. 20 #endif
  21. 21 {
  22. 22 if (p_lcb->link_xmit_quota == 0){ // Link 上没有窗口了,controller_xmit_window 窗口还是有的,此时就是 round_roubin_unack了(因为上面的数据已经下来了,必须得发送)
  23. 23 L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower--if (p_lcb->link_xmit_quota == 0)");
  24. 24 l2cb.round_robin_unacked++;
  25. 25 L2CAP_TRACE_DEBUG1("mike: l2c_link_send_to_lower--l2cb.round_robin_unacked=%d",l2cb.round_robin_unacked);
  26. 26 }
  27. 27 p_lcb->sent_not_acked++; //整个 Link 已经发送但是没有回复的数据包个数
  28. 28 L2CAP_TRACE_DEBUG1("mike:l2c_link_send_to_lower--p_lcb->sent_not_acked:",p_lcb->sent_not_acked);
  29. 29 p_buf->layer_specific = 0;
  30. 30
  31. 31 #if (BLE_INCLUDED == TRUE)
  32. 32 if (p_lcb->is_ble_link)
  33. 33 {
  34. 34 l2cb.controller_le_xmit_window--;
  35. 35 L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
  36. 36 }
  37. 37 else
  38. 38 #endif
  39. 39 {
  40. 40 l2cb.controller_xmit_window--; //当前 controller 发送窗口减1
  41. 41 L2CAP_TRACE_DEBUG1("mike:l2c_link_send_to_lower--,l2cb.controller_xmit_window=%d",l2cb.controller_xmit_window);
  42. 42 L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower--L2C_LINK_SEND_ACL_DATA");
  43. 43 L2C_LINK_SEND_ACL_DATA (p_buf); //发送当前这个数据包
  44. 44 }
  45. 45 }
  46. 46 else
  47. 47 {
  48. 48 #if BLE_INCLUDED == TRUE
  49. 49 if (p_lcb->is_ble_link)
  50. 50 {
  51. 51 acl_data_size = btu_cb.hcit_ble_acl_data_size;
  52. 52 xmit_window = l2cb.controller_le_xmit_window;
  53. 53
  54. 54 }
  55. 55 else
  56. 56 #endif
  57. 57 {
  58. 58 acl_data_size = btu_cb.hcit_acl_data_size;//ACL 包额度最大值
  59. 59 xmit_window = l2cb.controller_xmit_window; //controller目前为止的可用窗口
  60. 60 }
  61. 61 num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
  62. 62 L2CAP_TRACE_DEBUG3("mike: l2c_link_send_to_lower-- num_segs:%d, acl_data_size:%d,xmit_window=%d", num_segs,acl_data_size, xmit_window);
  63. 63
  64. 64 /* If doing round-robin, then only 1 segment each time */
  65. 65 if (p_lcb->link_xmit_quota == 0)
  66. 66 {
  67. 67 num_segs = 1;
  68. 68 p_lcb->partial_segment_being_sent = TRUE;
  69. 69 }
  70. 70 else
  71. 71 {
  72. 72 /* Multi-segment packet. Make sure it can fit */
  73. 73 if (num_segs > xmit_window)
  74. 74 {
  75. 75 num_segs = xmit_window;//分包个数比 controller 窗口的个数还多,只能发 controller 个数的包
  76. 76 p_lcb->partial_segment_being_sent = TRUE; //标志位,还有分包,需要继续发送,Btu_task 中有个 Event 就是处理分包的
  77. 77 }
  78. 78
  79. 79 if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
  80. 80 {
  81. 81 num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
  82. 82 p_lcb->partial_segment_being_sent = TRUE;
  83. 83 }
  84. 84 }
  85. 85
  86. 86 p_buf->layer_specific = num_segs;
  87. 87 #if BLE_INCLUDED == TRUE
  88. 88 if (p_lcb->is_ble_link)
  89. 89 {
  90. 90 l2cb.controller_le_xmit_window -= num_segs;
  91. 91
  92. 92 }
  93. 93 else
  94. 94 #endif
  95. 95 l2cb.controller_xmit_window -= num_segs;//分包占用的窗口数
  96. 96
  97. 97 if (p_lcb->link_xmit_quota == 0)
  98. 98 l2cb.round_robin_unacked += num_segs;
  99. 99
  100. 100 p_lcb->sent_not_acked += num_segs;
  101. 101 #if BLE_INCLUDED == TRUE
  102. 102 if (p_lcb->is_ble_link)
  103. 103 {
  104. 104 L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
  105. 105 }
  106. 106 else
  107. 107 #endif
  108. 108 {
  109. 109 L2C_LINK_SEND_ACL_DATA (p_buf);//发送数据包
  110. 110 }
  111. 111 }
  112. 112
  113. 113 #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
  114. 114 #if (BLE_INCLUDED == TRUE)
  115. 115 if (p_lcb->is_ble_link)
  116. 116 {
  117. 117 L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
  118. 118 l2cb.controller_le_xmit_window,
  119. 119 p_lcb->handle,
  120. 120 p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
  121. 121 l2cb.round_robin_quota, l2cb.round_robin_unacked);
  122. 122 }
  123. 123 else
  124. 124 #endif
  125. 125 {
  126. 126 L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
  127. 127 l2cb.controller_xmit_window,
  128. 128 p_lcb->handle,
  129. 129 p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
  130. 130 l2cb.round_robin_quota, l2cb.round_robin_unacked);
  131. 131 }
  132. 132 #endif
  133. 133
  134. 134 return TRUE;
  135. 135 }

l2c_link_send_to_lower 把数据交给了 L2C_LINK_SEND_ACL_DATA,L2C_LINK_SEND_ACL_DATA 其实是 bte_main_hci_send 函数,bte_main_hci_send 函数通过调用 hci 的接口 transmit_buf 来转送数据包。transmit_buf 函数作用比较简单,将此数据包入 tx_q 队列,串口(H5)的守护线程 bt_hc_worker_thread 会从 tx_q 队列中获取数据包,并将其发送。

  1. 1 static int transmit_buf(TRANSAC transac, char *p_buf, int len)
  2. 2 {
  3. 3 utils_enqueue(&tx_q, (void *) transac);
  4. 4
  5. 5 bthc_signal_event(HC_EVENT_TX);
  6. 6
  7. 7 return BT_HC_STATUS_SUCCESS;
  8. 8 }

到这里为止,我们就把 ACL 包整个发送流程分析完了。


ACL 包接收流程

有关 ACL 包接收的过程都是在 btu_task 这个守护线程中处理的。

我们看到 btu_task 处理数据包的过程:

  1. 等待事件,事件到来后,如果是 TASK_MBOX_0_EVT_MASK(是不是 MBOX里的Task),那么从 mbox 中取出这个数据包,并判断是什么类型的 Event。
  2. 如果是 BT_EVT_TO_BTU_HCI_ACL,说明是 ACL 数据,交给 l2cap 来处理。
  3. 如果是 BT_EVT_TO_BTU_L2C_SEG_XMIT,说明是 L2CAP 的分包数据没有发送完,那继续发送分包数据。
  1. 1 //部分 btu_task 源码
  2. 2 ...........
  3. 3 /* Wait for, and process, events */
  4. 4 for (;;)
  5. 5 {
  6. 6 event = GKI_wait (0xFFFF, 0);
  7. 7
  8. 8 if (event & TASK_MBOX_0_EVT_MASK)
  9. 9 {
  10. 10 /* Process all messages in the queue */
  11. 11 while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
  12. 12 {
  13. 13 /* Determine the input message type. */
  14. 14 switch (p_msg->event & BT_EVT_MASK)
  15. 15 {
  16. 16 case BT_EVT_TO_BTU_HCI_ACL:
  17. 17 /* All Acl Data goes to L2CAP */
  18. 18 l2c_rcv_acl_data (p_msg);//我们的 ACL 数据来了,关键分析这个函数
  19. 19 break;
  20. 20
  21. 21 case BT_EVT_TO_BTU_L2C_SEG_XMIT:
  22. 22 /* L2CAP segment transmit complete */
  23. 23 l2c_link_segments_xmitted (p_msg);
  24. 24 break;
  25. 25
  26. 26 case BT_EVT_TO_BTU_HCI_SCO:
  27. 27 #if BTM_SCO_INCLUDED == TRUE
  28. 28 btm_route_sco_data (p_msg);
  29. 29 break;
  30. 30 #endif
  31. 31
  32. 32 case BT_EVT_TO_BTU_HCI_EVT:
  33. 33 btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
  34. 34 GKI_freebuf(p_msg);
  35. 35
  36. 36 ....

l2c_rcv_acl_data 这个函数,处理收到的 ACL 包,下面我们来分析一下 l2c_rcv_acl_data 这个函数:

  1. 在收到的 ACL 包中找出 pkt_type(分包的话要另作处理) 和 handle。

  2. 若此 ACL 包是一个完整的数据包:

    • 首先通过 handle 找到 LCB
    • rcv_cid 大于 L2CAP_BASE_APPL_CID(0x0040),说明是上层应用普通数据包,通过 CID 找到当前包的 CCB。
    • hci_len 长度肯定要大于 L2CAP 头长度,否则肯定头部出错了。
    • 如果 rcv_cid 是 L2CAP_SIGNALLING_CID,说明数据包是 创建和建立 Channel 用的(上层应用传输数据),使用函数 process_l2cap_cmd 来处理。
    • 如果 rcv_cid 是 L2CAP_CONNECTIONLESS_CID 说明是 广播或单播,使用函数 tcs_proc_bcst_msg 处理。
    • 如果 rcv_cid 是 L2CAP_BLE_SIGNALLING_CID 说明是 BLE 的signalling包,交给函数 l2cble_process_sig_cmd 处理。
    • 普通数据包,直接交给 L2CAP 的数据流状态机 l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg) 来处理,找到 L2CEVT_L2CAP_DATA 的这个 case,原来通过回调,将此数据包交给上层了(如 RFCOMM,最终是交给 RFCOMM_BufDataInd函数作进一步处理)

上述数据包,我们仅仅考虑了最普通的数据流,其他的控制数据包有时间在分析。

  1. 1 void l2c_rcv_acl_data (BT_HDR *p_msg)
  2. 2 {
  3. 3 UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
  4. 4 UINT16 handle, hci_len;
  5. 5 UINT8 pkt_type;
  6. 6 tL2C_LCB *p_lcb;
  7. 7 tL2C_CCB *p_ccb = NULL;
  8. 8 UINT16 l2cap_len, rcv_cid, psm;
  9. 9
  10. 10 /* Extract the handle */
  11. 11 STREAM_TO_UINT16 (handle, p);
  12. 12 pkt_type = HCID_GET_EVENT (handle);
  13. 13 handle = HCID_GET_HANDLE (handle);
  14. 14
  15. 15 /* Since the HCI Transport is putting segmented packets back together, we */
  16. 16 /* should never get a valid packet with the type set to "continuation" */
  17. 17 if (pkt_type != L2CAP_PKT_CONTINUE)//数据包一定要是完整的,分包另作处理
  18. 18 {
  19. 19 /* Find the LCB based on the handle */
  20. 20 if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
  21. 21 {
  22. 22 UINT8 cmd_code;
  23. 23
  24. 24 /* There is a slight possibility (specifically with USB) that we get an */
  25. 25 /* L2CAP connection request before we get the HCI connection complete. */
  26. 26 /* So for these types of messages, hold them for up to 2 seconds. */
  27. 27 STREAM_TO_UINT16 (hci_len, p);
  28. 28 STREAM_TO_UINT16 (l2cap_len, p);
  29. 29 STREAM_TO_UINT16 (rcv_cid, p);
  30. 30 STREAM_TO_UINT8 (cmd_code, p);
  31. 31
  32. 32 if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
  33. 33 && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ))
  34. 34 {
  35. 35 L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
  36. 36 handle, p_msg->layer_specific, rcv_cid, cmd_code,
  37. 37 l2cb.rcv_hold_q.count);
  38. 38 p_msg->layer_specific = 2;
  39. 39 GKI_enqueue (&l2cb.rcv_hold_q, p_msg);//添加到队列中,等待 connect 数据包到达,有种可能发生的 case
  40. 40
  41. 41 if (l2cb.rcv_hold_q.count == 1)
  42. 42 btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
  43. 43
  44. 44 return;
  45. 45 }
  46. 46 else
  47. 47 {
  48. 48 L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
  49. 49 handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count);
  50. 50 }
  51. 51 GKI_freebuf (p_msg);
  52. 52 return;
  53. 53 }
  54. 54 }
  55. 55 else
  56. 56 {
  57. 57 L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
  58. 58 GKI_freebuf (p_msg);
  59. 59 return;
  60. 60 }
  61. 61 //下面是我们把 ACL 数据包给部分拆包了,即除掉 L2CAP 的控制部分,还原上层的数据包。
  62. 62 /* Extract the length and update the buffer header */
  63. 63 STREAM_TO_UINT16 (hci_len, p);
  64. 64 p_msg->offset += 4;
  65. 65
  66. 66 #if (L2CAP_HOST_FLOW_CTRL == TRUE)
  67. 67 /* Send ack if we hit the threshold */
  68. 68 if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh)
  69. 69 btu_hcif_send_host_rdy_for_data();
  70. 70 #endif
  71. 71
  72. 72 /* Extract the length and CID */
  73. 73 STREAM_TO_UINT16 (l2cap_len, p);
  74. 74 STREAM_TO_UINT16 (rcv_cid, p);
  75. 75
  76. 76 /* Find the CCB for this CID */
  77. 77 if (rcv_cid >= L2CAP_BASE_APPL_CID)// 说明此 rcv_cid 是上层应用普通数据流的 CID
  78. 78 {
  79. 79 if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
  80. 80 {
  81. 81 L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid);
  82. 82 GKI_freebuf (p_msg);
  83. 83 return;
  84. 84 }
  85. 85 }
  86. 86
  87. 87 if (hci_len >= L2CAP_PKT_OVERHEAD) //数据包长度肯定要大于 Head的值,否则必然是个错包
  88. 88 {
  89. 89 p_msg->len = hci_len - L2CAP_PKT_OVERHEAD;
  90. 90 p_msg->offset += L2CAP_PKT_OVERHEAD;
  91. 91 }
  92. 92 else
  93. 93 {
  94. 94 L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" );
  95. 95 GKI_freebuf (p_msg);
  96. 96 return;
  97. 97 }
  98. 98
  99. 99 if (l2cap_len != p_msg->len) //长度不相等,那数据包传送过程肯定出现了差错,丢包吧
  100. 100 {
  101. 101 L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d Act: %d",
  102. 102 l2cap_len, p_msg->len);
  103. 103
  104. 104 GKI_freebuf (p_msg);
  105. 105 return;
  106. 106 }
  107. 107
  108. 108 /* Send the data through the channel state machine */
  109. 109 if (rcv_cid == L2CAP_SIGNALLING_CID)//控制创建和建立 Channel的 signalling
  110. 110 {
  111. 111 process_l2cap_cmd (p_lcb, p, l2cap_len); //此函数专门处理这个Channel的事件
  112. 112 GKI_freebuf (p_msg);
  113. 113 }
  114. 114 else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
  115. 115 {
  116. 116 /* process_connectionless_data (p_lcb); */
  117. 117 STREAM_TO_UINT16 (psm, p);
  118. 118 L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
  119. 119 #if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
  120. 120 if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS)
  121. 121 {
  122. 122 p_msg->offset += L2CAP_BCST_OVERHEAD;
  123. 123 p_msg->len -= L2CAP_BCST_OVERHEAD;
  124. 124 tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ;
  125. 125 GKI_freebuf (p_msg);
  126. 126 }
  127. 127 else
  128. 128 #endif
  129. 129
  130. 130 #if (L2CAP_UCD_INCLUDED == TRUE)
  131. 131 /* if it is not broadcast, check UCD registration */
  132. 132 if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
  133. 133 {
  134. 134 /* nothing to do */
  135. 135 }
  136. 136 else
  137. 137 #endif
  138. 138 GKI_freebuf (p_msg);
  139. 139 }
  140. 140 #if (BLE_INCLUDED == TRUE)
  141. 141 else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) //LE 设备的专用 Channel
  142. 142 {
  143. 143 l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
  144. 144 GKI_freebuf (p_msg);
  145. 145 }
  146. 146 #endif
  147. 147 #if (L2CAP_NUM_FIXED_CHNLS > 0)
  148. 148 else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
  149. 149 (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
  150. 150 {
  151. 151 /* If no CCB for this channel, allocate one */
  152. 152 if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
  153. 153 {
  154. 154 p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
  155. 155
  156. 156 if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
  157. 157 l2c_fcr_proc_pdu (p_ccb, p_msg);
  158. 158 else
  159. 159 (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
  160. 160 }
  161. 161 else
  162. 162 GKI_freebuf (p_msg);
  163. 163 }
  164. 164 #endif
  165. 165
  166. 166 else
  167. 167 {
  168. 168 if (p_ccb == NULL)
  169. 169 GKI_freebuf (p_msg);
  170. 170 else
  171. 171 {
  172. 172 /* Basic mode packets go straight to the state machine */
  173. 173 if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
  174. 174 //普通的数据流都是经过这条通路的,下面这个函数觉得很熟悉吧,因为在发送数据包的时候也调用了他。
  175. 175 l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
  176. 176 else
  177. 177 {
  178. 178 /* eRTM or streaming mode, so we need to validate states first */
  179. 179 if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
  180. 180 l2c_fcr_proc_pdu (p_ccb, p_msg);
  181. 181 else
  182. 182 GKI_freebuf (p_msg);
  183. 183 }
  184. 184 }
  185. 185 }
  186. 186 }

下面我们分析一个 Event--number-of-completed-packets,是由函数 l2c_link_process_num_completed_pkts 处理。这个 event 将会更新我们 LCB 上的数据包数量。

我们追踪这个函数的调用链:

btu_task的一个 BT_EVT_TO_BTU_HCI_EVT case --> btu_hcif_process_event 的一个 HCI_NUM_COMPL_DATA_PKTS_EVT case --> l2c_link_process_num_completed_pkts

通过这个调用链,我们知道处理事件或数据流都在 btu_task 中进行。

l2c_link_process_num_completed_pkts这个函数都做了些什么呢?我们来深入代码了解一下整个过程。

  1. 通过 num_sent 来更新数据 controller_xmit_window,sent_not_acked。
  2. 既然又多了 credits(Snoop中的),那么自然调用 l2c_link_check_send_pkts 去找更多的包发送下去。
  3. l2c_link_process_num_completed_pkts 和 l2c_link_check_send_pkts 形成了一个递归式的调用,l2c_link_check_send_pkts 会产生 process num complete 这个event,l2c_link_process_num_completed_pkts找到 Link后在让 l2c_link_check_send_pkts 发包。
  1. 1 void l2c_link_process_num_completed_pkts (UINT8 *p)
  2. 2 {
  3. 3 UINT8 num_handles, xx;
  4. 4 UINT16 handle;
  5. 5 UINT16 num_sent; //已经发下去的数据,这个数据要更新controller_xmit_window
  6. 6 tL2C_LCB *p_lcb;
  7. 7
  8. 8 L2CAP_TRACE_DEBUG0("mike: l2c_link_process_num_completed_pkts");
  9. 9 STREAM_TO_UINT8 (num_handles, p);
  10. 10 L2CAP_TRACE_DEBUG1("mike: l2c_link_process_num_completed_pkts--number_handles:%d", num_handles);
  11. 11 for (xx = 0; xx < num_handles; xx++)//handle 对应着每条逻辑链路(Link)
  12. 12 {
  13. 13 STREAM_TO_UINT16 (handle, p);
  14. 14 STREAM_TO_UINT16 (num_sent, p);
  15. 15
  16. 16 p_lcb = l2cu_find_lcb_by_handle (handle);
  17. 17
  18. 18 /* Callback for number of completed packet event */
  19. 19 /* Originally designed for [3DSG] */
  20. 20 if((p_lcb != NULL) && (p_lcb->p_nocp_cb))
  21. 21 {
  22. 22 L2CAP_TRACE_DEBUG0 ("L2CAP - calling NoCP callback");
  23. 23 (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr);
  24. 24 }
  25. 25
  26. 26 if (p_lcb)
  27. 27 {
  28. 28 #if (BLE_INCLUDED == TRUE)
  29. 29 if (p_lcb->is_ble_link)
  30. 30 {
  31. 31 l2cb.controller_le_xmit_window += num_sent;
  32. 32 }
  33. 33 else
  34. 34 #endif
  35. 35 {
  36. 36 /* Maintain the total window to the controller */
  37. 37 l2cb.controller_xmit_window += num_sent;
  38. 38 }
  39. 39 /* If doing round-robin, adjust communal counts */
  40. 40 if (p_lcb->link_xmit_quota == 0)
  41. 41 {
  42. 42 /* Don't go negative */
  43. 43 if (l2cb.round_robin_unacked > num_sent)
  44. 44 l2cb.round_robin_unacked -= num_sent;
  45. 45 else
  46. 46 l2cb.round_robin_unacked = 0;
  47. 47 }
  48. 48
  49. 49 /* Don't go negative */
  50. 50 if (p_lcb->sent_not_acked > num_sent)
  51. 51 p_lcb->sent_not_acked -= num_sent; //更新
  52. 52 else
  53. 53 p_lcb->sent_not_acked = 0;
  54. 54
  55. 55 l2c_link_check_send_pkts (p_lcb, NULL, NULL);
  56. 56
  57. 57 L2CAP_TRACE_DEBUG1("mike:l2c_link_process_num_completed_pkts--l2cb.controller_xmit_window=%d",l2cb.controller_xmit_window);
  58. 58
  59. 59 /* If we were doing round-robin for low priority links, check 'em */
  60. 60 if ( (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
  61. 61 && (l2cb.check_round_robin)
  62. 62 && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
  63. 63 {
  64. 64 l2c_link_check_send_pkts (NULL, NULL, NULL);
  65. 65 }
  66. 66 }
  67. 67
  68. 68 #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
  69. 69 if (p_lcb)
  70. 70 {
  71. 71 #if (BLE_INCLUDED == TRUE)
  72. 72 if (p_lcb->is_ble_link)
  73. 73 {
  74. 74 L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
  75. 75 l2cb.controller_le_xmit_window,
  76. 76 p_lcb->handle, p_lcb->sent_not_acked,
  77. 77 l2cb.check_round_robin, l2cb.round_robin_unacked);
  78. 78 }
  79. 79 else
  80. 80 #endif
  81. 81 {
  82. 82 L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
  83. 83 l2cb.controller_xmit_window,
  84. 84 p_lcb->handle, p_lcb->sent_not_acked,
  85. 85 l2cb.check_round_robin, l2cb.round_robin_unacked);
  86. 86
  87. 87 }
  88. 88 }
  89. 89 else
  90. 90 {
  91. 91 #if (BLE_INCLUDED == TRUE)
  92. 92 L2CAP_TRACE_DEBUG5 ("TotalWin=%d LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d",
  93. 93 l2cb.controller_xmit_window,
  94. 94 l2cb.controller_le_xmit_window,
  95. 95 handle,
  96. 96 l2cb.check_round_robin, l2cb.round_robin_unacked);
  97. 97 #else
  98. 98 L2CAP_TRACE_DEBUG4 ("TotalWin=%d Handle=0x%x RRCheck=%d RRUnack=%d",
  99. 99 l2cb.controller_xmit_window,
  100. 100 handle,
  101. 101 l2cb.check_round_robin, l2cb.round_robin_unacked);
  102. 102 #endif
  103. 103 }
  104. 104 #endif
  105. 105 }
  106. 106
  107. 107 #if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
  108. 108 /* only full stack can enable sleep mode */
  109. 109 btu_check_bt_sleep ();
  110. 110 #endif
  111. 111 }

到此为止,我们已经把普通 ACL 包发送和接收部分源码分析完了。后续有时间会继续分析控制类型的ACL包,以及ACL链路建立的流程。


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/192133
推荐阅读
相关标签
  

闽ICP备14008679号