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

📄 tcpip.c

📁 基于SPCE061A的TCPIP协议
💻 C
📖 第 1 页 / 共 3 页
字号:
	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;
	}

	// IP校验和:错误丢弃!
	i = ((cptIpHdrBuf->Vhl & 0x0f) << 2);
	if (checksum(i, cpIpHdrBuf) != 0xffff){
		goto drop;
	}
	
	// 合法IP包:获取IP包缓冲区长度
	guwEthLen = cptIpHdrBuf->Len;
	
	// 合法IP包:更新ARP表,并记录更新后的映射表指针位置。
	pARP = msip_Arp_Update(cptIpHdrBuf->SrcIpAddr,cptEthHdrBuf->SrcEthAddr);


	// IP协议分组
	switch(cptIpHdrBuf->Proto){
	case cIP_PROTO_ICMP:				// 是否是ICMP包?
		goto icmp_input;
	case cIP_PROTO_TCP:					// 是否TCP包?
		goto tcp_input;
	default:							// 不是我们能处理的包,丢弃!
		goto drop;
	}

	
// ICMP处理线程
icmp_input:

	// ICMP处理:只接受 ping 呼叫,否则丢弃!
	if (cptIcmpHdrBuf->Type != cICMP_ECHO){
		goto drop;
	}

	// 校验 ICMP CheckSum
	i = cptIpHdrBuf->Len - ((cptIpHdrBuf->Vhl & 0x0f) << 2);
	if (checksum(i, cpIcmpHdrBuf) != 0xffff){
		goto drop;
	}
	
	// 处理ICMP的 ping 回应
	cptIcmpHdrBuf->Type = cICMP_ECHO_REPLY;
	
	// 计算 ICMP PING REPLY ChkSum
	if((cptIcmpHdrBuf->ChkSum += (cICMP_ECHO << 8)) < (cICMP_ECHO << 8)){
		cptIcmpHdrBuf->ChkSum += 1;
	} 

	// Swap IP addresses.
	cptIpHdrBuf->SrcIpAddr[0]  ^= cptIpHdrBuf->DestIpAddr[0];
	cptIpHdrBuf->DestIpAddr[0] ^= cptIpHdrBuf->SrcIpAddr[0];
	cptIpHdrBuf->SrcIpAddr[0]  ^= cptIpHdrBuf->DestIpAddr[0];
	
	cptIpHdrBuf->SrcIpAddr[1]  ^= cptIpHdrBuf->DestIpAddr[1];
	cptIpHdrBuf->DestIpAddr[1] ^= cptIpHdrBuf->SrcIpAddr[1];
	cptIpHdrBuf->SrcIpAddr[1]  ^= cptIpHdrBuf->DestIpAddr[1];

	goto send;	// 发送IP包

// TCP线程处理
tcp_input:
	
	// 校验 TCP checksum.
	if (msip_TcpChkSum() != 0xffff){
		goto drop;
	}

	// 是否是已经存在的TCP事务联接
	for (gptConn = cptConnsStart; gptConn < cptConnsEnd; gptConn++){

		if  ((gptConn->TcpStateFlags != cTCP_CLOSED) &&
			(cptIpHdrBuf->SrcIpAddr[0] == gptConn->RemoteIpAddr[0]) &&
			(cptIpHdrBuf->SrcIpAddr[1] == gptConn->RemoteIpAddr[1]) &&
			(cptTcpHdrBuf->DestPort == gptConn->LocalPort) &&
			(cptTcpHdrBuf->SrcPort == gptConn->RemotePort)){

			goto found;
		}
	}
	
	// 如果是不存在的TCP事务:(远端发同步连接请求)
	if (cptTcpHdrBuf->Flags & cTCP_SYN){
	// 1)如果是SYN请求联接包,就侦听本地联接
		for (i = 0; (i < cMaxListenPorts) && (guwListenPorts[i] != 0); i++){
			if (cptTcpHdrBuf->DestPort == guwListenPorts[i]){
				goto found_listen;
			}
		}
	} 

	// 2)如果也不是SYN请求联接包,就发送RSTACK,通知远端本地异常终止该连接!!!(半打开状态)
	// goto reset;	// UIP模式
	goto drop;		// 采用丢弃,防止不相关DDoS攻击!!!


reset:	// 本地异常终止连接处理:发送 RSTACK 包

	// 如果接到的是RSTACK包,不响应!
	if (cptTcpHdrBuf->Flags & cTCP_RST){
		goto drop;
	}

	// 准备发送RSTACK包
	guwEthLen = 2*(cIpHdrLen + cTcpHdrLen);
	cptTcpHdrBuf->HdrLen = cTCP_HDR_NOOPT;
	cptTcpHdrBuf->Flags = cTCP_RST|cTCP_ACK;
	
	// 直接使用远端的SeqNum和AckNum变换为本地的......
	cptTcpHdrBuf->SeqNum[0] ^= cptTcpHdrBuf->AckNum[0];
	cptTcpHdrBuf->AckNum[0] ^= cptTcpHdrBuf->SeqNum[0];
	cptTcpHdrBuf->SeqNum[0] ^= cptTcpHdrBuf->AckNum[0];
	cptTcpHdrBuf->SeqNum[1] ^= cptTcpHdrBuf->AckNum[1];
	cptTcpHdrBuf->AckNum[1] ^= cptTcpHdrBuf->SeqNum[1];
	cptTcpHdrBuf->SeqNum[1] ^= cptTcpHdrBuf->AckNum[1];

	// AckNum加1(SYN逻辑的需要)
	if (++cptTcpHdrBuf->AckNum[1] == 0){
		++cptTcpHdrBuf->AckNum[0];
	}

	// 交换端口
	cptTcpHdrBuf->SrcPort ^= cptTcpHdrBuf->DestPort;
	cptTcpHdrBuf->DestPort ^= cptTcpHdrBuf->SrcPort;
	cptTcpHdrBuf->SrcPort ^= cptTcpHdrBuf->DestPort;

	// 交换IP
	cptIpHdrBuf->SrcIpAddr[0]  ^= cptIpHdrBuf->DestIpAddr[0];
	cptIpHdrBuf->DestIpAddr[0] ^= cptIpHdrBuf->SrcIpAddr[0];
	cptIpHdrBuf->SrcIpAddr[0]  ^= cptIpHdrBuf->DestIpAddr[0];
	cptIpHdrBuf->SrcIpAddr[1]  ^= cptIpHdrBuf->DestIpAddr[1];
	cptIpHdrBuf->DestIpAddr[1] ^= cptIpHdrBuf->SrcIpAddr[1];
	cptIpHdrBuf->SrcIpAddr[1]  ^= cptIpHdrBuf->DestIpAddr[1];

	// 发送RSTACK包
	goto tcp_send_noconn;

// 如果接收的是SYN请求包,本地又有空闲的TCP事务连接
// 1)创建TCP事务连接
// 2)发送SYNACK,进入cTCP_SYN_RCVD|cTCP_OUTSTANDING状态
found_listen:
	// 查找空闲的TCP联接
	for (gptConn = cptConnsStart; gptConn < cptConnsEnd; gptConn++){
		if ((gptConn->TcpStateFlags == cTCP_CLOSED) ||

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -