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

📄 tcp.c

📁 基于51单片机和RTL8019以太网控制器的嵌入式以太网控制程序。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <general.h>

extern xdata union IP_address temp_ip_address;				   //用于存放临时IP地址
extern xdata union Ethernet_address my_ethernet_address;	   //本机的以太网地址
extern xdata union IP_address my_ip_address;				   //本机的ip地址
extern xdata union IP_address mask_ip_address;	
extern xdata union IP_address gateway_ip_address;
extern unsigned int frameindex;
extern xdata union netcard rxdnet;
xdata union netcard TCPSend;						   // 用于TCP发送缓冲区						   //IP包的序列号
xdata union IP_address my_ServerIP;
//-------------跟超时重发有关的设置------------------------

TCPBUF xdata Queen[QUEENLEN];				//允许有QUEENLEN个数据包在队列里
unsigned char xdata  TCPBuf[BUFLEN];		//缓冲区

// Options: MSS (4 bytes), NOPS (2 bytes), Selective ACK (2 bytes)
unsigned char code opt[10] = {
0x02, 0x04, 0x05, 0xB4,
0x01, 0x01,
0x04, 0x02};


// 最大5个连接
CONNECTION xdata  conxn[NO_CONNECTION];

//初始化序号,根据时间在改变
unsigned long  xdata initial_sequence_nr;
unsigned char idata just_closed; // Keeps track of when a conxn closed


xdata struct wait arpwait;		//用于等待ARP.


xdata union sw Server_PORT;
//#define HTTP_PORT  					3330


xdata union IP_address sender_ipaddr;				   //保存发送者的IP地址
unsigned int xdata sender_tcpport;					   //保存发送者端口
unsigned char idata debug;				//用于调试


