tcp4input.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,546 行 · 第 1/3 页

C
1,546
字号
/*++

Copyright (c) 2005 - 2006, Intel Corporation                                                         
All rights reserved. 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        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 

Module Name:

  Tcp4Input.c

Abstract:

  TCP input process routines.

--*/

#include "Tcp4Main.h"

INTN
TcpSeqAcceptable (
  IN TCP_CB  *Tcb,
  IN TCP_SEG *Seg
  )
/*++

Routine Description:

  Check whether the sequence number of the incoming segment
  is acceptable.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.
  Seg - Pointer to the incoming segment.

Returns:

  1 if the sequence number is acceptable, otherwise 0.

--*/
{
  return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&
          TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));
}

VOID
TcpFastRecover (
  IN TCP_CB  *Tcb,
  IN TCP_SEG *Seg
  )
/*++

Routine Description:

  NewReno fast recovery, RFC3782.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.
  Seg - Segment that triggers the fast recovery.

Returns:

  None.

--*/
{
  UINT32  FlightSize;
  UINT32  Acked;

  //
  // Step 1: Three duplicate ACKs and not in fast recovery
  //
  if (Tcb->CongestState != TCP_CONGEST_RECOVER) {

    //
    // Step 1A: Invoking fast retransmission.
    //
    FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);

    Tcb->Ssthresh     = NET_MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss));
    Tcb->Recover      = Tcb->SndNxt;

    Tcb->CongestState = TCP_CONGEST_RECOVER;
    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);

    //
    // Step 2: Entering fast retransmission
    //
    TcpRetransmit (Tcb, Tcb->SndUna);
    Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;

    TCP4_DEBUG_TRACE (("TcpFastRecover: enter fast retransmission"
      " for TCB %x, recover point is %d\n", Tcb, Tcb->Recover));
    return;
  }

  //
  // During fast recovery, execute Step 3, 4, 5 of RFC3782
  //
  if (Seg->Ack == Tcb->SndUna) {

    //
    // 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
    //
    Tcb->CWnd += Tcb->SndMss;
    TCP4_DEBUG_TRACE (("TcpFastRecover: received another"
      " duplicated ACK (%d) for TCB %x\n", Seg->Ack, Tcb));

  } else {

    //
    // New data is ACKed, check whether it is a
    // full ACK or partial ACK
    //
    if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) {

      //
      // Step 5 - Full ACK:
      // deflate the congestion window, and exit fast recovery
      //
      FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);

      Tcb->CWnd         = NET_MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss);

      Tcb->CongestState = TCP_CONGEST_OPEN;
      TCP4_DEBUG_TRACE (("TcpFastRecover: received a full ACK(%d)"
        " for TCB %x, exit fast recovery\n", Seg->Ack, Tcb));

    } else {

      //
      // Step 5 - Partial ACK:
      // fast retransmit the first unacknowledge field
      // , then deflate the CWnd
      //
      TcpRetransmit (Tcb, Seg->Ack);
      Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna);

      //
      // 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
      //
      if (Acked >= Tcb->SndMss) {
        Acked -= Tcb->SndMss;

      }

      Tcb->CWnd -= Acked;

      TCP4_DEBUG_TRACE (("TcpFastRecover: received a partial"
        " ACK(%d) for TCB %x\n", Seg->Ack, Tcb));

    }
  }
}

VOID
TcpFastLossRecover (
  IN TCP_CB  *Tcb,
  IN TCP_SEG *Seg
  )
/*++

Routine Description:

  NewReno fast loss recovery, RFC3792.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.
  Seg - Segment that triggers the fast loss recovery.

Returns:

  None.

--*/
{
  if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {

    //
    // New data is ACKed, check whether it is a
    // full ACK or partial ACK
    //
    if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) {

      //
      // Full ACK: exit the loss recovery.
      //
      Tcb->LossTimes    = 0;
      Tcb->CongestState = TCP_CONGEST_OPEN;

      TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "
        "full ACK(%d) for TCB %x\n", Seg->Ack, Tcb));

    } else {

      //
      // Partial ACK:
      // fast retransmit the first unacknowledge field.
      //
      TcpRetransmit (Tcb, Seg->Ack);
      TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "
        "partial ACK(%d) for TCB %x\n", Seg->Ack, Tcb));
    }
  }
}

VOID
TcpComputeRtt (
  IN TCP_CB *Tcb,
  IN UINT32 Measure
  )
/*++

Routine Description:

  Compute the RTT as specified in RFC2988

Arguments:

  Tcb     - Pointer to the TCP_CB of this TCP instance.
  Measure - Currently measured RTT in heart beats.

Returns:

  None.

--*/
{
  INT32 Var;

  //
  // Step 2.3: Compute the RTO for subsequent RTT measurement. 
  //
  if (Tcb->SRtt != 0) {

    Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT);

    if (Var < 0) {
      Var = -Var;
    }

    Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2;
    Tcb->SRtt   = 7 * (Tcb->SRtt >> 3) + Measure;

  } else {
    //
    // Step 2.2: compute the first RTT measure
    //
    Tcb->SRtt   = Measure << TCP_RTT_SHIFT;
    Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1);
  }

  Tcb->Rto = (Tcb->SRtt + NET_MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT;

  //
  // 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
  //
  if (Tcb->Rto < TCP_RTO_MIN) {
    Tcb->Rto = TCP_RTO_MIN;

  } else if (Tcb->Rto > TCP_RTO_MAX) {
    Tcb->Rto = TCP_RTO_MAX;

  }

  TCP4_DEBUG_TRACE (("TcpComputeRtt: new RTT for TCB %x"
    " computed SRTT: %d RTTVAR: %d RTO: %d\n",
    Tcb, Tcb->SRtt, Tcb->RttVar, Tcb->Rto));

}

