?? tcpip.c
字號:
(gptConn->TcpStateFlags == cTCP_TIME_WAIT)){
goto found_unused_connection;
}
}
goto drop; // 沒有空閑的TCP聯接,進入異常終止遠端處理!
// 有空閑的TCP聯接,回應遠端的SYN請求
found_unused_connection:
// 設置初始TCP聯接事務狀態
gptConn->Timer = cTCP_RTO;
gptConn->NumRetran = 0;
gptConn->LocalPort = cptTcpHdrBuf->DestPort;
gptConn->RemotePort = cptTcpHdrBuf->SrcPort;
gptConn->RemoteIpAddr[0] = cptIpHdrBuf->SrcIpAddr[0];
gptConn->RemoteIpAddr[1] = cptIpHdrBuf->SrcIpAddr[1];
gptConn->TcpStateFlags = cTCP_SYN_RCVD|cTCP_OUTSTANDING;
//-------------------------
gptConn->SeqNum[0] = guwISN[0];
gptConn->SeqNum[1] = guwISN[1];
//-------------------------
gptConn->AckNum[0] = guwISN[0];
gptConn->AckNum[1] = guwISN[1];
if (++gptConn->AckNum[1] == 0){
++gptConn->AckNum[0];
}
//-------------------------
gptConn->RcvNum[0] = cptTcpHdrBuf->SeqNum[0];
gptConn->RcvNum[1] = cptTcpHdrBuf->SeqNum[1];
if (++gptConn->RcvNum[1] == 0){
++gptConn->RcvNum[0];
}
// 獲取遠端TCP報文長度。如果遠端比本地小,就以遠端為準。
i = cptTcpHdrBuf->HdrLen;
if (i > cTCP_HDR_NOOPT){
i = (i - cTCP_HDR_NOOPT) << 1; // Convert 32bit number to 16bit number.
for (j = 0; j < i; j++){
if (cpTcpData[j] == 0x0204){
gptConn->MaxSegSize = cpTcpData[j + 1] > cTCP_MSS ? cTCP_MSS : cpTcpData[j + 1];
break;
}
}
}
// 發送 SYNACK 包
#if TCP_ACTIVE_OPEN == 1
tcp_send_synack:
cptTcpHdrBuf->Flags = cTCP_ACK;
tcp_send_syn:
cptTcpHdrBuf->Flags |= cTCP_SYN;
#else
tcp_send_synack:
cptTcpHdrBuf->Flags = cTCP_SYN|cTCP_ACK;
#endif
// 給 SYNACK 包配置TCP頭選項表
cpTcpData[0] = 0x0204; // 0x0204 表示最大報文段長度前綴
cpTcpData[1] = cTCP_MSS; // 最大報文段長度前綴
cpTcpData[2] = 0x0101; // 0x01表示無操作,0x00表示選項表結束
cpTcpData[3] = 0x0402; // 0x0402 表示 SACK 被允許
guwEthLen = 2*cIpHdrLen + (cTCP_HDR_OPT << 2);
cptTcpHdrBuf->HdrLen = cTCP_HDR_OPT;
goto tcp_send;
// 找到已經存在的TCP聯接事物
found:
guwFlags = 0;
// 如果遠端是RST包,就通知本地應用層:當前連接被遠端異常終止!
if (cptTcpHdrBuf->Flags & cTCP_RST){
gptConn->TcpStateFlags = cTCP_CLOSED;
guwFlags = cTCP_ABORT;
msip_APPCALL();
goto drop;
}
// 如果沒有ACK標識,不響應!
if (!(cptTcpHdrBuf->Flags & cTCP_ACK)){
goto drop;
}
// 計算TCP數據段字節長度
guwEthLen -= ((cptIpHdrBuf->Vhl & 0x0f) << 2) + (cptTcpHdrBuf->HdrLen << 2);
// 檢驗遠端的ACK序號是否我們期待的.....
if ((cptTcpHdrBuf->AckNum[0] == gptConn->AckNum[0]) && (cptTcpHdrBuf->AckNum[1] == gptConn->AckNum[1])){
gptConn->SeqNum[0] = gptConn->AckNum[0];
gptConn->SeqNum[1] = gptConn->AckNum[1];
gptConn->TcpStateFlags &= ~cTCP_OUTSTANDING;
gptConn->Timer = cTCP_RTO;
gptConn->NumRetran = 0;
guwFlags = cTCP_ACKDATA;
} else {
goto drop;
}
// 根據不同的聯接狀態決定TCP狀態變遷,并通知應用程序
switch (gptConn->TcpStateFlags & cTCP_TS_MASK){
// CLOSED和LISTEN狀態不在這里處理
// CLOSE_WAIT狀態同樣被忽略:因為一旦本地收到FIN,我們就強制應用層關閉,即從ESTABLISH到LAST_ACK
case cTCP_SYN_RCVD:
// 在SYN_RCVD狀態下,我們收到遠端ACK回應
// 另一方面,如果已經存在cTCP_ACKDATA標識,就進入ESTABLISHED狀態
gptConn->TcpStateFlags = cTCP_ESTABLISHED;
guwFlags = cTCP_CONNECTED;
msip_APPCALL();
goto appsend;
#if TCP_ACTIVE_OPEN == 1
case cTCP_SYN_SENT:
// 在SYN_SENT狀態,我們收到遠端SYNACK響應,本地發送ACK后就進入ESTABLISHED狀態
// 獲取遠端TCP報文長度。如果遠端比本地小,就以遠端為準。
i = cptTcpHdrBuf->HdrLen;
if (i > cTCP_HDR_NOOPT){
i = (i - cTCP_HDR_NOOPT) << 1;
for (j = 0; j < i; j++){
if (cpTcpData[j] == 0x0204){
gptConn->MaxSegSize = cpTcpData[j + 1] > cTCP_MSS ? cTCP_MSS : cpTcpData[j + 1];
break;
}
}
}
gptConn->RcvNum[0] = cptTcpHdrBuf->SeqNum[0];
gptConn->RcvNum[1] = cptTcpHdrBuf->SeqNum[1];
if (++gptConn->RcvNum[1] == 0){
++gptConn->RcvNum[0];
}
gptConn->TcpStateFlags = cTCP_ESTABLISHED;
guwFlags = cTCP_CONNECTED;
msip_APPCALL();
goto appsend;
#endif
case cTCP_ESTABLISHED: // 應用狀態標識cTCP_ACKDATA被設置,允許應用層發送TCP數據包
// 如果收到包含FIN標識的包,協議層發送FIN并進入LAST_ACK狀態,并向應用層發cTCP_CLOSE標識
if (cptTcpHdrBuf->Flags & cTCP_FIN) {
i = 1 + guwEthLen;
if ((gptConn->RcvNum[1] += i) < i){
++gptConn->RcvNum[0];
}
guwFlags = cTCP_CLOSE;
msip_APPCALL();
if (++gptConn->AckNum[1] == 0){
++gptConn->AckNum[0];
}
gptConn->TcpStateFlags = cTCP_LAST_ACK|cTCP_OUTSTANDING;
tcp_send_finack: // 發送FINACK包:由TCP事務查詢重傳跳過來的.....
cptTcpHdrBuf->Flags = cTCP_FIN|cTCP_ACK;
goto tcp_send_nodata;
}
if (guwEthLen > 0){ // 收到的TCP包有數據段
if (gptConn->TcpStateFlags & cTCP_STOPPED){
// 1)如果有cTCP_STOPPED標識,表明應用層沒有buffer處理,我們只能ACK回應。
// guwFlags = cTCP_ACKDATA; // 已經存在的,這里不需要重設
goto tcp_send_ack;
} else {
// 2)應用層可以處理這個含數據段的TCP包,給應用層發cTCP_NEWDATA標識以替換cTCP_ACKDATA標識
guwFlags = cTCP_NEWDATA;
if ((gptConn->RcvNum[1] += guwEthLen) < guwEthLen){
++gptConn->RcvNum[0];
}
}
}
// 協議層通知應用層目前的狀態:
msip_APPCALL();
appsend: // 根據應用層的反饋標識處理回應遠端
// 如果應用層需要異常終止當前連接,協議層就RSTACK遠端,并清除這個TCP事務!
if (guwFlags & cTCP_ABORT){
gptConn->TcpStateFlags = cTCP_CLOSED;
cptTcpHdrBuf->Flags = cTCP_RST|cTCP_ACK;
guwEthLen = 0;
goto tcp_send_nodata;
}
// 如果應用層需要正常關閉當前連接,協議層就進入等待FIN_WAIT_1狀態,并向遠端發送FINACK
if (guwFlags & cTCP_CLOSE){
if (++gptConn->AckNum[1] == 0){
++gptConn->AckNum[0];
}
gptConn->TcpStateFlags = cTCP_FIN_WAIT_1|cTCP_OUTSTANDING;
gptConn->NumRetran = 0;
cptTcpHdrBuf->Flags = cTCP_FIN|cTCP_ACK;
guwEthLen = 0;
goto tcp_send_nodata;
}
// 檢查應用層是否有TCP數據包
if (guwEthLen > 0){ // 應用層有TCP數據包
gptConn->TcpStateFlags |= cTCP_OUTSTANDING;
gptConn->NumRetran = 0;
if ((gptConn->AckNum[1] += guwEthLen) < guwEthLen){
++gptConn->AckNum[0];
}
// 重傳處理,當然也要處理正常的ACK回應。
apprexmit:
// 發送ACK確認,可能包含TCP數據
guwEthLen += 2*(cIpHdrLen + cTcpHdrLen);
// 設置PSHACK標識
cptTcpHdrBuf->Flags = cTCP_ACK | cTCP_PSH;
// 進入TCP封裝
goto tcp_send_noopts;
} else if (guwFlags & cTCP_NEWDATA){ // 應用層沒有有TCP數據包。檢查遠端是否等待本地的ACK回應
goto tcp_send_ack;
}
goto drop; // 遠端是沒有數據的ACK回應,并且應用層也沒有數據要傳。
case cTCP_LAST_ACK:
// 如果收到遠端ACK確認本地FIN,協議層關閉連接。
if (guwFlags & cTCP_ACKDATA){
gptConn->TcpStateFlags = cTCP_CLOSED;
}
goto drop;
case cTCP_FIN_WAIT_1:
// 應用層已經關閉,但遠端還沒有。本地協議層等待FIN
if (guwEthLen > 0){
if ((gptConn->RcvNum[1] += guwEthLen) < guwEthLen){
++gptConn->RcvNum[0];
}
}
if (cptTcpHdrBuf->Flags & cTCP_FIN){
if (guwFlags & cTCP_ACKDATA){
gptConn->TcpStateFlags = cTCP_TIME_WAIT;
gptConn->Timer = 0;
}
else{
gptConn->TcpStateFlags = cTCP_CLOSING|cTCP_OUTSTANDING;
}
if (++gptConn->RcvNum[1] == 0){
++gptConn->RcvNum[0];
}
goto tcp_send_ack;
}
else if (guwFlags & cTCP_ACKDATA){
gptConn->TcpStateFlags = cTCP_FIN_WAIT_2;
goto drop;
}
if (guwEthLen > 0){
goto tcp_send_ack;
}
goto drop;
case cTCP_FIN_WAIT_2:
if (guwEthLen > 0){
if ((gptConn->RcvNum[1] += guwEthLen) < guwEthLen){
++gptConn->RcvNum[0];
}
}
if (cptTcpHdrBuf->Flags & cTCP_FIN){
gptConn->TcpStateFlags = cTCP_TIME_WAIT;
gptConn->Timer = 0;
if (+gptConn->RcvNum[1] == 0){
++gptConn->RcvNum[0];
}
goto tcp_send_ack;
}
if(guwEthLen > 0){
goto tcp_send_ack;
}
goto drop;
case cTCP_TIME_WAIT:
goto tcp_send_ack;
case cTCP_CLOSING:
if (guwFlags & cTCP_ACKDATA){
gptConn->TcpStateFlags = cTCP_TIME_WAIT;
gptConn->Timer = 0;
}
}
goto drop;
// 封裝 TCP
tcp_send_ack:
cptTcpHdrBuf->Flags = cTCP_ACK;
tcp_send_nodata:
guwEthLen = 2*(cIpHdrLen + cTcpHdrLen);
tcp_send_noopts:
cptTcpHdrBuf->HdrLen = cTCP_HDR_NOOPT;
tcp_send: // 構造TCP頭
cptTcpHdrBuf->AckNum[0] = gptConn->RcvNum[0];
cptTcpHdrBuf->AckNum[1] = gptConn->RcvNum[1];
cptTcpHdrBuf->SeqNum[0] = gptConn->SeqNum[0];
cptTcpHdrBuf->SeqNum[1] = gptConn->SeqNum[1];
cptTcpHdrBuf->SrcPort = gptConn->LocalPort;
cptTcpHdrBuf->DestPort = gptConn->RemotePort;
cptIpHdrBuf->SrcIpAddr[0] = guwIpAddr[0];
cptIpHdrBuf->SrcIpAddr[1] = guwIpAddr[1];
cptIpHdrBuf->DestIpAddr[0] = gptConn->RemoteIpAddr[0];
cptIpHdrBuf->DestIpAddr[1] = gptConn->RemoteIpAddr[1];
// 如果應用層要求停止數據,協議層凍結窗口
if (gptConn->TcpStateFlags & cTCP_STOPPED){
cptTcpHdrBuf->WndSize = 0;
}
else{
// 通知遠端本地重新開放窗口。由于本地RAM小,所以是靜態窗口
cptTcpHdrBuf->WndSize = cTCP_WS;
}
tcp_send_noconn: // 構造IP頭
cptIpHdrBuf->Vhl = cIP_VER_HLEN;
cptIpHdrBuf->Tos = 0;
cptIpHdrBuf->Len = guwEthLen;
cptIpHdrBuf->IpId = ++guwIpId;
cptIpHdrBuf->Flags = cIP_DF; // Do not Fragment!
cptIpHdrBuf->Offset = 0;
cptIpHdrBuf->Ttl = cIP_TTL;
cptIpHdrBuf->Proto = cIP_PROTO_TCP;
// Calculate IP checksums.
cptIpHdrBuf->IpChkSum = 0;
cptIpHdrBuf->IpChkSum = ~checksum(2*cIpHdrLen, cpIpHdrBuf);
// Calculate TCP checksums.
cptTcpHdrBuf->Reserve = 0;
cptTcpHdrBuf->TcpChkSum = 0;
cptTcpHdrBuf->TcpChkSum = ~msip_TcpChkSum();
send: // 發生送IP包
msip_Arp_Out(pARP);
drop: // 釋放緩沖區
guwEthLen = 0;
return;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -