📄 tcp.c
字号:
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 = AppConfig.MyIPAddr;
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;
// 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();
#if !defined(TCP_NO_WAIT_FOR_ACK) && !defined(DEBUG)
// If we send the packet again, the remote node might think that we timed
// out and retransmitted. It could thus immediately send back an ACK and
// dramatically improve throuput.
while(!IPIsTxReady(TRUE));
MACFlush();
#endif
}
/*********************************************************************
* 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;
}
}
}
}
// We are not listening on this port
if(partialMatch == INVALID_SOCKET)
return INVALID_SOCKET;
// Copy the remote node IP/MAC address and source TCP port
// number into our TCB and return this socket to the caller
ps = &TCB[partialMatch];
memcpy((void*)&ps->remote, (void*)remote, sizeof(*remote));
ps->remotePort = h->SourcePort;
ps->Flags.bIsGetReady = FALSE;
if(ps->TxBuffer != INVALID_BUFFER)
{
MACDiscardTx(ps->TxBuffer);
ps->TxBuffer = INVALID_BUFFER;
}
ps->Flags.bIsPutReady = TRUE;
return partialMatch;
}
/*********************************************************************
* Function: static void SwapTCPHeader(TCP_HEADER* header)
*
* PreCondition: None
*
* Input: header - TCP Header to be swapped.
*
* Output: Given header is swapped.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static void SwapTCPHeader(TCP_HEADER* header)
{
header->SourcePort = swaps(header->SourcePort);
header->DestPort = swaps(header->DestPort);
header->SeqNumber = swapl(header->SeqNumber);
header->AckNumber = swapl(header->AckNumber);
header->Window = swaps(header->Window);
header->Checksum = swaps(header->Checksum);
header->UrgentPointer = swaps(header->UrgentPointer);
}
/*********************************************************************
* Function: static void CloseSocket(SOCKET_INFO* ps)
*
* PreCondition: TCPInit() is already called
*
* Input: ps - Pointer to a socket info that is to be
* closed.
*
* Output: Given socket information is reset and any
* buffer held by this socket is discarded.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static void CloseSocket(SOCKET_INFO* ps)
{
if(ps->TxBuffer != INVALID_BUFFER)
{
MACDiscardTx(ps->TxBuffer);
ps->TxBuffer = INVALID_BUFFER;
ps->Flags.bIsPutReady = TRUE;
}
ps->remote.IPAddr.Val = 0x00;
ps->remotePort = 0x00;
if(ps->Flags.bIsGetReady)
{
MACDiscardRx();
}
ps->Flags.bIsGetReady = FALSE;
ps->TimeOut = TCP_START_TIMEOUT_VAL;
ps->Flags.bIsTxInProgress = FALSE;
if(ps->Flags.bServer)
{
ps->smState = TCP_LISTEN;
}
else
{
ps->smState = TCP_CLOSED;
}
ps->TxCount = 0;
return;
}
/*********************************************************************
* Function: static void HandleTCPSeg(TCP_SOCKET s,
* NODE_INFO *remote,
* TCP_HEADER* h,
* WORD len)
*
* PreCondition: TCPInit() is already called AND
* TCPProcess() is the caller.
*
* Input: s - Socket that owns this segment
* remote - Remote node info
* h - TCP Header
* len - Total buffer length.
*
* Output: TCP FSM is executed on given socket with
* given TCP segment.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static void HandleTCPSeg(TCP_SOCKET s,
NODE_INFO *remote,
TCP_HEADER *h,
WORD len)
{
DWORD ack;
DWORD seq;
DWORD prevAck, prevSeq;
SOCKET_INFO *ps;
BYTE flags;
ps = &TCB[s];
flags = 0x00;
// Clear timeout info
ps->RetryCount = 0;
ps->startTick = TickGet();
ps->TimeOut = TCP_START_TIMEOUT_VAL;
// Reset FSM, if RST is received.
if(h->Flags.bits.flagRST)
{
MACDiscardRx();
ps->smState = ps->Flags.bServer ? TCP_LISTEN : TCP_SYN_SENT;
return;
}
seq = ps->SND_SEQ;
// ack is just a temporary variable
ack = h->Window - (seq - h->AckNumber) - ps->TxCount;
if((signed long)ack < 0)
ps->RemoteWindow = 0;
else
ps->RemoteWindow = ack;
#ifdef STACK_CLIENT_MODE
// Handle TCP_SYN_SENT state
// The TCP_SYN_SENT state occurs when an application
// calls TCPConnect(). After an initial SYN is sent,
// we expect a SYN + ACK before establishing the
// connection.
if(ps->smState == TCP_SYN_SENT)
{
// Check if this is a SYN packet. Unsynchronized, we cannot
// handle any other packet types.
if(!h->Flags.bits.flagSYN)
{
MACDiscardRx();
// Send out a RESET if the remote node thinks a connection is already established
if(h->Flags.bits.flagACK)
{
flags = RST;
goto SendTCPControlPacket;
}
return;
}
// We now have a sequence number for the remote node
ps->SND_ACK = h->SeqNumber + len + 1;
ack = ps->SND_ACK;
// If there is no ACK, we must go to TCP_SYN_RECEIVED. With an ACK,
// we can establish the connection now.
if(!h->Flags.bits.flagACK)
{
ps->smState = TCP_SYN_RECEIVED;
MACDiscardRx();
// Send out a SYN+ACK for simultaneous connection open
flags = SYN | ACK;
goto SendTCPControlPacket;
}
// We received SYN+ACK, establish the connection now
ps->smState = TCP_ESTABLISHED;
// Send out an ACK
flags = ACK;
ps->RemoteWindow = h->Window;
// Check for application data and make it
// available, if present
if(len)
{
ps->Flags.bIsGetReady = TRUE;
ps->RxCount = len;
ps->Flags.bFirstRead = TRUE;
}
else // No application data in this packet
{
MACDiscardRx();
}
goto SendTCPControlPacket;
}
#endif
// Handle TCP_LISTEN state
if(ps->smState == TCP_LISTEN )
{
MACDiscardRx();
// Send a RST if this isn't a SYN packet
if(!h->Flags.bits.flagSYN)
{
flags = RST;
goto SendTCPControlPacket;
}
ps->SND_ACK = h->SeqNumber + len + 1;
ps->RemoteWindow = h->Window;
// This socket has received connection request (SYN).
// Remember calling node, assign next segment seq. number
// for this potential connection.
memcpy((void*)&ps->remote, (const void*)remote, sizeof(*remote));
ps->remotePort = h->SourcePort;
// Grant connection request.
ps->smState = TCP_SYN_RECEIVED;
seq = ps->SND_SEQ++;
ack = ps->SND_ACK;
flags = SYN | ACK;
goto SendTCPControlPacket;
}
// Remember current seq and ack for our connection so that if
// we have to silently discard this packet, we can go back to
// previous ack and seq numbers.
prevAck = ps->SND_ACK;
prevSeq = ps->SND_SEQ;
ack = h->SeqNumber;
ack += (DWORD)len;
seq = ps->SND_SEQ;
// State is something other than TCP_LISTEN, handle it.
{
// Check to see if the incomming sequence number is what
// we expect (last transmitted ACK value). Throw this packet
// away if it is wrong.
if(h->SeqNumber == prevAck)
{
// After receiving a SYNchronization request, we expect an
// ACK to our transmitted SYN
if(ps->smState == TCP_SYN_RECEIVED)
{
if(h->Flags.bits.flagACK)
{
// ACK received as expected, this connection is
// now established
ps->SND_ACK = ack;
ps->smState = TCP_ESTABLISHED;
// Check if this first packet has application data
// in it. Make it available if so.
if(len)
{
ps->Flags.bIsGetReady = TRUE;
ps->RxCount = len;
ps->Flags.bFirstRead = TRUE;
}
else
MACDiscardRx();
}
else // No ACK to our SYN
{
MACDiscardRx();
}
}
// Connection is established, closing, or otherwise
else
{
// Save the seq+len value of the packet for our future
// ACK transmission, and so out of sequence packets
// can be detected in the future.
ps->SND_ACK = ack;
// Handle packets received while connection established.
if(ps->smState == TCP_ESTABLISHED)
{
// If this packet has the ACK set, mark all
// previous TX packets as no longer needed for
// possible retransmission.
// TODO: Make this more sophisticated so that partial ACKs due to fragmentation are handled correctly. i.e. Keep a real output stream buffer with slidable window capability.
if(h->Flags.bits.flagACK && !ps->Flags.bIsPutReady)
{
if(ps->TxBuffer != INVALID_BUFFER)
{
MACDiscardTx(ps->TxBuffer);
ps->TxBuffer = INVALID_BUFFER;
ps->Flags.bIsPutReady = TRUE;
}
}
// Check if the remote node is closing the connection
if(h->Flags.bits.flagFIN)
{
DebugPrint("|");
flags = FIN | ACK;
seq = ps->SND_SEQ++;
ack = ++ps->SND_ACK;
ps->smState = TCP_LAST_ACK;
}
// Check if there is any application data in
// this packet.
if(len)
{
// There is data. Make it available if we
// don't already have data available.
if(!ps->Flags.bIsGetReady)
{
ps->Flags.bIsGetReady = TRUE;
ps->RxCount = len;
ps->Flags.bFirstRead = TRUE;
// 4/1/02
flags |= ACK;
}
// There is data, but we cannot handle it at this time.
else
{
DebugPrint("D");
// Since we cannot accept this packet,
// restore to previous seq and ack.
// and do not send anything back.
// Host has to resend this packet when
// we are ready.
ps->SND_SEQ = prevSeq;
ps->SND_ACK = prevAck;
MACDiscardRx();
}
}
// There is no data in this packet, and thus it
// can be thrown away.
else
{
MACDiscardRx();
}
}
// Connection is not established; check if we've sent
// a FIN and expect our last ACK
else if(ps->smState == TCP_LAST_ACK)
{
MACDiscardRx();
if(h->Flags.bits.flagACK)
{
CloseSocket(ps);
}
}
else if(ps->smState == TCP_FIN_WAIT_1)
{
MACDiscardRx();
if(h->Flags.bits.flagFIN)
{
flags = ACK;
ack = ++ps->SND_ACK;
if(h->Flags.bits.flagACK)
{
CloseSocket(ps);
}
else
{
ps->smState = TCP_CLOSING;
}
}
else if(h->Flags.bits.flagACK)
{
ps->smState = TCP_FIN_WAIT_2;
}
}
else if(ps->smState == TCP_FIN_WAIT_2)
{
MACDiscardRx();
if(h->Flags.bits.flagFIN)
{
flags = ACK;
ack = ++ps->SND_ACK;
CloseSocket(ps);
}
}
else if ( ps->smState == TCP_CLOSING )
{
MACDiscardRx();
if ( h->Flags.bits.flagACK )
{
CloseSocket(ps);
}
}
}
}
// This packet's sequence number does not match what we were
// expecting (the last value we ACKed). Throw this packet
// away. This may happen if packets are delivered out of order.
// Not enough memory is available on our PIC or Ethernet
// controller to implement a robust stream reconstruction
// buffer. As a result, the remote node will just have to
// retransmit its packets starting with the proper sequence number.
else
{
MACDiscardRx();
// Send a new ACK out in case if the previous one was lost
// (ACKs aren't ACKed). This is required to prevent an
// unlikely but possible situation which would cause the
// connection to time out if the ACK was lost and the
// remote node keeps sending us older data than we are
// expecting.
flags = ACK;
ack = prevAck;
}
}
SendTCPControlPacket:
if(flags)
{
SendTCP(remote,
h->DestPort,
h->SourcePort,
seq,
ack,
flags);
}
}
#endif //#if defined(STACK_USE_TCP)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -