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

📄 tcpip.c

📁 以凌阳单片机SPCE061A为核心的TCPIP协议实现(C原代码)。
💻 C
📖 第 1 页 / 共 3 页
字号:
			(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 + -