ACL 包接收流程
有關 ACL 包接收的過程都是在 btu_task 這個守護線程中處理的。
我們看到 btu_task 處理數據包的過程:
- 等待事件,事件到來後,如果是 TASK_MBOX_0_EVT_MASK(是不是 MBOX裡的Task),那麼從 mbox 中取出這個數據包,並判斷是什麼類型的 Event。
- 如果是 BT_EVT_TO_BTU_HCI_ACL,說明是 ACL 數據,交給 l2cap 來處理。
- 如果是 BT_EVT_TO_BTU_L2C_SEG_XMIT,說明是 L2CAP 的分包數據沒有發送完,那繼續發送分包數據。
1 //部分 btu_task 源碼
2 ...........
3 /* Wait for, and process, events */
4 for (;;)
5 {
6 event = GKI_wait (0xFFFF, 0);
7
8 if (event & TASK_MBOX_0_EVT_MASK)
9 {
10 /* Process all messages in the queue */
11 while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
12 {
13 /* Determine the input message type. */
14 switch (p_msg->event & BT_EVT_MASK)
15 {
16 case BT_EVT_TO_BTU_HCI_ACL:
17 /* All Acl Data goes to L2CAP */
18 l2c_rcv_acl_data (p_msg);//我們的 ACL 數據來了,關鍵分析這個函數
19 break;
20
21 case BT_EVT_TO_BTU_L2C_SEG_XMIT:
22 /* L2CAP segment transmit complete */
23 l2c_link_segments_xmitted (p_msg);
24 break;
25
26 case BT_EVT_TO_BTU_HCI_SCO:
27 #if BTM_SCO_INCLUDED == TRUE
28 btm_route_sco_data (p_msg);
29 break;
30 #endif
31
32 case BT_EVT_TO_BTU_HCI_EVT:
33 btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
34 GKI_freebuf(p_msg);
35
36 ....
l2c_rcv_acl_data 這個函數,處理收到的 ACL 包,下面我們來分析一下 l2c_rcv_acl_data 這個函數:
- 在收到的 ACL 包中找出 pkt_type(分包的話要另作處理) 和 handle。
- 若此 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 void l2c_rcv_acl_data (BT_HDR *p_msg)
2 {
3 UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
4 UINT16 handle, hci_len;
5 UINT8 pkt_type;
6 tL2C_LCB *p_lcb;
7 tL2C_CCB *p_ccb = NULL;
8 UINT16 l2cap_len, rcv_cid, psm;
9
10 /* Extract the handle */
11 STREAM_TO_UINT16 (handle, p);
12 pkt_type = HCID_GET_EVENT (handle);
13 handle = HCID_GET_HANDLE (handle);
14
15 /* Since the HCI Transport is putting segmented packets back together, we */
16 /* should never get a valid packet with the type set to "continuation" */
17 if (pkt_type != L2CAP_PKT_CONTINUE)//數據包一定要是完整的,分包另作處理
18 {
19 /* Find the LCB based on the handle */
20 if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
21 {
22 UINT8 cmd_code;
23
24 /* There is a slight possibility (specifically with USB) that we get an */
25 /* L2CAP connection request before we get the HCI connection complete. */
26 /* So for these types of messages, hold them for up to 2 seconds. */
27 STREAM_TO_UINT16 (hci_len, p);
28 STREAM_TO_UINT16 (l2cap_len, p);
29 STREAM_TO_UINT16 (rcv_cid, p);
30 STREAM_TO_UINT8 (cmd_code, p);
31
32 if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
33 && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ))
34 {
35 L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
36 handle, p_msg->layer_specific, rcv_cid, cmd_code,
37 l2cb.rcv_hold_q.count);
38 p_msg->layer_specific = 2;
39 GKI_enqueue (&l2cb.rcv_hold_q, p_msg);//添加到隊列中,等待 connect 數據包到達,有種可能發生的 case
40
41 if (l2cb.rcv_hold_q.count == 1)
42 btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
43
44 return;
45 }
46 else
47 {
48 L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
49 handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count);
50 }
51 GKI_freebuf (p_msg);
52 return;
53 }
54 }
55 else
56 {
57 L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
58 GKI_freebuf (p_msg);
59 return;
60 }
61 //下面是我們把 ACL 數據包給部分拆包了,即除掉 L2CAP 的控制部分,還原上層的數據包。
62 /* Extract the length and update the buffer header */
63 STREAM_TO_UINT16 (hci_len, p);
64 p_msg->offset += 4;
65
66 #if (L2CAP_HOST_FLOW_CTRL == TRUE)
67 /* Send ack if we hit the threshold */
68 if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh)
69 btu_hcif_send_host_rdy_for_data();
70 #endif
71
72 /* Extract the length and CID */
73 STREAM_TO_UINT16 (l2cap_len, p);
74 STREAM_TO_UINT16 (rcv_cid, p);
75
76 /* Find the CCB for this CID */
77 if (rcv_cid >= L2CAP_BASE_APPL_CID)// 說明此 rcv_cid 是上層應用普通數據流的 CID
78 {
79 if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
80 {
81 L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid);
82 GKI_freebuf (p_msg);
83 return;
84 }
85 }
86
87 if (hci_len >= L2CAP_PKT_OVERHEAD) //數據包長度肯定要大於 Head的值,否則必然是個錯包
88 {
89 p_msg->len = hci_len - L2CAP_PKT_OVERHEAD;
90 p_msg->offset += L2CAP_PKT_OVERHEAD;
91 }
92 else
93 {
94 L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" );
95 GKI_freebuf (p_msg);
96 return;
97 }
98
99 if (l2cap_len != p_msg->len) //長度不相等,那數據包傳送過程肯定出現了差錯,丟包吧
100 {
101 L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d Act: %d",
102 l2cap_len, p_msg->len);
103
104 GKI_freebuf (p_msg);
105 return;
106 }
107
108 /* Send the data through the channel state machine */
109 if (rcv_cid == L2CAP_SIGNALLING_CID)//控制創建和建立 Channel的 signalling
110 {
111 process_l2cap_cmd (p_lcb, p, l2cap_len); //此函數專門處理這個Channel的事件
112 GKI_freebuf (p_msg);
113 }
114 else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
115 {
116 /* process_connectionless_data (p_lcb); */
117 STREAM_TO_UINT16 (psm, p);
118 L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
119 #if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
120 if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS)
121 {
122 p_msg->offset += L2CAP_BCST_OVERHEAD;
123 p_msg->len -= L2CAP_BCST_OVERHEAD;
124 tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ;
125 GKI_freebuf (p_msg);
126 }
127 else
128 #endif
129
130 #if (L2CAP_UCD_INCLUDED == TRUE)
131 /* if it is not broadcast, check UCD registration */
132 if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
133 {
134 /* nothing to do */
135 }
136 else
137 #endif
138 GKI_freebuf (p_msg);
139 }
140 #if (BLE_INCLUDED == TRUE)
141 else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) //LE 設備的專用 Channel
142 {
143 l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
144 GKI_freebuf (p_msg);
145 }
146 #endif
147 #if (L2CAP_NUM_FIXED_CHNLS > 0)
148 else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
149 (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
150 {
151 /* If no CCB for this channel, allocate one */
152 if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
153 {
154 p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
155
156 if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
157 l2c_fcr_proc_pdu (p_ccb, p_msg);
158 else
159 (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
160 }
161 else
162 GKI_freebuf (p_msg);
163 }
164 #endif
165
166 else
167 {
168 if (p_ccb == NULL)
169 GKI_freebuf (p_msg);
170 else
171 {
172 /* Basic mode packets go straight to the state machine */
173 if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
174 //普通的數據流都是經過這條通路的,下面這個函數覺得很熟悉吧,因為在發送數據包的時候也調用了他。
175 l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
176 else
177 {
178 /* eRTM or streaming mode, so we need to validate states first */
179 if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
180 l2c_fcr_proc_pdu (p_ccb, p_msg);
181 else
182 GKI_freebuf (p_msg);
183 }
184 }
185 }
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這個函數都做了些什麼呢?我們來深入代碼瞭解一下整個過程。
- 通過 num_sent 來更新數據 controller_xmit_window,sent_not_acked。
- 既然又多了 credits(Snoop中的),那麼自然調用 l2c_link_check_send_pkts 去找更多的包發送下去。
- 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 void l2c_link_process_num_completed_pkts (UINT8 *p)
2 {
3 UINT8 num_handles, xx;
4 UINT16 handle;
5 UINT16 num_sent; //已經發下去的數據,這個數據要更新controller_xmit_window
6 tL2C_LCB *p_lcb;
7
8 L2CAP_TRACE_DEBUG0("mike: l2c_link_process_num_completed_pkts");
9 STREAM_TO_UINT8 (num_handles, p);
10 L2CAP_TRACE_DEBUG1("mike: l2c_link_process_num_completed_pkts--number_handles:%d", num_handles);
11 for (xx = 0; xx < num_handles; xx++)//handle 對應着每條邏輯鏈路(Link)
12 {
13 STREAM_TO_UINT16 (handle, p);
14 STREAM_TO_UINT16 (num_sent, p);
15
16 p_lcb = l2cu_find_lcb_by_handle (handle);
17
18 /* Callback for number of completed packet event */
19 /* Originally designed for [3DSG] */
20 if((p_lcb != NULL) && (p_lcb->p_nocp_cb))
21 {
22 L2CAP_TRACE_DEBUG0 ("L2CAP - calling NoCP callback");
23 (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr);
24 }
25
26 if (p_lcb)
27 {
28 #if (BLE_INCLUDED == TRUE)
29 if (p_lcb->is_ble_link)
30 {
31 l2cb.controller_le_xmit_window += num_sent;
32 }
33 else
34 #endif
35 {
36 /* Maintain the total window to the controller */
37 l2cb.controller_xmit_window += num_sent;
38 }
39 /* If doing round-robin, adjust communal counts */
40 if (p_lcb->link_xmit_quota == 0)
41 {
42 /* Don't go negative */
43 if (l2cb.round_robin_unacked > num_sent)
44 l2cb.round_robin_unacked -= num_sent;
45 else
46 l2cb.round_robin_unacked = 0;
47 }
48
49 /* Don't go negative */
50 if (p_lcb->sent_not_acked > num_sent)
51 p_lcb->sent_not_acked -= num_sent; //更新
52 else
53 p_lcb->sent_not_acked = 0;
54
55 l2c_link_check_send_pkts (p_lcb, NULL, NULL);
56
57 L2CAP_TRACE_DEBUG1("mike:l2c_link_process_num_completed_pkts--l2cb.controller_xmit_window=%d",l2cb.controller_xmit_window);
58
59 /* If we were doing round-robin for low priority links, check 'em */
60 if ( (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
61 && (l2cb.check_round_robin)
62 && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
63 {
64 l2c_link_check_send_pkts (NULL, NULL, NULL);
65 }
66 }
67
68 #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
69 if (p_lcb)
70 {
71 #if (BLE_INCLUDED == TRUE)
72 if (p_lcb->is_ble_link)
73 {
74 L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
75 l2cb.controller_le_xmit_window,
76 p_lcb->handle, p_lcb->sent_not_acked,
77 l2cb.check_round_robin, l2cb.round_robin_unacked);
78 }
79 else
80 #endif
81 {
82 L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
83 l2cb.controller_xmit_window,
84 p_lcb->handle, p_lcb->sent_not_acked,
85 l2cb.check_round_robin, l2cb.round_robin_unacked);
86
87 }
88 }
89 else
90 {
91 #if (BLE_INCLUDED == TRUE)
92 L2CAP_TRACE_DEBUG5 ("TotalWin=%d LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d",
93 l2cb.controller_xmit_window,
94 l2cb.controller_le_xmit_window,
95 handle,
96 l2cb.check_round_robin, l2cb.round_robin_unacked);
97 #else
98 L2CAP_TRACE_DEBUG4 ("TotalWin=%d Handle=0x%x RRCheck=%d RRUnack=%d",
99 l2cb.controller_xmit_window,
100 handle,
101 l2cb.check_round_robin, l2cb.round_robin_unacked);
102 #endif
103 }
104 #endif
105 }
106
107 #if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
108 /* only full stack can enable sleep mode */
109 btu_check_bt_sleep ();
110 #endif
111 }
到此為止,我們已經把普通 ACL 包發送和接收部分源碼分析完了。後續有時間會繼續分析控制類型的ACL包,以及ACL鏈路建立的流程。
沒有留言:
張貼留言