STATIC
INTN
TcpTrimSegment (
  IN NET_BUF   *Nbuf,
  IN TCP_SEQNO Left,
  IN TCP_SEQNO Right
  )
/*++

Routine Description:

  Trim the data, SYN and FIN to fit into the window defined by
  Left and Right.

Arguments:

  Nbuf  - Buffer that contains received TCP segment without IP header.
  Left  - The sequence number of the window's left edge.
  Right - The sequence number of the window's right edge.

Returns:

  0, the data is successfully trimmed.

--*/
{
  TCP_SEG   *Seg;
  TCP_SEQNO Urg;
  UINT32    Drop;

  Seg = TCPSEG_NETBUF (Nbuf);

  //
  // If the segment is completely out of window,
  // truncate every thing, include SYN and FIN.
  //
  if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {

    TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);
    TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);

    Seg->Seq = Seg->End;
    NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);
    return 0;
  }

  //
  // Adjust the buffer header
  //
  if (TCP_SEQ_LT (Seg->Seq, Left)) {

    Drop      = TCP_SUB_SEQ (Left, Seg->Seq);
    Urg       = Seg->Seq + Seg->Urg;
    Seg->Seq  = Left;

    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
      TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);
      Drop--;
    }

    //
    // Adjust the urgent point
    //
    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {

      if (TCP_SEQ_LT (Urg, Seg->Seq)) {

        TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);
      } else {
        Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);
      }
    }

    if (Drop) {
      NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);
    }
  }

  //
  // Adjust the buffer tail
  //
  if (TCP_SEQ_GT (Seg->End, Right)) {

    Drop      = TCP_SUB_SEQ (Seg->End, Right);
    Seg->End  = Right;

    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
      TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);
      Drop--;
    }

    if (Drop) {
      NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);
    }
  }

  ASSERT (TcpVerifySegment (Nbuf));
  return 0;
}

INTN
TcpTrimInWnd (
  IN TCP_CB  *Tcb,
  IN NET_BUF *Nbuf
  )
/*++

Routine Description:

  Trim off the data outside the tcb's receive window.

Arguments:

  Tcb  - Pointer to the TCP_CB of this TCP instance.
  Nbuf - Pointer to the NET_BUF containing the received tcp segment.

Returns:

  0, the data is trimmed.

--*/
{
  return TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);
}

INTN
TcpDeliverData (
  IN TCP_CB *Tcb
  )
/*++

Routine Description:

  Process the data and FIN flag, check whether to deliver
  data to the socket layer.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.

Returns:

  0   - No error occurred to deliver data.
  -1  - Error condition occurred. Proper response is to reset
        the connection.

--*/
{
  NET_LIST_ENTRY  *Entry;
  NET_BUF         *Nbuf;
  TCP_SEQNO       Seq;
  TCP_SEG         *Seg;
  UINT32          Urgent;

  ASSERT (Tcb && Tcb->Sk);

  //
  // make sure there is some data queued,
  // and TCP is in a proper state
  //
  if (NetListIsEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {

    return 0;
  }

  //
  // Deliver data to the socket layer
  //
  Entry = Tcb->RcvQue.ForwardLink;
  Seq   = Tcb->RcvNxt;

  while (Entry != &Tcb->RcvQue) {
    Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
    Seg   = TCPSEG_NETBUF (Nbuf);

    ASSERT (TcpVerifySegment (Nbuf));
    ASSERT (Nbuf->Tcp == NULL);

    if (TCP_SEQ_GT (Seg->Seq, Seq)) {
      break;
    }

    Entry       = Entry->ForwardLink;
    Seq         = Seg->End;
    Tcb->RcvNxt = Seq;

    NetListRemoveEntry (&Nbuf->List);

    //
    // RFC793 Eighth step: process FIN in sequence
    //
    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {

      //
      // The peer sends to us junky data after FIN,
      // reset the connection.
      //
      if (!NetListIsEmpty (&Tcb->RcvQue)) {
        TCP4_DEBUG_ERROR (("TcpDeliverData: data received after"
          " FIN from peer of TCB %x, reset connection\n", Tcb));

        NetbufFree (Nbuf);
        return -1;
      }

      TCP4_DEBUG_TRACE (("TcpDeliverData: processing FIN "
        "from peer of TCB %x\n", Tcb));

      switch (Tcb->State) {
      case TCP_SYN_RCVD:
      case TCP_ESTABLISHED:

        TcpSetState (Tcb, TCP_CLOSE_WAIT);
        break;

      case TCP_FIN_WAIT_1:

        if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {

          TcpSetState (Tcb, TCP_CLOSING);
          break;
        }

      //
      // fall through
      //
      case TCP_FIN_WAIT_2:

        TcpSetState (Tcb, TCP_TIME_WAIT);

⌨️ 快捷键说明

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