ACL 链路在 Bluetooth 中非常重要,一些重要的应用如 A2DP, 基于 RFCOMM 的应用,BNEP等都要建立 ACL 链路,发送/接收ACL 包。跟大家一起来分析 ACL 包发送/接收流程,以及涉及到的重要 command/event。
(一)
ACL包发送
下面的图是各种应用层使用 L2CAP 的 API:L2CA_DataWrite 发送数据流的过程,此API继续往下走,我仅分析了正常数据流的走向(暂时没有考虑别的情况)。
应用层数据到 L2CAP 的入口
我们假设一个听音乐的场景,我跟大家一起分析音乐数据流 AVDTP 以下层的传送。
在 AVDTP 中,所有的功能想发送 Data,必须调用 avdt_ad_write_req 这个函数,我们就从这个函数入手分析。
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 这个函数做的事情主要有:
- 根据参数 cid(Channel ID) 找到 对应的 ccb(Channel Control Block), 找不到返回 L2CAP_DW_FAILED
- 如果测试者 打开 TESTER 这个宏,发送任意数据,当数据大小 大于 MTU 最大值,也会返回 L2CAP_DW_FAILED
- 通过检查 p_ccb->cong_sent 字段,TRUE,则说明当前 Channel 已经拥挤,此时L2CAP的这个Channel不在接收数据,返回 L2CAP_DW_FAILED
- 以上三个条件都通过,说明数据可发送,将数据通过 l2c_csm_execute 继续处理。进入 l2c_csm_execute 函数,标志着这笔数据已经成功交给 l2CAP 来处理,与上层已经没有关系了。
- 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的处理函数。
L2CAP层的处理
我们的音乐数据,通过 L2CAP 入口函数 l2c_data_write 的层层“考验”,已经顺利进入到 L2CAP 里了,下面我们来看看 L2CAP 层具体是怎么处理数据的。
首先我们进入了 L2CAP 层的状态机。
1 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_LP_CONNECT_CFM,则置 p_ccb->chnl_state 为 CST_ORIG_W4_SEC_COMP 状态,下面会接着介绍这个。
- 如果是 L2CEVT_LP_CONNECT_CFM_NEG 则说明当前 Link 失败,
- 如果是 L2CEVT_SEC_COMP 则说明 Security 已经清除成功。
- 若是 L2CEVT_L2CA_CONNECT_REQ 则说明 来自上层的 connect 请求,如果当前处于 sniff 状态,要先取消 sniff。
- L2CEVT_SEC_COMP_NEG 说明 Security 失败,清除当前 CCB,返回
- L2CEVT_L2CAP_CONNECT_REQ 说明是 Peer connect request,既然成功连接了,结束掉 timer
- L2CEVT_L2CA_DATA_WRITE,如果我们的数据从上层经过这里,并且是 CST_CLOSED,由于当前的 Channel 没有建立好,并且上层已经将数据丢给L2CAP了,只能将数据丢弃处理了(数据流不能逆向)。
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_TERM_W4_SEC_COMP状态:Acceptor(接收者)等待 security 的间隙,源码易读,不再详细展开分析,注意一个事件 L2CEVT_SEC_COMP 的处理,会将 p_ccb->chnl_state 置为 CST_W4_L2CA_CONNECT_RSP
- CST_W4_L2CAP_CONNECT_RSP: 经过 2 或 3 这个关于安全链接的步骤,当然要等待 Peer connect的回应(Response)。分为 获取 peer connect的 confirm、pending、rejected connection等信息,作进一步的判断。
- CST_CONFIG:商讨配置的过程。
- CST_OPEN:Channel 处于 OPEN 状态,我们可以发送上层传过来的数据,我们的音乐数据就是从这个 case 里发出去的。
- CST_W4_L2CAP_DISCONNECT_RSP:等待 peer(对方设备)断开链接的 Response
- 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 //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