📄 tcpip.c
字号:
#include "tcpip.h"
#if TCP_DHCP == 0
const UINT16 guwIpAddr[2] = {((cIpAddr1<<8)|cIpAddr2), ((cIpAddr3<<8)|cIpAddr4)};
#else
UINT16 guwIpAddr[2];
#endif
#if TCP_DHCP == 0
const UINT16 guwNetMask[2] = {((cNetMask1<<8)|cNetMask2), ((cNetMask3<<8)|cNetMask4)};
#else
UINT16 guwNetMask[2];
#endif
#if TCP_DHCP == 0
const UINT16 guwDR_IpAddr[2] = {((cDR_IpAddr1<<8)|cDR_IpAddr2), ((cDR_IpAddr3<<8)|cDR_IpAddr4)};
#else
UINT16 guwDR_IpAddr[2];
#endif
const UINT16 guwEthAddr[3] = {((cEthAddr1<<8)|cEthAddr2), ((cEthAddr3<<8)|cEthAddr4), ((cEthAddr5<<8)|cEthAddr6)};
// 最大允许的以太包缓冲区
UINT16 guwEthBuf[cEthBufSize];
// 正在处理包的字节长度。这个值随处理层的不同而改变!
volatile UINT16 guwEthLen = 0;
// 分配ARP表的内寸
ArpEntries_Stru gstArpTab[cArpTabSize];
// 记录本地IP序号
volatile UINT16 guwIpId;
// TCP 本地初始32位序号
volatile UINT16 guwISN[2];
// 记录TCP本地端口号
UINT16 guwListenPorts[cMaxListenPorts];
// TCP最大联接事务记录表
Conn_Stru gstConns[cMaxConnetions];
// 当前TCP事务联接指针
Conn_Stru *gptConn;
// TCP/IP协议栈和应用程序间通讯的变量
volatile UINT16 guwFlags;
//--------------------------------------------------------------------------------------
void msip_Init(void){
UINT16 index;
// Initialize ArpEntries
for (index = 0; index < cArpTabSize; index++){
gstArpTab[index].IpAddr[0] = 0;
gstArpTab[index].IpAddr[1] = 0;
}
// Initialize Listen Ports
for (index = 0; index < cMaxListenPorts; index++)
guwListenPorts[index] = 0;
// Initialize Listen Ports
for (index = 0; index < cMaxConnetions; index++){
gstConns[index].TcpStateFlags = cTCP_CLOSED;
gstConns[index].PollTime = 0;
}
}
//--------------------------------------------------------------------------------------
void msip_Arp_Time(){
ArpEntries_Stru *pARP;
for (pARP = cptArpTabStart; pARP < cptArpTabEnd; pARP++){
if (((pARP->IpAddr[0] | pARP->IpAddr[1]) != 0) && ((guwTime2 - pARP->Time2) > 2*cArpMaxAge)){
pARP->IpAddr[0] = 0;
pARP->IpAddr[1] = 0;
}
}
guwMsg_Route &= ~cM_ARP_TIME; // 清除ARP表老化处理事件
}
//--------------------------------------------------------------------------------------
ArpEntries_Stru *msip_Arp_Update(UINT16 *uwIpAddr, UINT16 *uwEthAddr){
ArpEntries_Stru *pARPTAB, *pARPTAB1;
UINT16 maxtime,cmptime;
// 如果接收包的源地址与本地相同,说明是DDoS攻击!!!
if ((uwIpAddr[0] == guwIpAddr[0]) && (uwIpAddr[1] == guwIpAddr[1])){
return cptArpTabEnd;
}
// 如果找到匹配的IP,就更新MAC
for (pARPTAB = cptArpTabStart; pARPTAB < cptArpTabEnd; pARPTAB++){
if((pARPTAB->IpAddr[0] == uwIpAddr[0]) && (pARPTAB->IpAddr[1] == uwIpAddr[1])){
goto Arp_Update_Exit2; // 更新 MAC/Time
}
}
// 没有找到匹配IP,找个空记录来更新
for (pARPTAB = cptArpTabStart; pARPTAB < cptArpTabEnd; pARPTAB++){
if((pARPTAB->IpAddr[0] | pARPTAB->IpAddr[1]) == 0){
goto Arp_Update_Exit1; // 更新 IP/MAC/Time
}
}
// 既没有匹配IP,又没有空记录!把时间最长的记录更新
maxtime = 0;
for (pARPTAB1 = cptArpTabStart; pARPTAB1 < cptArpTabEnd; pARPTAB1++){
cmptime = guwTime2 - pARPTAB1->Time2; // 计算记录存放时间
if(cmptime > maxtime){
maxtime = cmptime; // 记录最大时间
pARPTAB = pARPTAB1; // 记录ARP表指针
}
}
Arp_Update_Exit1:
pARPTAB->IpAddr[0] = uwIpAddr[0];
pARPTAB->IpAddr[1] = uwIpAddr[1];
Arp_Update_Exit2:
pARPTAB->EthAddr[0] = uwEthAddr[0];
pARPTAB->EthAddr[1] = uwEthAddr[1];
pARPTAB->EthAddr[2] = uwEthAddr[2];
pARPTAB->Time2 = guwTime2;
return pARPTAB;
}
//--------------------------------------------------------------------------------------
void msip_Arp_In(void){
// 如果接收包的源地址与本地相同,说明是DDoS攻击!!!
if ((cptArpHdrBuf->SndIpAddr[0] == guwIpAddr[0]) &&
(cptArpHdrBuf->SndIpAddr[1] == guwIpAddr[1])){
goto arp_in_exit;
}
// 如果不是请求本地,就退出!
if ((cptArpHdrBuf->RcvIpAddr[0] != guwIpAddr[0]) ||
(cptArpHdrBuf->RcvIpAddr[1] != guwIpAddr[1])){
goto arp_in_exit;
}
switch (cptArpHdrBuf->OpCode){
case cArpRequest:
// 如果是ARP请求,就构造ARP回应
cptEthHdrBuf->DestEthAddr[0] = cptArpHdrBuf->SndEthAddr[0];
cptArpHdrBuf->RcvEthAddr[0] = cptArpHdrBuf->SndEthAddr[0];
cptEthHdrBuf->DestEthAddr[1] = cptArpHdrBuf->SndEthAddr[1];
cptArpHdrBuf->RcvEthAddr[1] = cptArpHdrBuf->SndEthAddr[1];
cptEthHdrBuf->DestEthAddr[2] = cptArpHdrBuf->SndEthAddr[2];
cptArpHdrBuf->RcvEthAddr[2] = cptArpHdrBuf->SndEthAddr[2];
cptEthHdrBuf->SrcEthAddr[0] = guwEthAddr[0];
cptArpHdrBuf->SndEthAddr[0] = guwEthAddr[0];
cptEthHdrBuf->SrcEthAddr[1] = guwEthAddr[1];
cptArpHdrBuf->SndEthAddr[1] = guwEthAddr[1];
cptEthHdrBuf->SrcEthAddr[2] = guwEthAddr[2];
cptArpHdrBuf->SndEthAddr[2] = guwEthAddr[2];
cptArpHdrBuf->RcvIpAddr[0] = cptArpHdrBuf->SndIpAddr[0];
cptArpHdrBuf->RcvIpAddr[1] = cptArpHdrBuf->SndIpAddr[1];
cptArpHdrBuf->SndIpAddr[0] = guwIpAddr[0];
cptArpHdrBuf->SndIpAddr[1] = guwIpAddr[1];
cptArpHdrBuf->OpCode = cArpReply;
// cptEthHdrBuf->EthType: is unchanged
// cptArpHdrBuf->HwType: is unchanged
// cptArpHdrBuf->ProtoType: is unchanged
// cptArpHdrBuf->HwLen8Proto8: is unchanged
// 发送以太包
guwEthLen = 60;
ether_Send();
break;
case cArpReply:
// 如果是ARP回应,就更新ARP表
msip_Arp_Update(cptArpHdrBuf->SndIpAddr, cptArpHdrBuf->SndEthAddr);
}
arp_in_exit:
// 释放缓冲区
guwEthLen = 0;
}
//--------------------------------------------------------------------------------------
void msip_Arp_Out(ArpEntries_Stru *pARPTAB){
// 如果指针是否在ARP表范围内,就构造以太头
if ((pARPTAB >= cptArpTabStart) && (pARPTAB < cptArpTabEnd)){
goto build_eth;
}
// 指针不在ARP范围,检查远端IP是否在本地网内,以决定ARP请求的远端IP地址
if (((cptIpHdrBuf->DestIpAddr[0] & guwNetMask[0]) == (guwIpAddr[0] & guwNetMask[0])) &&
((cptIpHdrBuf->DestIpAddr[1] & guwNetMask[1]) == (guwIpAddr[1] & guwNetMask[1]))){
// IP在本地网内,在ARP表里查找对应远端IP地址的表指针
for (pARPTAB = cptArpTabStart; pARPTAB < cptArpTabEnd; pARPTAB++){
if((pARPTAB->IpAddr[0] == cptIpHdrBuf->DestIpAddr[0]) &&
(pARPTAB->IpAddr[1] == cptIpHdrBuf->DestIpAddr[1])){
goto build_eth;
}
}
goto request_local;
} else {
// 远端IP不在本地网内,在ARP表里查找网关IP地址的表指针
for (pARPTAB = cptArpTabStart; pARPTAB < cptArpTabEnd; pARPTAB++){
if((pARPTAB->IpAddr[0] == guwDR_IpAddr[0]) && (pARPTAB->IpAddr[1] == guwDR_IpAddr[1])){
goto build_eth;
}
}
//goto request_gateway;
}
// 如果到这里,表明在ARP表里找不到相应的IP记录!所以构造需要的ARP请求包
request_gateway:
cptArpHdrBuf->RcvIpAddr[0] = guwDR_IpAddr[0];
cptArpHdrBuf->RcvIpAddr[1] = guwDR_IpAddr[1];
goto build_arp;
request_local:
cptArpHdrBuf->RcvIpAddr[0] = cptIpHdrBuf->DestIpAddr[0];
cptArpHdrBuf->RcvIpAddr[1] = cptIpHdrBuf->DestIpAddr[1];
build_arp:
cptArpHdrBuf->SndIpAddr[0] = guwIpAddr[0];
cptArpHdrBuf->SndIpAddr[1] = guwIpAddr[1];
cptEthHdrBuf->DestEthAddr[0] = 0xffff;
cptEthHdrBuf->DestEthAddr[1] = 0xffff;
cptEthHdrBuf->DestEthAddr[2] = 0xffff;
cptArpHdrBuf->RcvEthAddr[0] = 0x0000;
cptArpHdrBuf->RcvEthAddr[1] = 0x0000;
cptArpHdrBuf->RcvEthAddr[2] = 0x0000;
cptEthHdrBuf->SrcEthAddr[0] = guwEthAddr[0];
cptArpHdrBuf->SndEthAddr[0] = guwEthAddr[0];
cptEthHdrBuf->SrcEthAddr[1] = guwEthAddr[1];
cptArpHdrBuf->SndEthAddr[1] = guwEthAddr[1];
cptEthHdrBuf->SrcEthAddr[2] = guwEthAddr[2];
cptArpHdrBuf->SndEthAddr[2] = guwEthAddr[2];
cptEthHdrBuf->EthType = cEthType_Arp;
cptArpHdrBuf->HwType = cHwType_Eth;
cptArpHdrBuf->ProtoType = cEthType_Ip;
cptArpHdrBuf->Hw8Proto8 = c_vIP4;
cptArpHdrBuf->OpCode = cArpRequest;
guwEthLen = 60;
goto send_eth; // 跳到发送以太包处理
build_eth:
// 构造需要的以太头
cptEthHdrBuf->DestEthAddr[0] = pARPTAB->EthAddr[0];
cptEthHdrBuf->DestEthAddr[1] = pARPTAB->EthAddr[1];
cptEthHdrBuf->DestEthAddr[2] = pARPTAB->EthAddr[2];
cptEthHdrBuf->SrcEthAddr[0] = guwEthAddr[0];
cptEthHdrBuf->SrcEthAddr[1] = guwEthAddr[1];
cptEthHdrBuf->SrcEthAddr[2] = guwEthAddr[2];
cptEthHdrBuf->EthType = cEthType_Ip;
if ((guwEthLen += 2*cEthHdrLen) < 60){
guwEthLen = 60;
}
send_eth:
ether_Send(); // 发送以太包
guwEthLen = 0; // 释放缓冲区
}
//--------------------------------------------------------------------------------------
#if TCP_ACTIVE_OPEN == 1
UINT16 msip_Connect(UINT16 uwLocalPort, UINT16 *puwRemoteIpAddr, UINT16 uwRemotePort){
Conn_Stru *pConn;
// 检查本地端口是否在本机指定的范围内
if ((uwLocalPort < cLocalPortStart) && (uwLocalPort > cLocalPortEnd)){
return 0;
}
// 检查本地端口是否已经分配或占用
for (pConn = cptConnsStart; pConn < cptConnsEnd; pConn++){
if ((pConn->TcpStateFlags != cTCP_CLOSED) && (pConn->LocalPort == uwLocalPort)){
return 0;
}
}
// 查找TCP事务中的未使用联接(或已经关闭的联接)
for (pConn = cptConnsStart; pConn < cptConnsEnd; pConn++){
if (pConn->TcpStateFlags == cTCP_CLOSED){
// 构造一个主动联接事务
pConn->TcpStateFlags = cTCP_SYN_SENT|cTCP_OUTSTANDING;
pConn->SeqNum[0] = guwISN[0];
pConn->SeqNum[1] = guwISN[1];
pConn->AckNum[0] = guwISN[0];
pConn->AckNum[1] = guwISN[1];
if (++pConn->AckNum[1] == 0){
++pConn->AckNum[0];
}
pConn->NumRetran = 0;
pConn->Timer = 1;
pConn->LocalPort = uwLocalPort;
pConn->RemotePort = uwRemotePort;
pConn->RemoteIpAddr[0] = puwRemoteIpAddr[0];
pConn->RemoteIpAddr[1] = puwRemoteIpAddr[1];
pConn->MaxSegSize = 0; // 远端未知,初始化为:0
return 1;
}
}
// 找不到空闲的TCP联接!
return 0;
}
#endif
//--------------------------------------------------------------------------------------
UINT16 msip_Listen(UINT16 uwPort){
UINT16 index;
for (index = 0; index < cMaxListenPorts; index++){
if (guwListenPorts[index] == 0){
guwListenPorts[index] = uwPort;
return 1;
}
}
return 0;
}
//--------------------------------------------------------------------------------------
UINT16 msip_TcpChkSum(void){
UINT16 SUM , temp;
// 获取TCP段字节长度
temp = cptIpHdrBuf->Len - ((cptIpHdrBuf->Vhl & 0x0f) << 2);
// 计算TCP头和数据段的校验和
SUM = checksum(temp, cpTcpHdrBuf);
// 累加计算伪TCP头的校验和
// 16bit TCP length
if ((SUM += temp) < temp)
++SUM;
// 8bit Protocol
if ((SUM += cptIpHdrBuf->Proto) < cptIpHdrBuf->Proto)
++SUM;
// Source IP Address
if ((SUM += cptIpHdrBuf->SrcIpAddr[0]) < cptIpHdrBuf->SrcIpAddr[0])
++SUM;
if ((SUM += cptIpHdrBuf->SrcIpAddr[1]) < cptIpHdrBuf->SrcIpAddr[1])
++SUM;
// Destination IP Address
if ((SUM += cptIpHdrBuf->DestIpAddr[0]) < cptIpHdrBuf->DestIpAddr[0])
++SUM;
if ((SUM += cptIpHdrBuf->DestIpAddr[1]) < cptIpHdrBuf->DestIpAddr[1])
++SUM;
return SUM;
}
//--------------------------------------------------------------------------------------
void msip_Periodic(){
// 增加初始序号
if (++guwISN[1] == 0){
++guwISN[0];
}
for (gptConn = cptConnsStart; gptConn < cptConnsEnd; gptConn++){
msip_Process(cTCP_TIMER);
}
guwMsg_Route &= ~cM_TCP_PERIODIC; // 清除TCP轮询事件
}
//--------------------------------------------------------------------------------------
void msip_Process(UINT16 uwFlag){
ArpEntries_Stru *pARP = cptArpTabEnd; // 给他一个等价的空指针
UINT16 i,j;
switch (uwFlag){
case cTCP_DATA: // IP输入处理
goto ip_input;
case cTCP_TIMER: // 检验是否TCP事务论询
// goto tcp_Periodic;
}
tcp_Periodic:
guwEthLen = 0;
if ((gptConn->TcpStateFlags == cTCP_TIME_WAIT) ||
(gptConn->TcpStateFlags == cTCP_FIN_WAIT_2)){ // TIMER_WAIT状态:2MSL等待!
if (++gptConn->Timer == cTCP_TIME_WAIT_2MSL){ // 记录等待超时时间,并判断超时
gptConn->TcpStateFlags = cTCP_CLOSED; // 超时关闭联接
}
} else if (gptConn->TcpStateFlags != cTCP_CLOSED){ // 如果是已经关闭的事务,就跳过!
// 如果在OUTSTANDING状态(本地已经发出包,但没有收到回应),需要特殊的重传处理!
if (gptConn->TcpStateFlags & cTCP_OUTSTANDING){
if (--gptConn->Timer == 0){ // 记录等待时间,并校验是否等待时间已过
if (gptConn->NumRetran == cTCP_MAXRTX){ // 记录重传次数,并校验是否到达最大重传次数
// 超过重传次数......
gptConn->TcpStateFlags = cTCP_CLOSED; // 关闭联接
// 通知应用程序时间益出
guwFlags = cTCP_TIMEDOUT;
msip_APPCALL();
// 发RSTACK包通知确认给远端:本地已经异常停止连接!
cptTcpHdrBuf->Flags = cTCP_RST | cTCP_ACK;
goto tcp_send_nodata;
}
// 等待时间的指数退避
gptConn->Timer = cTCP_RTO << (gptConn->NumRetran > 4 ? 4 : gptConn->NumRetran);
++gptConn->NumRetran; // 记录重传次数
// 重传处理变迁
switch (gptConn->TcpStateFlags & cTCP_TS_MASK){
case cTCP_SYN_RCVD: // SYN_RCVD状态:发送SYNACK包
goto tcp_send_synack;
#if TCP_ACTIVE_OPEN == 1
case cTCP_SYN_SENT: // SYN_SENT状态:重发SYN包。
cptTcpHdrBuf->Flags = 0;
goto tcp_send_syn;
#endif
case cTCP_ESTABLISHED: // ESTABLISHED状态:通知应用程序,需要重传上次发出的数据包!!!
guwEthLen = 0;
guwFlags = cTCP_REXMIT;
msip_APPCALL();
goto apprexmit;
case cTCP_CLOSE_WAIT:
case cTCP_LAST_ACK: // LAST_ACK状态,结束当前连接!
goto tcp_send_finack; // 重发FINACK包
case cTCP_FIN_WAIT_1:
goto tcp_send_finack; // 重发FINACK包
case cTCP_FIN_WAIT_2:
case cTCP_CLOSING:
case cTCP_TIME_WAIT:
}
}
} else if ((gptConn->TcpStateFlags & cTCP_TS_MASK) == cTCP_ESTABLISHED){
// ESTABLISHED状态,通知应用程序允许发送数据。
guwEthLen = 0;
guwFlags = cTCP_POLL;
msip_APPCALL();
goto appsend;
}
}
goto drop;
// IP输入处理线程
ip_input:
// IP头校验:IP version and header length. vIP4
if(cptIpHdrBuf->Vhl != cIP_VER_HLEN){
goto drop;
}
// IP分片校验:必须是最后帧才响应(隐含默认:不分片帧)。
if (cptIpHdrBuf->Flags & cIP_MF){
goto drop;
}
// 接收IP包的目标IP地址与本地不相同,丢弃!
if((cptIpHdrBuf->DestIpAddr[0] != guwIpAddr[0]) ||
(cptIpHdrBuf->DestIpAddr[1] != guwIpAddr[1])){
goto drop;
}
// 接收IP包的源地址是与本地相同,丢弃!说明远端在做 DDos 攻击!!!!
if((cptIpHdrBuf->SrcIpAddr[0] == guwIpAddr[0]) &&
(cptIpHdrBuf->SrcIpAddr[1] == guwIpAddr[1])){
goto drop;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -