📄 tcp.c
字号:
#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 + -