📄 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 + -