ACL 链路,发送/接收ACL 包。 Mike 跟大家一起来分析 ACL 包发送/接收流程,以及涉及到的重要 command/event。ACL 链路在 Bluetooth 中非常重要,一些重要的应用如 A2DP, 基于 RFCOMM 的应用,BNEP等都要建立
此API继续往下走, 我仅分析了正常数据流的走向(暂时没有考虑别的情况)。ACL包发送下面的图(点击大图)是各种应用层使用 L2CAP 的 API:L2CA_DataWrite 发送数据流的过程,
我们假设一个听音乐的场景,Mike跟大家一起分析音乐数据流 AVDTP 以下层的传送。在 AVDTP 中,所有的功能想发送 Data,必须调用 avdt_ad_write_req 这个函数,Mike 就从这个函数入手分析。
//当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 这个函数做的事情主要有:
/返回的数据跟上面的 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);
下面我们来看看 L2CAP 层的处理
我们的音乐数据,通过 L2CAP 入口函数 l2c_data_write 的层层“考验”,已经顺利进入到 L2CAP 里了,下面我们来看看 L2CAP 层具体是怎么处理数据的。
首先我们进入了 L2CAP 层的状态机。
void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
2 {
3 switch (p_ccb->chnl_state)
4 {
5 case CST_CLOSED:
6 l2c_csm_closed (p_ccb, event, p_data);
7 break;
8
9 case CST_ORIG_W4_SEC_COMP:
10 l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
11 break;
12
13 case CST_TERM_W4_SEC_COMP:
14 l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
15 break;
16
17 case CST_W4_L2CAP_CONNECT_RSP:
18 l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
19 break;
20
21 case CST_W4_L2CA_CONNECT_RSP:
22 l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
23 break;
24
25 case CST_CONFIG:
26 l2c_csm_config (p_ccb, event, p_data);
27 break;
28
29 case CST_OPEN:
30 l2c_csm_open (p_ccb, event, p_data);
31 break;
32
33 case CST_W4_L2CAP_DISCONNECT_RSP:
34 l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
35 break;
36
37 case CST_W4_L2CA_DISCONNECT_RSP:
38 l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
39 break;
40
41 default:
42 break;
43 }
44 }
具体的 Channel 状态信息如下
1 typedef enum
2 {
3 CST_CLOSED, /* Channel is in clodes state */
4 CST_ORIG_W4_SEC_COMP, /* Originator waits security clearence */
5 CST_TERM_W4_SEC_COMP, /* Acceptor waits security clearence */
6 CST_W4_L2CAP_CONNECT_RSP, /* Waiting for peer conenct response */
7 CST_W4_L2CA_CONNECT_RSP, /* Waiting for upper layer connect rsp */
8 CST_CONFIG, /* Negotiating configuration */
9 CST_OPEN, /* Data transfer state */
10 CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */
11 CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */
12 } tL2C_CHNL_STATE;
l2c_csm_execute
函数通过 p_ccb 中的 chnl_state 字段,来确定接下来数据包的走向。如下图所示:
点击看大图
CST_CLOSED 状态:这个 case 处理 Channel 处于 CLOSED 状态的事件。这个状态仅仅存在于 L2CAP 的 Link 初始建立过程中。
如果发现事件是 L2CEVT_LP_DISCONNECT_IND,则当前 Link 已经断开,则释放当前 Channel的 ccb;
L2CEVT_L2CA_DISCONNECT_REQ,上层想断开链接,会使用这个 Event来处理。
CST_ORIG_W4_SEC_COMP 状态:Originator(我的理解是 发起 link 建立的应用)等待 security 的间隙,这个间隙需要处理的事件。跟 CST_CLOSED 差不多,源码很容易读,这里不再次做分析。注意,如果是 L2CEVT_SEC_COMP 事件(跟安全相关),会把 p_ccb->chnl_state 置为 CST_W4_L2CAP_CONNECT_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 这个函数发送数据包。下面我们会继续分析这两个函数。
//l2c_csm_open 处理 Channel 处于 OPEN 状态下的各种 Event
2 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
3 {
4 UINT16 local_cid = p_ccb->local_cid;
5 tL2CAP_CFG_INFO *p_cfg;
6 tL2C_CHNL_STATE tempstate;
7 UINT8 tempcfgdone;
8 UINT8 cfg_result;
9
10 #if (BT_TRACE_VERBOSE == TRUE)
11 L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
12 #else
13 L2CAP_TRACE_EVENT1 ("L2CAP - st: OPEN evt: %d", event);
14 #endif
15
16 #if (L2CAP_UCD_INCLUDED == TRUE) //默认 UCD 是关闭的
17 if ( local_cid == L2CAP_CONNECTIONLESS_CID )
18 {
19 /* check if this event can be processed by UCD */
20 if ( l2c_ucd_process_event (p_ccb, event, p_data) )
21 {
22 /* The event is processed by UCD state machine */
23 return;
24 }
25 }
26 #endif
27
28 switch (event)
29 {
30 case L2CEVT_LP_DISCONNECT_IND: //Link 都断开连接了,自然 Channel也没有存在的必要了,各种清除 CCB 的工作
31 L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
32 l2cu_release_ccb (p_ccb);//释放 当前的 CCB
33 if (p_ccb->p_rcb)
34 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
35 break;
36
37 case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */
38 /* Tell upper layer. If service guaranteed, then clear the channel */
39 if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
40 (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
41 break;
42
43 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
44 p_cfg = (tL2CAP_CFG_INFO *)p_data;
45
46 tempstate = p_ccb->chnl_state;
47 tempcfgdone = p_ccb->config_done;
48 p_ccb->chnl_state = CST_CONFIG; //如果数据流中的数据是 L2CEVT_L2CAP_CONFIG_REQ,当然要转到 CST_CONFIG中继续处理
49 p_ccb->config_done &= ~CFG_DONE_MASK;
50 //启动一个 timer ,一段时间后,查看 cfg 的状态
51 //如果配置处于 L2CAP_PEER_CFG_UNACCEPTABLE,继续尝试配置
52 //如果配置处于断开状态,那当前 Channel 直接断开连接。
53 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
54
55 if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
56 {
57 (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
58 }
59
60 /* Error in config parameters: reset state and config flag */
61 else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
62 {
63 btu_stop_timer(&p_ccb->timer_entry);
64 p_ccb->chnl_state = tempstate;
65 p_ccb->config_done = tempcfgdone;
66 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
67 }
68 else /* L2CAP_PEER_CFG_DISCONNECT */
69 {
70 /* Disconnect if channels are incompatible
71 * Note this should not occur if reconfigure
72 * since this should have never passed original config.
73 */
74 l2cu_disconnect_chnl (p_ccb);
75 }
76 break;
77
78 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
79 // btla-specific ++
80 /* Make sure we are not in sniff mode */
81 #if BTM_PWR_MGR_INCLUDED == TRUE
82 {
83 tBTM_PM_PWR_MD settings;
84 settings.mode = BTM_PM_MD_ACTIVE;
85 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
86 }
87 #else
88 BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
89 #endif
90 // btla-specific --
91
92 p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP; //Peer 发送 Disconnect,我们要对此发 Response
93 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
94 L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
95 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
96 break;
97
98 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
99 //收到 Peer 传来的数据,当然要把这个数据通过回调送到上层应用去
100 //pL2CA_DataInd_Cb 中定义了回调,交给上层处理收到的数据
101 (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
102 break;
103
104 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
105 /* Make sure we are not in sniff mode */
106 #if BTM_PWR_MGR_INCLUDED == TRUE
107 {
108 tBTM_PM_PWR_MD settings;
109 settings.mode = BTM_PM_MD_ACTIVE;
110 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
111 }
112 #else
113 BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
114 #endif
115
116 l2cu_send_peer_disc_req (p_ccb);
117 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
118 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
119 break;
120
121 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ //mike mark l2c
122 //上层将数据发送给下层
123 //我们的音乐数据就是走这个 case(为什么?看整个函数的参数就明白了)
124 //首先将数据入队,下面会展开分析这个函数
125 l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
126 //最终调用 l2c_link_check_send_pkts 来发送我们的音乐数据包
127 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
128 break;
129
130 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
131 p_ccb->chnl_state = CST_CONFIG;
132 p_ccb->config_done &= ~CFG_DONE_MASK;
133 l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
134 l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
135 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
136 break;
137
138 case L2CEVT_TIMEOUT:
139 /* Process the monitor/retransmission time-outs in flow control/retrans mode */
140 if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
141 l2c_fcr_proc_tout (p_ccb);
142 break;
143
144 case L2CEVT_ACK_TIMEOUT:
145 l2c_fcr_proc_ack_tout (p_ccb);
146 break;
147 }
148 }
OK,我们下面将分析数据包入队列的函数。
void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
2 {
3 UINT8 *p;
4
5 if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
6 {
7 p_buf->event = 0;
8 }
9 else
10 {
11 /* Save the channel ID for faster counting */
12 p_buf->event = p_ccb->local_cid;
13
14 /* Step back to add the L2CAP header */
15 p_buf->offset -= L2CAP_PKT_OVERHEAD;
16 p_buf->len += L2CAP_PKT_OVERHEAD;
17
18 /* Set the pointer to the beginning of the data */
19 p = (UINT8 *)(p_buf + 1) + p_buf->offset;
20
21 /* Now the L2CAP header */
22 UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
23 UINT16_TO_STREAM (p, p_ccb->remote_cid);
24 }
25
26 GKI_enqueue (&p_ccb->xmit_hold_q, p_buf);//真正将组装好的 p_buf 入队
27
28 l2cu_check_channel_congestion (p_ccb); //检测当前 Channel 拥堵情况,下面会继续分析这个函数
29
30 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
31 /* if new packet is higher priority than serving ccb and it is not overrun */
32 if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority ) //当前数据包所在Channel的权限
33 &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
34 {
35 /* send out higher priority packet */
36 p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;//当前要发送的数据的Channel,设置为ccb_priority,比原来权限要高。
37 }
38 #endif
39
40 //如果当前 link 上的 link_xmit_quota ==0(link上的发送窗口为0),那么有必要做一次 RR
41 if (p_ccb->p_lcb->link_xmit_quota == 0)
42 l2cb.check_round_robin = TRUE;
43 }
44
45 //check if any change in congestion status
46
47 void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
48 {
49 UINT16 q_count = p_ccb->xmit_hold_q.count; //当前 CCB 中 发送数据队列中数据包的总数
50
51 #if (L2CAP_UCD_INCLUDED == TRUE)
52 if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
53 {
54 q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
55 }
56 #endif
57
58 /* If the CCB queue limit is subject to a quota, check for congestion */
59
60 /* if this channel has outgoing traffic */
61 if ((p_ccb->p_rcb)&&(p_ccb->buff_quota != 0))
62 {
63 /* If this channel was congested */
64 if ( p_ccb->cong_sent ) //当前 Channel 的这个字段为TRUE,是否真正拥堵,我们要继续判断
65 {
66 /* If the channel is not congested now, tell the app */
67 //p_ccb->buff_quota = quota_per_weighted_chnls[HCI_ACL_POOL_ID] * p_ccb->tx_data_rate
68 //在函数 l2c_link_adjust_chnl_allocation 中配置此值
69 if (q_count <= (p_ccb->buff_quota / 2))//q_count为 CCB 中的xmit_hold_q
70 {
71 p_ccb->cong_sent = FALSE; //当前CCB中的 xmit_hold_q 小于 buffer_quota 值的一半,就认为已经不拥堵了
72 if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
73 {
74 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u",
75 p_ccb->local_cid, q_count, p_ccb->buff_quota);
76
77 /* Prevent recursive calling */
78 l2cb.is_cong_cback_context = TRUE;
79 (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE);
80 l2cb.is_cong_cback_context = FALSE;
81 }
82 #if (L2CAP_UCD_INCLUDED == TRUE)
83 else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )//无连接的 CID
84 {
85 if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
86 {
87 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
88 p_ccb->p_lcb->ucd_out_sec_pending_q.count,
89 p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
90 p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE );
91 }
92 }
93 #endif
94 }
95 }
96 else
97 {
98 /* If this channel was not congested but it is congested now, tell the app */
99 if (q_count > p_ccb->buff_quota) //此时仍然处于拥堵状态
100 {
101 p_ccb->cong_sent = TRUE;
102 if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
103 {
104 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
105 p_ccb->local_cid, q_count, p_ccb->buff_quota);
106
107 (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
108 }
109 #if (L2CAP_UCD_INCLUDED == TRUE)
110 else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
111 {
112 if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
113 {
114 L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
115 p_ccb->p_lcb->ucd_out_sec_pending_q.count,
116 p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
117 p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE );
118 }
119 }
120 #endif
121 }
122 }
123 }
124 }
l2c_link_check_send_pkts (tL2C_LCB p_lcb, tL2C_CCB p_ccb, BT_HDR *p_buf)函数的主要作用是:
OK,上面流程 1 -> 3 是一个单独的流程, 处理一些 L2CAP command 或 Response 的发送情况。
下面偶在来分析另外一个 case,这三个参数全部为非空的情况,这种情况只在 L2CAP 发送 disconnect request 命令时出现(关闭当前 Link 要确保对应上层应用的 CCB 中的数据要发完),主要作用是:
还有一种 case 是全部为空的情况,这是触发了 RR 机制所致,正常情况还有发送窗口的情况下,会遍历每个 Link ,然后先发当前 Link上的 Queue里的数据发送出去,然后再发送 CCB 中 Queue 的数据。
OK,这个函数还剩最后一个 case,就是正常情况下,我们听音乐的数据流发送的情况,这是最常见的一种情况,调用形式为 l2c_link_check_send_pkts (p_lcb, NULL, NULL)。
void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
2 {
3 int xx;
4 BOOLEAN single_write = FALSE; //最后 Link Disc 用来把 CCB 中的数据包放到 Link 上的队列发,速度加快
5 L2CAP_TRACE_DEBUG0("mike: in func-- l2c_link_check_send_pkts");
6 /* Save the channel ID for faster counting */
7 if (p_buf) //一般数据包都为空,只有发送 L2CAP 发送 command/response 或 发送 S-Frame 才用到
8 {
9 if (p_ccb != NULL) //这个 case 就是 当前 Link 即将断开的情况了
10 {
11 p_buf->event = p_ccb->local_cid;
12 single_write = TRUE; //见上面注释
13 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_buf p_ccb not null");
14 }
15 else
16 p_buf->event = 0;
17
18 p_buf->layer_specific = 0;
19 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_buf->layer_specific=0");
20 GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf); //把这个数据包放到 当前 link 上的 link_xmit_data_q队列中
21
22 if (p_lcb->link_xmit_quota == 0){
23 l2cb.check_round_robin = TRUE; // 没有发送窗口了,需要 RR 看看有没有别的数据包可以发送的
24 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_lcb->link_xmit_quota");
25 }
26 }
27
28 /* If this is called from uncongested callback context break recursive calling.
29 ** This LCB will be served when receiving number of completed packet event.
30 */
31 if (l2cb.is_cong_cback_context){//当前 Link 拥堵了,不发送数据包直接返回,几乎不会发生
32 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- l2cd.is_cong_cback_context");
33 return;
34 }
35 /* If we are in a scenario where there are not enough buffers for each link to
36 ** have at least 1, then do a round-robin for all the LCBs
37 */
38 if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
39 {
40 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- (p_lcb == NULL) ||(p_lcb->link_xmit_quota == 0)");
41 if (p_lcb == NULL)
42 p_lcb = l2cb.lcb_pool;
43 else if (!single_write)
44 p_lcb++;
45
46 /* Loop through, starting at the next */
47 //哎呀,没有足够发送窗口了,在所有的 Link 上做一次 RR
48 for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
49 {
50 L2CAP_TRACE_DEBUG1("mike: l2c_link_check_send_pkts--Loop through: xx = %d",xx);
51 /* If controller window is full, nothing to do */
52 if ( (l2cb.controller_xmit_window == 0
53 #if (BLE_INCLUDED == TRUE)
54 && !p_lcb->is_ble_link
55 #endif
56 )
57 #if (BLE_INCLUDED == TRUE)
58 || (p_lcb->is_ble_link && l2cb.controller_le_xmit_window == 0 )
59 #endif
60 || (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
61 break;
62
63 /* Check for wraparound */
64 if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
65 p_lcb = &l2cb.lcb_pool[0];
66
67 if ( (!p_lcb->in_use)
68 || (p_lcb->partial_segment_being_sent)
69 || (p_lcb->link_state != LST_CONNECTED)
70 || (p_lcb->link_xmit_quota != 0)
71 || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
72 continue;
73
74 //首先从 当前 Link 上的 link_xmit_data_q 中取出数据包并发送
75 if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
76 {
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 l2c_link_send_to_lower (p_lcb, p_buf);
79 }
80 else if (single_write) //如果是 single_write 设置为 TRUE,说明数据包 已经在 link_xmit_data_q 发送了,没必要在执行下面的 code 了
81 {
82 /* If only doing one write, break out */
83 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--single write is true then break");
84 break;
85 }
86 //Link 上的 Queue 中没有东西可以发送,查找 CCB 中的 Queue,直到找到一个为止。
87 else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
88 {
89 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--(p_buf=l2cu_get_next_buffer_to_send (p_lcb)) != NULL");
90 l2c_link_send_to_lower (p_lcb, p_buf);
91 }
92 }
93
94 /* If we finished without using up our quota, no need for a safety check */
95 #if (BLE_INCLUDED == TRUE)
96 if ( ((l2cb.controller_xmit_window > 0 && !p_lcb->is_ble_link) ||
97 (l2cb.controller_le_xmit_window > 0 && p_lcb->is_ble_link))
98 && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
99 #else
100 if ( (l2cb.controller_xmit_window > 0)
101 && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
102
103 #endif
104 l2cb.check_round_robin = FALSE;
105 }
106 else /* if this is not round-robin service */
107 {
108 /* If a partial segment is being sent, can't send anything else */
109 if ( (p_lcb->partial_segment_being_sent)
110 || (p_lcb->link_state != LST_CONNECTED)
111 || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
112 return;
113
114 /* See if we can send anything from the link queue */
115 #if (BLE_INCLUDED == TRUE)
116 while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
117 (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
118 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
119 #else
120 while ( (l2cb.controller_xmit_window != 0)
121 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
122 #endif
123 {
124 if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)//发送Link上的数据包
125 break;
126
127 if (!l2c_link_send_to_lower (p_lcb, p_buf))
128 break;
129 }
130
131 if (!single_write)//确保不是在 链路 disc 状态下
132 {
133 /* See if we can send anything for any channel */
134 #if (BLE_INCLUDED == TRUE)
135 while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
136 (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
137 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
138 #else
139 while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
140 #endif
141 {
142 if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)//找到一个数据包来发送
143 break;
144
145 if (!l2c_link_send_to_lower (p_lcb, p_buf))
146 break;
147 }
148 }
149
150 /* There is a special case where we have readjusted the link quotas and */
151 /* this link may have sent anything but some other link sent packets so */
152 /* so we may need a timer to kick off this link's transmissions. */
153 if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
154 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--a timer to kick off this link's transmissions");
155 btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
156 }
157
158 }
最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:
/*******************************************************************************
2 **
3 ** Function l2c_link_send_to_lower
4 **
5 ** Description This function queues the buffer for HCI transmission
6 **
7 ** Returns TRUE for success, FALSE for fail
8 **
9 *******************************************************************************/
10 static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
11 {
12 UINT16 num_segs;
13 UINT16 xmit_window, acl_data_size;
14 L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower");
15 #if (BLE_INCLUDED == TRUE)
16 if ((!p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_acl_pkt_size)) ||
17 (p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size)))
18 #else
19 if (p_buf->len <= btu_cb.hcit_acl_pkt_size) //一般都是走这条路径,p_buf一般不会超过 ACL 长度最大值
20 #endif
21 {
22 if (p_lcb->link_xmit_quota == 0){ // Link 上没有窗口了,controller_xmit_window 窗口还是有的,此时就是 round_roubin_unack了(因为上面的数据已经下来了,必须得发送)
23 L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower--if (p_lcb->link_xmit_quota == 0)");
24 l2cb.round_robin_unacked++;
25 L2CAP_TRACE_DEBUG1("mike: l2c_link_send_to_lower--l2cb.round_robin_unacked=%d",l2cb.round_robin_unacked);
26 }
27 p_lcb->sent_not_acked++; //整个 Link 已经发送但是没有回复的数据包个数
28 L2CAP_TRACE_DEBUG1("mike:l2c_link_send_to_lower--p_lcb->sent_not_acked:",p_lcb->sent_not_acked);
29 p_buf->layer_specific = 0;
30
31 #if (BLE_INCLUDED == TRUE)
32 if (p_lcb->is_ble_link)
33 {
34 l2cb.controller_le_xmit_window--;
35 L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
36 }
37 else
38 #endif
39 {
40 l2cb.controller_xmit_window--; //当前 controller 发送窗口减1
41 L2CAP_TRACE_DEBUG1("mike:l2c_link_send_to_lower--,l2cb.controller_xmit_window=%d",l2cb.controller_xmit_window);
42 L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower--L2C_LINK_SEND_ACL_DATA");
43 L2C_LINK_SEND_ACL_DATA (p_buf); //发送当前这个数据包
44 }
45 }
46 else
47 {
48 #if BLE_INCLUDED == TRUE
49 if (p_lcb->is_ble_link)
50 {
51 acl_data_size = btu_cb.hcit_ble_acl_data_size;
52 xmit_window = l2cb.controller_le_xmit_window;
53
54 }
55 else
56 #endif
57 {
58 acl_data_size = btu_cb.hcit_acl_data_size;//ACL 包额度最大值
59 xmit_window = l2cb.controller_xmit_window; //controller目前为止的可用窗口
60 }
61 num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
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
64 /* If doing round-robin, then only 1 segment each time */
65 if (p_lcb->link_xmit_quota == 0)
66 {
67 num_segs = 1;
68 p_lcb->partial_segment_being_sent = TRUE;
69 }
70 else
71 {
72 /* Multi-segment packet. Make sure it can fit */
73 if (num_segs > xmit_window)
74 {
75 num_segs = xmit_window;//分包个数比 controller 窗口的个数还多,只能发 controller 个数的包
76 p_lcb->partial_segment_being_sent = TRUE; //标志位,还有分包,需要继续发送,Btu_task 中有个 Event 就是处理分包的
77 }
78
79 if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
80 {
81 num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
82 p_lcb->partial_segment_being_sent = TRUE;
83 }
84 }
85
86 p_buf->layer_specific = num_segs;
87 #if BLE_INCLUDED == TRUE
88 if (p_lcb->is_ble_link)
89 {
90 l2cb.controller_le_xmit_window -= num_segs;
91
92 }
93 else
94 #endif
95 l2cb.controller_xmit_window -= num_segs;//分包占用的窗口数
96
97 if (p_lcb->link_xmit_quota == 0)
98 l2cb.round_robin_unacked += num_segs;
99
100 p_lcb->sent_not_acked += num_segs;
101 #if BLE_INCLUDED == TRUE
102 if (p_lcb->is_ble_link)
103 {
104 L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
105 }
106 else
107 #endif
108 {
109 L2C_LINK_SEND_ACL_DATA (p_buf);//发送数据包
110 }
111 }
112
113 #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
114 #if (BLE_INCLUDED == TRUE)
115 if (p_lcb->is_ble_link)
116 {
117 L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
118 l2cb.controller_le_xmit_window,
119 p_lcb->handle,
120 p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
121 l2cb.round_robin_quota, l2cb.round_robin_unacked);
122 }
123 else
124 #endif
125 {
126 L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
127 l2cb.controller_xmit_window,
128 p_lcb->handle,
129 p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
130 l2cb.round_robin_quota, l2cb.round_robin_unacked);
131 }
132 #endif
133
134 return TRUE;
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 队列中获取数据包,并将其发送。
static int transmit_buf(TRANSAC transac, char *p_buf, int len)
2 {
3 utils_enqueue(&tx_q, (void *) transac);
4
5 bthc_signal_event(HC_EVENT_TX);
6
7 return BT_HC_STATUS_SUCCESS;
8 }