當收到的數據報的協議字段指明這是一個TCP報文段時,ipintr(通過協議協議轉換表中的pr_input函數)會調用tcp_input
進行處理,tcp_inut在軟件中斷一級執行。
函數非常長,我們將分兩張討論,下圖列出了tcp_input中的處理框架。本章將結束對RST報文段處理的講解,下一章開始
介紹ACK報文段的處理。
頭幾個步驟是非常典型的:對輸入報文段做有效性驗證(檢驗和、長度等),以及尋找連接的PCB。儘管後面還有大量的
代碼,但通過“首部預測”,算法卻有可能完全跳過後續的邏輯。首部預測算法是基於這樣的假定,一般情況下,報文段既
不會丟失,次序也不會錯誤,因此,對於給定連接,TCP總能猜到下一個接收報文段的內容。如果算法起作用,函數直接
返回,這是tcp_input中最快的一條執行路徑。
1.預處理
該部分介紹對收到的TCP報文段進行於預處理。處理的大概流程如下:
1.從第一個mbuf中獲取IP和TCP首部。
2.驗證TCP的檢驗和。
3.驗證TCP偏移字段。
4.把IP和TCP首部及選項放入第一個mbuf。
5.快速處理時間戳選項。
6.保存輸入標誌,把字段轉換成主機字節序。
7.尋找Internet PCB。
8.如果沒有找到PCB,則丟棄報文,併發送RST作爲響應。
9.如果TCP控制塊存在,但連接狀態爲closed,說明插口已創建,且得到了本地地址和本地端口號,但還未調用connect或
listen。報文段被丟棄,且不發送任何響應。
10.不改變通告窗口大小。
11.如果選定了插口調試選項,則保存連接狀態及IP和TCP首部。
12.如果監聽插口收到了報文段,則創建新的插口。
13.計算窗口縮放因子。
14.復位空閒時間和保活定時器。
15.如果不處於監聽狀態,處理TCP選項。
2.首部預測
首部預測算法通過處理兩種常見現象,簡化單向數據傳輸的實現。
1.如果TCP發送數據,連接上等待接收的下一個報文段是對已發送數據的ACK。
2.如果TCP接收數據,連接上等待的下一個報文段時順序到達的數據報文段。
3.TCP輸入:緩慢的執行路徑
下面介紹首部預測失敗時的處理代碼,tcp_input中較慢的一條執行路徑。
1.丟棄IP和TCP首部,包括TCP選項。
2.計算接收窗口。
因爲函數後面的代碼必須確定通告窗口中能放入多少數據,所以現在必須計算通告窗口的大小。落在通告窗口之外的接收
數據被丟棄;落在窗口左側的數據是已接收並確認過的數據,落在窗口右側的數據時暫時不允許對端發送的數據。
4.完成被動打開或主動打開
如果連接狀態等於LISTEN或者SYN_SENT,則執行本節的處理。連接處於這兩個狀態時,等待接收的報文段爲SYN,任何
其他報文將被丟棄。
4.1.完成被動打開
4.2.完成主動打開
5.PAWS:防止序號迴繞
6.裁剪報文段使數據在窗口內
7.自連接和同時打開
8.記錄時間戳
下面給出了tcp_input的處理收到的時間戳選項。
如果收到的報文段中帶有時間戳,時間戳值保存在變量中。
9.RST處理
下面給出處理RST標誌的switch語句,取決於當前的連接狀態。
1.SYN_RCVD狀態下,插口差錯代碼設定爲ECONNREFUSED,關閉插口。
2.如果在ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2或CLOSE_WAIT狀態收到RST,則返回差錯代碼ECOORESET。
3.如果狀態爲CLOSING、LAST_ACK或TIME_WAIT,由於應用進程已關閉插口,無需返回差錯代碼。
4.如果SYN標誌依舊置位,說明出現了差錯,連接被丟棄,返回代碼ECONNRESET。
5.如果ACK標誌未置位,報文被丟棄。