extern unsigned char data WriteBuf;	//写内容
extern unsigned char data addr0,addr1;	//地址
sbit P11=P1^1;
//------------------------------------------------------------------------
//函数功能:生成TCP包CRC校验
//
//入参:发送区指针,TCP包的长度(包括头部)
//
//
//
//
//作者:
//
//注意:
//
//
//注释:	Mingtree
//日期:	2004-11-10
//------------------------------------------------------------------------
void createtcpcrc(union netcard xdata *pTxdnet,unsigned int len)//生成TCP包CRC校验
{

	unsigned long sum;
	unsigned int result;
    unsigned int result2;
	unsigned char hdr_len;


	//计算检验和,包括伪头部,TCP头部,数据
   	// Compute checksum including 12 bytes of pseudoheader
	// Must pre-fill 2 items in ip header to do this
	//计算TCP头部长度
	hdr_len=(pTxdnet->tcpframe.offset)>>2;


	//-------------------------------------------------------------
	//				算法1

	// Sum source_ipaddr, dest_ipaddr, and entire TCP message
	sum = (unsigned long)checksum(&(pTxdnet->ippacket.ippacket[6]) , 8 + len);

	// Add in the rest of pseudoheader which is
	// protocol id and TCP segment length
	sum += (unsigned long)0x0006;
	sum += (unsigned long)len;

	// In case there was a carry, add it back around
	result2 = (unsigned int)(sum + (sum >> 16));
//	pTxdnet->tcpframe.crc = ~result;
    result2=~result2;

	//-----------------------------------------------------------


	//-----------------------------------------------------------
	//                算法2

	pTxdnet->ipframe.ttl=0;
	pTxdnet->ipframe.crc=len;
	pTxdnet->ipframe.protocal=0x0006;

	result=checksum(&(pTxdnet->ippacket.ippacket[4]),12+ len);
	pTxdnet->tcpframe.crc=result;
	//-----------------------------------------------------------

}
//------------------------------------------------------------------------
//函数功能:对tcp头进行校验,错误返回0,正确返回1
//
//入参:	无
//
//
//
//
//作者:
//
//注意:
//
//
//注释:	Mingtree
//日期:	2004-11-10
//------------------------------------------------------------------------
unsigned char verifytcpcrc(union netcard xdata *pRxdnet)//对tcp头进行校验,错误返回0,正确返回1
{
	unsigned int crc;

	pRxdnet->ipframe.ttl=0;
        	pRxdnet->ipframe.protocal=0x0006;
	//将IP包的16位首部检验和替换成TCP包的长度
	pRxdnet->ipframe.crc=pRxdnet->ipframe.totallength-(pRxdnet->ipframe.verandihl&0x0f)*4;
	crc=checksum(&(pRxdnet->ippacket.ippacket[4]),pRxdnet->ipframe.crc+12);

	if(crc==0) return (1);
	return(0);
}
//------------------------------------------------------------------------
//函数功能:发送IP包
//
//入参:	发送缓冲区,接收方IP地址,协议类型,低层协议数据包长度(包括头部)
//
//
//
//
//作者:
//
//注意:
//
//
//注释:	Mingtree
//日期:	2004-11-29
//------------------------------------------------------------------------
void ip_send(union netcard xdata *pTxdnet,union IP_address ip, unsigned char proto_id, unsigned int len)
{
	xdata union Ethernet_address  temp;
	//构建以太网包
	pTxdnet->etherframe.protocal=0x0800;
	pTxdnet->etherframe.uSourceID[0]=my_ethernet_address.words[0];
	pTxdnet->etherframe.uSourceID[1]=my_ethernet_address.words[1];
	pTxdnet->etherframe.uSourceID[2]=my_ethernet_address.words[2];
	pTxdnet->ipframe.verandihl=0x45;
	pTxdnet->ipframe.typeofserver=0x00;
	pTxdnet->ipframe.totallength=20+len;
    pTxdnet->ipframe.ttl=0x80;
	pTxdnet->ipframe.frameindex=frameindex;
	frameindex++;
	pTxdnet->ipframe.segment=0x0000;
	pTxdnet->ipframe.protocal=proto_id;
    pTxdnet->ipframe.crc=0;
    pTxdnet->ipframe.destip[0]=ip.words[0];
    pTxdnet->ipframe.destip[1]=ip.words[1];
    pTxdnet->ipframe.sourceip[0]=my_ip_address.words[0];
    pTxdnet->ipframe.sourceip[1]=my_ip_address.words[1];
    pTxdnet->ipframe.crc=createipheadcrc(pTxdnet);

	//判断对方IP是否在同一网段内
	if((ip.dwords & mask_ip_address.dwords) != (my_ip_address.dwords & mask_ip_address.dwords))
	{
		// Use ARP to get hardware address to send this to
		if(findmacadr(gateway_ip_address,&temp))
		{
			//填写目的MAC
			pTxdnet->etherframe.uDestID[0]=temp.words[0];
			pTxdnet->etherframe.uDestID[1]=temp.words[1];
			pTxdnet->etherframe.uDestID[2]=temp.words[2];
			
			send_packet(pTxdnet,34+len);
		}
		else
		{
			// Fill in the destination information so ehrn the ARP response
			// arrives we can identify it and know what to do when we get it
			arpwait.buf = pTxdnet;
			arpwait.ipaddr.dwords = ip.dwords;
			arpwait.proto_id = proto_id;
			arpwait.len = len;
			arpwait.timer = ARP_TIMEOUT;
			arpwait.wait_arp=TRUE;
			arp_request(gateway_ip_address);
		}
	}
	else
	{
		if(findmacadr(ip,&temp))
		{
			//填写目的MAC
			pTxdnet->etherframe.uDestID[0]=temp.words[0];
			pTxdnet->etherframe.uDestID[1]=temp.words[1];
			pTxdnet->etherframe.uDestID[2]=temp.words[2];

			send_packet(pTxdnet,34+len);
		}
		else
		{
			// Fill in the destination information so ehrn the ARP response
			// arrives we can identify it and know what to do when we get it
			arpwait.buf = pTxdnet;
			arpwait.ipaddr.dwords = ip.dwords;
			arpwait.proto_id = proto_id;
			arpwait.len = len;
			arpwait.timer = ARP_TIMEOUT;
			arpwait.wait_arp=TRUE;
			arp_request(ip);
		}
	}
	
}
//------------------------------------------------------------------------
//函数功能:发送TCP包
//
//入参:flags:TCP包的标志,index_conn:表示哪个连接发数据,hdr_len:整个TCP首部的长度
//
//
//
//
//作者:
//
//注意:
//
//
//注释:	Mingtree
//日期:	2004-11-29
//------------------------------------------------------------------------
void tcp_send(union netcard xdata *pTxdnet,unsigned char flags, unsigned char hdr_len, unsigned char index_conn)
{
	union IP_address dest;
	unsigned char i;
   	// If no connection, then message is probably a reset
   	// message which goes back to the sender
   	// Otherwise, use information from the connection.
   	if (index_conn == NO_CONNECTION)
   	{
      	pTxdnet->tcpframe.sourceport = Server_PORT.word;
      	pTxdnet->tcpframe.destport = sender_tcpport;
      	pTxdnet->tcpframe.seqnumber = 0;
      	pTxdnet->tcpframe.acknumber = 0;
      	dest.dwords = sender_ipaddr.dwords;
   	}
   	else if (index_conn  < NO_CONNECTION)
   	{
      	// This message is to connected port
		if(conxn[index_conn].socket_type==SERVER)
      		pTxdnet->tcpframe.sourceport = Server_PORT.word;
		if(conxn[index_conn].socket_type==CLIENT)
			pTxdnet->tcpframe.sourceport = LOCAL_PORT;
      	pTxdnet->tcpframe.destport = conxn[index_conn].port;
      	pTxdnet->tcpframe.seqnumber = conxn[index_conn].my_sequence;
      	pTxdnet->tcpframe.acknumber = conxn[index_conn].his_sequence;
      	dest.dwords = conxn[index_conn].ip.dwords;
   	}
   	else
   	{
   // 	if (debug) PrintStr("TCP: Oops, sock nr out of range\r");
		return;
	}

   	// Total segment length = header length

   	// Insert header len
   	pTxdnet->tcpframe.offset = hdr_len << 2;
	pTxdnet->tcpframe.control = flags;
   	pTxdnet->tcpframe.window = WNDSIZE;
   	pTxdnet->tcpframe.crc = 0;
   	pTxdnet->tcpframe.urg = 0;

   	// Sending SYN with header options
   	if (hdr_len == 28)
   	{
		for(i=0;i<8;i++)
			pTxdnet->tcpframe.tcpdata[i]=opt[i];
   	}
    //计算检验和,包括伪头部,TCP头部,数据
   	// Compute checksum including 12 bytes of pseudoheader
	// Must pre-fill 2 items in ip header to do this
	pTxdnet->ipframe.sourceip[0] = my_ip_address.words[0];
	pTxdnet->ipframe.sourceip[1] = my_ip_address.words[1];

	pTxdnet->ipframe.destip[0] = dest.words[0];
	pTxdnet->ipframe.destip[1] = dest.words[1];

	createtcpcrc(pTxdnet,hdr_len);

 //  	if (debug) PrintStr("TCP: Sending msg to IP layer\r");
	ip_send(pTxdnet, dest, TCP_TYPE, (unsigned int)hdr_len);
}


