📄 tcp.c
字号:
*/
switch(ps->smState)
{
case TCP_SYN_SENT:
/*
* Keep sending SYN until we hear from remote node.
* This may be for infinite time, in that case
* caller must detect it and do something.
* Bug Fix: 11/1/02
*/
flags = SYN;
break;
case TCP_SYN_RCVD:
/*
* We must receive ACK before timeout expires.
* If not, resend SYN+ACK.
* Abort, if maximum attempts counts are reached.
*/
if ( ps->RetryCount < MAX_RETRY_COUNTS )
{
flags = SYN | ACK;
}
else
CloseSocket(ps);
break;
case TCP_EST:
#if !defined(TCP_NO_WAIT_FOR_ACK)
/*
* Don't let this connection idle for very long time.
* If we did not receive or send any message before timeout
* expires, close this connection.
*/
if ( ps->RetryCount <= MAX_RETRY_COUNTS )
{
if ( ps->TxBuffer != INVALID_BUFFER )
{
MACSetTxBuffer(ps->TxBuffer, 0);
MACFlush();
}
else
flags = ACK;
}
else
{
// Forget about previous transmission.
if ( ps->TxBuffer != INVALID_BUFFER )
MACDiscardTx(ps->TxBuffer);
ps->TxBuffer = INVALID_BUFFER;
#endif
// Request closure.
flags = FIN | ACK;
ps->smState = TCP_FIN_WAIT_1;
#if !defined(TCP_NO_WAIT_FOR_ACK)
}
#endif
break;
case TCP_FIN_WAIT_1:
case TCP_LAST_ACK:
/*
* If we do not receive any response to out close request,
* close it outselves.
*/
if ( ps->RetryCount > MAX_RETRY_COUNTS )
CloseSocket(ps);
else
flags = FIN;
break;
case TCP_CLOSING:
case TCP_TIMED_WAIT:
/*
* If we do not receive any response to out close request,
* close it outselves.
*/
if ( ps->RetryCount > MAX_RETRY_COUNTS )
CloseSocket(ps);
else
flags = ACK;
break;
}
if ( flags > 0x00 )
{
if ( flags != ACK )
seq = ps->SND_SEQ++;
else
seq = ps->SND_SEQ;
SendTCP(&ps->remote,
ps->localPort,
ps->remotePort,
seq,
ps->SND_ACK,
flags);
}
}
#else
return;
#endif
}
/*********************************************************************
* Function: BOOL TCPProcess(NODE_INFO* remote,
* IP_ADDR *localIP,
* WORD len)
*
* PreCondition: TCPInit() is already called AND
* TCP segment is ready in MAC buffer
*
* Input: remote - Remote node info
* len - Total length of TCP semgent.
*
* Output: TRUE if this function has completed its task
* FALSE otherwise
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPProcess(NODE_INFO *remote, IP_ADDR *localIP, WORD len)
{
TCP_HEADER TCPHeader;
PSEUDO_HEADER pseudoHeader;
TCP_SOCKET socket;
WORD_VAL checksum;
BYTE optionsSize;
// Retrieve TCP header.
MACGetArray((BYTE*)&TCPHeader, sizeof(TCPHeader));
SwapTCPHeader(&TCPHeader);
// Calculate IP pseudoheader checksum.
pseudoHeader.SourceAddress = remote->IPAddr;
pseudoHeader.DestAddress.v[0] = localIP->v[0];
pseudoHeader.DestAddress.v[1] = localIP->v[1];
pseudoHeader.DestAddress.v[2] = localIP->v[2];
pseudoHeader.DestAddress.v[3] = localIP->v[3];
pseudoHeader.Zero = 0x0;
pseudoHeader.Protocol = IP_PROT_TCP;
pseudoHeader.TCPLength = len;
SwapPseudoTCPHeader(pseudoHeader);
checksum.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader,
sizeof(pseudoHeader));
// Set TCP packet checksum = pseudo header checksum in MAC RAM.
IPSetRxBuffer(16);
MACPut(checksum.v[0]);
// In case if the end of the RX buffer is reached and a wraparound is needed, set the next address to prevent writing to the wrong address.
IPSetRxBuffer(17);
MACPut(checksum.v[1]);
IPSetRxBuffer(0);
// Now calculate TCP packet checksum in NIC RAM - including
// pesudo header.
checksum.Val = CalcIPBufferChecksum(len);
if ( checksum.Val != TCPHeader.Checksum )
{
MACDiscardRx();
return TRUE;
}
// Skip over options and retrieve all data bytes.
optionsSize = (BYTE)((TCPHeader.DataOffset.Val << 2)-
sizeof(TCPHeader));
len = len - optionsSize - sizeof(TCPHeader);
// Position packet read pointer to start of data area.
IPSetRxBuffer((TCPHeader.DataOffset.Val << 2));
// Find matching socket.
socket = FindMatchingSocket(&TCPHeader, remote);
if ( socket < INVALID_SOCKET )
{
HandleTCPSeg(socket, remote, &TCPHeader, len);
}
else
{
/*
* If this is an unknown socket, discard it and
* send RESET to remote node.
*/
MACDiscardRx();
if ( socket == UNKNOWN_SOCKET )
{
TCPHeader.AckNumber += len;
if ( TCPHeader.Flags.bits.flagSYN ||
TCPHeader.Flags.bits.flagFIN )
TCPHeader.AckNumber++;
SendTCP(remote,
TCPHeader.DestPort,
TCPHeader.SourcePort,
TCPHeader.AckNumber,
TCPHeader.SeqNumber,
RST);
}
}
return TRUE;
}
/*********************************************************************
* Function: static void TransmitTCP(NODE_INFO* remote
* TCP_PORT localPort,
* TCP_PORT remotePort,
* DWORD seq,
* DWORD ack,
* BYTE flags,
* BUFFER buffer,
* WORD len)
*
* PreCondition: TCPInit() is already called AND
* TCPIsPutReady() == TRUE
*
* Input: remote - Remote node info
* localPort - Source port number
* remotePort - Destination port number
* seq - Segment sequence number
* ack - Segment acknowledge number
* flags - Segment flags
* buffer - Buffer to which this segment
* is to be transmitted
* len - Total data length for this segment.
*
* Output: A TCP segment is assembled and put to transmit.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static void TransmitTCP(NODE_INFO *remote,
TCP_PORT localPort,
TCP_PORT remotePort,
DWORD tseq,
DWORD tack,
BYTE flags,
BUFFER buffer,
WORD len)
{
WORD_VAL checkSum;
TCP_HEADER header;
TCP_OPTIONS options;
PSEUDO_HEADER pseudoHeader;
/*
* When using SLIP (USART), packet transmission takes some time
* and hence before sending another packet, we must make sure
* that, last packet is transmitted.
* When using ethernet controller, transmission occurs very fast
* and by the time next packet is transmitted, previous is
* transmitted and we do not need to check for last packet.
*/
while( !IPIsTxReady() );
header.SourcePort = localPort;
header.DestPort = remotePort;
header.SeqNumber = tseq;
header.AckNumber = tack;
header.Flags.bits.Reserved2 = 0;
header.DataOffset.Reserved3 = 0;
header.Flags.byte = flags;
// Receive window = MAC Free buffer size - TCP header (20) - IP header (20)
// - ETHERNET header (14 if using NIC) .
header.Window = MACGetFreeRxSize();
#if !defined(STACK_USE_SLIP)
/*
* Limit one segment at a time from remote host.
* This limit increases overall throughput as remote host does not
* flood us with packets and later retry with significant delay.
*/
if ( header.Window >= MAC_RX_BUFFER_SIZE )
header.Window = MAC_RX_BUFFER_SIZE;
else if ( header.Window > 54 )
{
header.Window -= 54;
}
else
header.Window = 0;
#else
if ( header.Window > 40 )
{
header.Window -= 40;
}
else
header.Window = 0;
#endif
header.Checksum = 0;
header.UrgentPointer = 0;
SwapTCPHeader(&header);
len += sizeof(header);
if ( flags & SYN )
{
len += sizeof(options);
options.Kind = TCP_OPTIONS_MAX_SEG_SIZE;
options.Length = 0x04;
// Load MSS in already swapped order.
options.MaxSegSize.v[0] = (MAC_RX_BUFFER_SIZE >> 8); // 0x05;
options.MaxSegSize.v[1] = (MAC_RX_BUFFER_SIZE & 0xff); // 0xb4;
header.DataOffset.Val = (sizeof(header) + sizeof(options)) >> 2;
}
else
header.DataOffset.Val = sizeof(header) >> 2;
// Calculate IP pseudoheader checksum.
pseudoHeader.SourceAddress.v[0] = MY_IP_BYTE1;
pseudoHeader.SourceAddress.v[1] = MY_IP_BYTE2;
pseudoHeader.SourceAddress.v[2] = MY_IP_BYTE3;
pseudoHeader.SourceAddress.v[3] = MY_IP_BYTE4;
pseudoHeader.DestAddress = remote->IPAddr;
pseudoHeader.Zero = 0x0;
pseudoHeader.Protocol = IP_PROT_TCP;
pseudoHeader.TCPLength = len;
SwapPseudoTCPHeader(pseudoHeader);
header.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader,
sizeof(pseudoHeader));
checkSum.Val = header.Checksum;
if ( buffer == INVALID_BUFFER )
buffer = MACGetTxBuffer();
IPSetTxBuffer(buffer, 0);
// Write IP header.
IPPutHeader(remote, IP_PROT_TCP, len);
IPPutArray((BYTE*)&header, sizeof(header));
if ( flags & SYN )
IPPutArray((BYTE*)&options, sizeof(options));
IPSetTxBuffer(buffer, 0);
checkSum.Val = CalcIPBufferChecksum(len);
// Update the checksum.
IPSetTxBuffer(buffer, 16);
MACPut(checkSum.v[1]);
MACPut(checkSum.v[0]);
MACSetTxBuffer(buffer, 0);
MACFlush();
}
/*********************************************************************
* Function: static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h,
* NODE_INFO* remote)
*
* PreCondition: TCPInit() is already called
*
* Input: h - TCP Header to be matched against.
* remote - Node who sent this header.
*
* Output: A socket that matches with given header and remote
* node is searched.
* If such socket is found, its index is returned
* else INVALID_SOCKET is returned.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h, NODE_INFO *remote)
{
SOCKET_INFO *ps;
TCP_SOCKET s;
TCP_SOCKET partialMatch;
partialMatch = INVALID_SOCKET;
for ( s = 0; s < MAX_SOCKETS; s++ )
{
ps = &TCB[s];
if ( ps->smState != TCP_CLOSED )
{
if ( ps->localPort == h->DestPort )
{
if ( ps->smState == TCP_LISTEN )
partialMatch = s;
if ( ps->remotePort == h->SourcePort &&
ps->remote.IPAddr.Val == remote->IPAddr.Val )
{
return s;
}
}
}
}
ps = &TCB[partialMatch];
if ( partialMatch != INVALID_SOCKET &&
ps->smState == TCP_LISTEN )
{
memcpy((void*)&ps->remote, (void*)remote, sizeof(*remote));
//ps->remote = *remote;
ps->localPort = h->DestPort;
ps->remotePort = h->SourcePort;
ps->Flags.bIsGetReady = FALSE;
ps->TxBuffer = INVALID_BUFFER;
ps->Flags.bIsPutReady = TRUE;
return partialMatch;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -