/** @file
TCP input process routines.
Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Tcp4Main.h"
/**
Check whether the sequence number of the incoming segment is acceptable.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Seg Pointer to the incoming segment.
@retval 1 The sequence number is acceptable.
@retval 0 The sequence number is not acceptable.
**/
)
{
}
/**
NewReno fast recovery, RFC3782.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Seg Segment that triggers the fast recovery.
**/
)
{
//
// Step 1: Three duplicate ACKs and not in fast recovery
//
//
// Step 1A: Invoking fast retransmission.
//
//
// Step 2: Entering fast retransmission
//
return;
}
//
// During fast recovery, execute Step 3, 4, 5 of RFC3782
//
//
// Step 3: Fast Recovery,
// If this is a duplicated ACK, increse Cwnd by SMSS.
//
// Step 4 is skipped here only to be executed later
// by TcpToSendData
//
} else {
//
// New data is ACKed, check whether it is a
// full ACK or partial ACK
//
//
// Step 5 - Full ACK:
// deflate the congestion window, and exit fast recovery
//
} else {
//
// Step 5 - Partial ACK:
// fast retransmit the first unacknowledge field
// , then deflate the CWnd
//
//
// Deflate the CWnd by the amount of new data
// ACKed by SEG.ACK. If more than one SMSS data
// is ACKed, add back SMSS byte to CWnd after
//
}
}
}
}
/**
NewReno fast loss recovery, RFC3792.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Seg Segment that triggers the fast loss recovery.
**/
)
{
//
// New data is ACKed, check whether it is a
// full ACK or partial ACK
//
//
// Full ACK: exit the loss recovery.
//
} else {
//
// Partial ACK:
// fast retransmit the first unacknowledge field.
//
}
}
}
/**
Compute the RTT as specified in RFC2988.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Measure Currently measured RTT in heart beats.
**/
)
{
//
// Step 2.3: Compute the RTO for subsequent RTT measurement.
//
if (Var < 0) {
}
} else {
//
// Step 2.2: compute the first RTT measure
//
}
//
// Step 2.4: Limit the RTO to at least 1 second
// Step 2.5: Limit the RTO to a maxium value that
// is at least 60 second
//
}
" computed SRTT: %d RTTVAR: %d RTO: %d\n",
}
/**
Trim the data, SYN and FIN to fit into the window defined by Left and Right.
@param Nbuf Buffer that contains received TCP segment without IP header.
@param Left The sequence number of the window's left edge.
@param Right The sequence number of the window's right edge.
**/
)
{
//
// If the segment is completely out of window,
// truncate every thing, include SYN and FIN.
//
return;
}
//
// Adjust the buffer header
//
Drop--;
}
//
// Adjust the urgent point
//
} else {
}
}
if (Drop != 0) {
}
}
//
// Adjust the buffer tail
//
Drop--;
}
if (Drop != 0) {
}
}
}
/**
Trim off the data outside the tcb's receive window.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Nbuf Pointer to the NET_BUF containing the received tcp segment.
**/
)
{
}
/**
Process the data and FIN flag, check whether to deliver
data to the socket layer.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@retval 0 No error occurred to deliver data.
@retval -1 Error condition occurred. Proper response is to reset the
connection.
**/
)
{
//
// make sure there is some data queued,
// and TCP is in a proper state
//
return 0;
}
//
// Deliver data to the socket layer
//
break;
}
//
// RFC793 Eighth step: process FIN in sequence
//
//
// The peer sends to us junky data after FIN,
// reset the connection.
//
" FIN from peer of TCB %p, reset connection\n", Tcb));
NetbufFree (Nbuf);
return -1;
}
"from peer of TCB %p\n", Tcb));
case TCP_SYN_RCVD:
case TCP_ESTABLISHED:
break;
case TCP_FIN_WAIT_1:
break;
}
//
// fall through
//
case TCP_FIN_WAIT_2:
if (Tcb->TimeWaitTimeout != 0) {
} else {
"because app disables TIME_WAIT timer for %p\n", Tcb));
TcpSendAck (Tcb);
}
break;
case TCP_CLOSE_WAIT:
case TCP_CLOSING:
case TCP_LAST_ACK:
case TCP_TIME_WAIT:
//
// The peer sends to us junk FIN byte. Discard
// the buffer then reset the connection
//
NetbufFree (Nbuf);
return -1;
break;
default:
break;
}
}
//
// Don't delay the ack if PUSH flag is on.
//
}
Urgent = 0;
} else {
}
}
}
}
NetbufFree (Nbuf);
}
return 0;
}
/**
Store the data into the reassemble queue.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Nbuf Pointer to the buffer containing the data to be queued.
**/
)
{
NET_GET_REF (Nbuf);
//
// Fast path to process normal case. That is,
// no out-of-order segments are received.
//
if (IsListEmpty (Head)) {
return ;
}
//
// Find the point to insert the buffer
//
break;
}
}
//
// Check whether the current segment overlaps with the
// previous segment.
//
NetbufFree (Nbuf);
return ;
}
}
}
//
// Check the segments after the insert point.
//
NetbufFree (Node);
continue;
}
NetbufFree (Nbuf);
return ;
}
break;
}
}
}
/**
Ajust the send queue or the retransmit queue.
@param Tcb Pointer to the TCP_CB of this TCP instance.
@param Ack The acknowledge seuqence number of the received segment.
**/
)
{
break;
}
//
// Remove completely ACKed segments
//
NetbufFree (Node);
continue;
}
break;
}
}
/**
Process the received TCP segments.
@param Nbuf Buffer that contains received TCP segment without IP header.
@param Src Source address of the segment, or the peer's IP address.
@param Dst Destination address of the segment, or the local end's IP
address.
@retval 0 Segment is processed successfully. It is either accepted or
discarded. But no connection is reset by the segment.
@retval -1 A connection is reset by the segment.
**/
TcpInput (
)
{
goto DISCARD;
}
Len++;
}
Len++;
}
Tcb = TcpLocateTcb (
Dst,
Src,
);
goto SEND_RESET;
}
//
// RFC1122 recommended reaction to illegal option
// (in fact, an illegal option length) is reset.
//
" of mal-format option for Tcb %p\n", Tcb));
goto SEND_RESET;
}
//
// From now on, the segment is headless
//
//
// Process the segment in LISTEN state.
//
//
// First step: Check RST
//
"for TCB %p in listening\n", Tcb));
goto DISCARD;
}
//
// Second step: Check ACK.
// Any ACK sent to TCP in LISTEN is reseted.
//
" segment with ACK for TCB %p in listening\n", Tcb));
goto SEND_RESET;
}
//
// Third step: Check SYN
//
//
// create a child TCB to handle the data
//
" failed to clone a child for TCB%x\n", Tcb));
goto DISCARD;
}
" in listening\n", Tcb));
//
// init the TCB structure
//
goto StepSix;
}
goto DISCARD;
//
// First step: Check ACK bit
//
"wrong ACK received for TCB %p in SYN_SENT\n", Tcb));
goto SEND_RESET;
}
//
// Second step: Check RST bit
//
" peer for TCB %p in SYN_SENT\n", Tcb));
goto DROP_CONNECTION;
} else {
"because of no ACK for TCB %p in SYN_SENT\n", Tcb));
goto DISCARD;
}
}
//
// Third step: Check security and precedence. Skipped
//
//
// Fourth step: Check SYN. Pay attention to sitimulatous open
//
}
}
" for TCB %p in SYN_SENT\n", Tcb));
goto StepSix;
} else {
//
// Received a SYN segment without ACK, simultanous open.
//
"for TCB %p in SYN_SENT\n", Tcb));
goto StepSix;
}
}
goto DISCARD;
}
//
// Process segment in SYN_RCVD or TCP_CONNECTED states
//
//
// Clear probe timer since the RecvWindow is opened.
//
}
//
// First step: Check whether SEG.SEQ is acceptable
//
" test failed for segment of TCB %p\n", Tcb));
TcpSendAck (Tcb);
}
goto DISCARD;
}
}
//
// Second step: Check the RST
//
//
// This TCB comes from either a LISTEN TCB,
// or active open TCB with simultanous open.
// Do NOT signal user CONNECTION refused
// if it comes from a LISTEN TCB.
//
} else {
}
goto DROP_CONNECTION;
}
//
// Trim the data and flags.
//
//
// Third step: Check security and precedence, Ignored
//
//
// Fourth step: Check the SYN bit.
//
"because received extra SYN for TCB %p\n", Tcb));
goto RESET_THEN_DROP;
}
//
// Fifth step: Check the ACK
//
" of no ACK for connected TCB %p\n", Tcb));
goto DISCARD;
}
" for TCB %p in SYN_RCVD\n", Tcb));
//
// Continue the process as ESTABLISHED state
//
} else {
" wrong ACK for TCB %p in SYN_RCVD\n", Tcb));
goto SEND_RESET;
}
}
" ACK for connected TCB %p\n", Tcb));
goto StepSix;
"future ACK for connected TCB %p\n", Tcb));
TcpSendAck (Tcb);
goto DISCARD;
}
//
// From now on: SND.UNA <= SEG.ACK <= SND.NXT.
//
//
// update TsRecent as specified in page 16 RFC1323.
// RcvWl2 equals to the variable "LastAckSent"
// defined there.
//
}
}
} else {
}
//
// Count duplicate acks.
//
(0 == Len)) {
} else {
}
//
// Congestion avoidance, fast recovery and fast retransmission.
//
} else {
}
}
}
} else {
}
}
}
//
// Update window info
//
(Len == 0)) {
goto NO_UPDATE;
}
" window for connected TCB %p\n", Tcb));
}
}
}
}
}
}
" peer for connected TCB %p\n", Tcb));
}
//
// Transit the state if proper.
//
case TCP_FIN_WAIT_1:
}
case TCP_FIN_WAIT_2:
break;
case TCP_CLOSE_WAIT:
break;
case TCP_CLOSING:
if (Tcb->TimeWaitTimeout != 0) {
} else {
"because app disables TIME_WAIT timer for %p\n", Tcb));
}
}
break;
case TCP_LAST_ACK:
}
break;
case TCP_TIME_WAIT:
TcpSendAck (Tcb);
if (Tcb->TimeWaitTimeout != 0) {
} else {
"because app disables TIME_WAIT timer for %p\n", Tcb));
}
break;
default:
break;
}
//
// Sixth step: Check the URG bit.update the Urg point
// if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
//
"from peer for connected TCB %p\n", Tcb));
} else {
}
}
//
// Seventh step: Process the segment data
//
" data is lost for connected TCB %p\n", Tcb));
goto RESET_THEN_DROP;
}
" data is lost for connected TCB %p\n", Tcb));
goto RESET_THEN_DROP;
}
goto RESET_THEN_DROP;
}
}
}
//
// Eighth step: check the FIN.
// This step is moved to TcpDeliverData. FIN will be
// processed in sequence there. Check the comments in
// the beginning of the file header for information.
//
//
// Tcb is a new child of the listening Parent,
// commit it.
//
TcpInsertTcb (Tcb);
}
(TcpToSendData (Tcb, 0) == 0) &&
TcpToSendAck (Tcb);
}
NetbufFree (Nbuf);
return 0;
NetbufFree (Nbuf);
return -1;
//
// Tcb is a child of Parent, and it doesn't survive
//
NetbufFree (Nbuf);
}
return 0;
}
/**
Process the received ICMP error messages for TCP.
@param Nbuf Buffer that contains part of the TCP segment without IP header
truncated from the ICMP error packet.
@param IcmpErr The ICMP error code interpreted from ICMP error packet.
@param Src Source address of the ICMP error message.
@param Dst Destination address of the ICMP error message.
**/
)
{
Tcb = TcpLocateTcb (
Dst,
Src,
);
goto CLEAN_EXIT;
}
//
// Validate the sequence number.
//
goto CLEAN_EXIT;
}
);
if (IcmpErrNotify) {
}
if (IcmpErrIsHard) {
}
NetbufFree (Nbuf);
}