//------------------------------------------------------------------------
//函数功能:接收TCP包,根据接收到的包来改变连接的状态
//
//入参:	无
//
//
//
//
//作者:
//
//注意:
//
//
//注释:	Mingtree
//日期:	2004-11-29
//修改:2006-02-13,假如对 对方保活探测的相应,即对对方序号小于常值-1的ack发送正常的ack
//------------------------------------------------------------------------
void tcp_rcve(union netcard xdata *pRxdnet)
{
	unsigned int data_len;
	unsigned char i,index,j,header_len;
	unsigned long seq , packACK,packSeq;
	//对tcp头进行校验
	if(verifytcpcrc(pRxdnet))
	{
	//	crccheck(pRxdnet);
		//校验正确

		//取得对方的IP地址,端口号
		sender_ipaddr.words[0]=pRxdnet->ipframe.sourceip[0];
		sender_ipaddr.words[1]=pRxdnet->ipframe.sourceip[1];
		sender_tcpport=pRxdnet->tcpframe.sourceport;

		// 判断该TCP包是否是来自已连接的机器
	    for(i=0;i<NO_CONNECTION;i++)
		{
		   if ((sender_ipaddr.dwords==conxn[i].ip.dwords) &&
				(sender_tcpport==conxn[i].port))
		   {
			  index=i;		//保留序号
//			  if (debug) PrintStr("TCP: Rcvd msg from existing conxn\r");
			  break;
		   }
		}
		//该TCP包来自未连接的机器
		if (NO_CONNECTION==i)
		{
			if (pRxdnet->tcpframe.control & FLG_SYN)
			{
				// Find first unused connection (one with IP = 0)
				for (j=0; j < NO_CONNECTION; j++)
				{
					if (!conxn[j].bUsed)
					{
					   index=j;
					   // Initialize new connection
					   conxn[index].state=STATE_LISTEN;
					   conxn[index].socket_type=SERVER;
					   break;
					}
				 }
				 //所有的连接都被占有,则丢弃该包
				 if (NO_CONNECTION==j) return;
			}
			else
				return;
		  }
		//保证程序不出错
		if (index > NO_CONNECTION-1)
		{
//			if (debug) PrintStr("TCP: Error in assigning conxn number\r");
			return;
		}
		//检查收到的包的序列号是否出错
		if (pRxdnet->tcpframe.seqnumber > 0xFFFFFF00L)
		{
//			if (debug) PrintStr("TCP: Rcvd a high sequence number\r");	
			InerClose(index);
			tcp_send(&TCPSend,FLG_RST, 20, NO_CONNECTION);
			return;
		}
		if (pRxdnet->tcpframe.control & FLG_RST)
		{
			// An RST does not depend on state at all.  And it does
			// not count as data so do not send an ACK here.  Close
			// connection
// 			if (debug) PrintStr("TCP: Rcvd a reset\r");
			InerClose(index);
			return;
		}
		else if (pRxdnet->tcpframe.control & FLG_SYN)
		{
			//收到一个SYN+ACK包,则该包只有在STATE_SYN_SEND时才有效
			//由Mingtree添加,以适应当单片机为客户端时的情况
			if(pRxdnet->tcpframe.control & FLG_ACK)
			{
				if (conxn[index].state != STATE_SYN_SENT)
				{
//					if (debug) PrintStr("TCP: Error, rcvd bogus SYN AND ACK\r");
					tcp_send(&TCPSend,FLG_RST, 20, NO_CONNECTION);
		  			return;
				}
			}

			// A SYN segment only makes sense if connection is in LISTEN
			else if ((conxn[index].state != STATE_LISTEN) &&
				(conxn[index].state != STATE_CLOSED))
			{
//				if (debug) PrintStr("TCP: Error, rcvd bogus SYN\r");
				InerClose(index);
		  		tcp_send(&TCPSend,FLG_RST, 20, NO_CONNECTION);
		  		return;
			}
		}
		else if ((pRxdnet->tcpframe.control & FLG_ACK) == 0)
		{
			// Incoming segments except SYN or RST must have ACK bit set
	 		// See TCP/IP Illustrated, Vol 2, Page 965
			// Drop segment but do not send a reset
//			if (debug) PrintStr("TCP: Error, rcvd segment has no ACK\r");
			return;
		}
		// Compute length of header including options, and from that
		// compute length of actual data
		//计算头部长度,并计算实际长度
		header_len=(pRxdnet->tcpframe.offset&0xF0)>>2;
		data_len=pRxdnet->ipframe.totallength-((pRxdnet->ipframe.verandihl& 0x0F)*4)-header_len;
		packACK = pRxdnet->tcpframe.acknumber;
		packSeq = pRxdnet->tcpframe.seqnumber;
		// Handle TCP state machine for this connection
		switch (conxn[index].state)
		{
			case STATE_CLOSED:
			case STATE_LISTEN:
				// If incoming segment contains SYN and no ACK, then handle
				if ((pRxdnet->tcpframe.control & FLG_SYN) && ((pRxdnet->tcpframe.control & FLG_ACK) == 0))
				{
					// Capture his starting sequence number and generate
					// my starting sequence number
					// Fill in connection information
					conxn[index].ip.words[0]= pRxdnet->ipframe.sourceip[0];
					conxn[index].ip.words[1]= pRxdnet->ipframe.sourceip[1];
					conxn[index].port = pRxdnet->tcpframe.sourceport;
					conxn[index].state = STATE_LISTEN;
					conxn[index].his_sequence = 1 + packACK;
					conxn[index].his_ack = packSeq;

⌨️ 快捷键说明

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