⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpip.c

📁 凌阳61板上实现的tcp-ic代码 61其实功能挺强的
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -