tcp4input.c

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

C
1,546
字号
  //
  // Second step: Check the RST
  //
  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {

    TCP4_DEBUG_WARN (("TcpInput: connection reset for TCB %x\n", Tcb));

    if (Tcb->State == TCP_SYN_RCVD) {

      SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);

      //
      // 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 if ((Tcb->State == TCP_ESTABLISHED) ||
             (Tcb->State == TCP_FIN_WAIT_1) ||
             (Tcb->State == TCP_FIN_WAIT_2) ||
             (Tcb->State == TCP_CLOSE_WAIT)
            ) {

      SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);

    } else {
      //
      // TODO: set socket error to CLOSED
      //
    }

    goto DROP_CONNECTION;
  }

  //
  // Trim the data and flags.
  //
  TcpTrimInWnd (Tcb, Nbuf);

  //
  // Third step: Check security and precedence, Ignored
  //

  //
  // Fourth step: Check the SYN bit.
  //
  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {

    TCP4_DEBUG_WARN (("TcpInput: connection reset "
      "because received extra SYN for TCB %x\n", Tcb));

    SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
    goto RESET_THEN_DROP;
  }

  //
  // Fifth step: Check the ACK
  //
  if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
    TCP4_DEBUG_WARN (("TcpInput: segment discard because"
      " of no ACK for connected TCB %x\n", Tcb));

    goto DISCARD;

  }

  if (Tcb->State == TCP_SYN_RCVD) {

    if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&
        TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {

      Tcb->SndWnd     = Seg->Wnd;
      Tcb->SndWndMax  = NET_MAX (Tcb->SndWnd, Tcb->SndWndMax);
      Tcb->SndWl1     = Seg->Seq;
      Tcb->SndWl2     = Seg->Ack;
      TcpSetState (Tcb, TCP_ESTABLISHED);

      TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
      TcpDeliverData (Tcb);

      TCP4_DEBUG_TRACE (("TcpInput: connection established "
        " for TCB %x in SYN_RCVD\n", Tcb));

      //
      // Continue the process as ESTABLISHED state
      //
    } else {
      TCP4_DEBUG_WARN (("TcpInput: send reset because of"
        " wrong ACK for TCB %x in SYN_RCVD\n", Tcb));

      goto SEND_RESET;
    }
  }

  if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {

    TCP4_DEBUG_WARN (("TcpInput: ignore the out-of-data"
      " ACK for connected TCB %x\n", Tcb));

    goto StepSix;

  } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {

    TCP4_DEBUG_WARN (("TcpInput: discard segment for "
      "future ACK for connected TCB %x\n", Tcb));

    TcpSendAck (Tcb);
    goto DISCARD;
  }

  //
  // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
  //
  if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {
    //
    // update TsRecent as specified in page 16 RFC1323.
    // RcvWl2 equals to the variable "LastAckSent"
    // defined there.
    //
    if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&
        TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {

      Tcb->TsRecent     = Option.TSVal;
      Tcb->TsRecentAge  = mTcpTick;
    }

    TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));

  } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {

    ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);

    TcpComputeRtt (Tcb, Tcb->RttMeasure);
    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
  }

  if (Seg->Ack == Tcb->SndNxt) {

    TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
  } else {

    TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
  }

  //
  // Count duplicate acks.
  //
  if ((Seg->Ack == Tcb->SndUna) &&
      (Tcb->SndUna != Tcb->SndNxt) &&
      (Seg->Wnd == Tcb->SndWnd) &&
      (0 == Len)) {

    Tcb->DupAck++;
  } else {

    Tcb->DupAck = 0;
  }

  //
  // Congestion avoidance, fast recovery and fast retransmission. 
  //
  if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||
      (Tcb->CongestState == TCP_CONGEST_LOSS)) {

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

      if (Tcb->CWnd < Tcb->Ssthresh) {

        Tcb->CWnd += Tcb->SndMss;
      } else {

        Tcb->CWnd += NET_MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);
      }

      Tcb->CWnd = NET_MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);
    }

    if (Tcb->CongestState == TCP_CONGEST_LOSS) {
      TcpFastLossRecover (Tcb, Seg);
    }
  } else {

    TcpFastRecover (Tcb, Seg);
  }

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

    TcpAdjustSndQue (Tcb, Seg->Ack);
    Tcb->SndUna = Seg->Ack;

    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&
        (TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))) {

      TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
    }
  }

  //
  // Update window info
  //
  if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) || 
      ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) {

    Right = Seg->Ack + Seg->Wnd;

    if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {

      if ((Tcb->SndWl1 == Seg->Seq) &&
          (Tcb->SndWl2 == Seg->Ack) &&
          (Len == 0)) {

        goto NO_UPDATE;
      }

      TCP4_DEBUG_WARN (("TcpInput: peer shrinks the"
        " window  for connected TCB %x\n", Tcb));

      if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&
          (TCP_SEQ_LT (Right, Tcb->Recover))) {

        Tcb->Recover = Right;
      }

      if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&
          (TCP_SEQ_LT (Right, Tcb->LossRecover))) {

        Tcb->LossRecover = Right;
      }

      if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {

        Tcb->SndNxt = Right;

        if (Right == Tcb->SndUna) {

          TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
          TcpSetProbeTimer (Tcb);
        }
      }
    }

    Tcb->SndWnd     = Seg->Wnd;
    Tcb->SndWndMax  = NET_MAX (Tcb->SndWnd, Tcb->SndWndMax);
    Tcb->SndWl1     = Seg->Seq;
    Tcb->SndWl2     = Seg->Ack;
  }

NO_UPDATE:

  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&
      (Tcb->SndUna == Tcb->SndNxt)) {

    TCP4_DEBUG_TRACE (("TcpInput: local FIN is ACKed by"
      " peer for connected TCB %x\n", Tcb));

    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);
  }

  //
  // Transit the state if proper.
  //
  switch (Tcb->State) {
  case TCP_FIN_WAIT_1:

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

      TcpSetState (Tcb, TCP_FIN_WAIT_2);

      TcpClearAllTimer (Tcb);
      TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);
    }

  case TCP_FIN_WAIT_2:

    break;

  case TCP_CLOSE_WAIT:
    break;

  case TCP_CLOSING:

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

      TcpSetState (Tcb, TCP_TIME_WAIT);

      TcpClearAllTimer (Tcb);

      if (Tcb->TimeWaitTimeout != 0) {

        TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
      } else {

        TCP4_DEBUG_WARN (("Connection closed immediately "
          "because app disables TIME_WAIT timer for %x\n", Tcb));

        TcpClose (Tcb);
      }
    }
    break;

  case TCP_LAST_ACK:

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

      TcpSetState (Tcb, TCP_CLOSED);
    }

    break;

  case TCP_TIME_WAIT:

    TcpSendAck (Tcb);

    if (Tcb->TimeWaitTimeout != 0) {

      TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
    } else {

      TCP4_DEBUG_WARN (("Connection closed immediately "
        "because app disables TIME_WAIT timer for %x\n", Tcb));

      TcpClose (Tcb);
    }
    break;
  }

  //
  // Sixth step: Check the URG bit.update the Urg point
  // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
  //
StepSix:

  Tcb->Idle = 0;
  TcpSetKeepaliveTimer (Tcb);

  if (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {

    TcpClearTimer (Tcb, TCP_TIMER_PROBE);
  }

  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) &&
      !TCP_FIN_RCVD (Tcb->State)) {

    TCP4_DEBUG_TRACE (("TcpInput: received urgent data "
      "from peer for connected TCB %x\n", Tcb));

    Urg = Seg->Seq + Seg->Urg;

    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
        TCP_SEQ_GT (Urg, Tcb->RcvUp)) {

      Tcb->RcvUp = Urg;
    } else {

      Tcb->RcvUp = Urg;
      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);
    }
  }

  //
  // Seventh step: Process the segment data
  //
  if (Seg->End != Seg->Seq) {

    if (TCP_FIN_RCVD (Tcb->State)) {

      TCP4_DEBUG_WARN (("TcpInput: connection reset because"
        " data is lost for connected TCB %x\n", Tcb));

      goto RESET_THEN_DROP;
    }

    if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {
      TCP4_DEBUG_WARN (("TcpInput: connection reset because"
        " data is lost for connected TCB %x\n", Tcb));

      goto RESET_THEN_DROP;
    }

    TcpQueueData (Tcb, Nbuf);
    if (TcpDeliverData (Tcb) == -1) {
      goto RESET_THEN_DROP;
    }

    if (!NetListIsEmpty (&Tcb->RcvQue)) {
      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
    }
  }

  //
  // 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.
  //
  if (Parent) {
    Tcb->Parent = Parent;
    TcpInsertTcb (Tcb);
  }

  if ((Tcb->State != TCP_CLOSED) &&
      (!TcpToSendData (Tcb, 0)) &&
      (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || Nbuf->TotalSize)) {

    TcpToSendAck (Tcb);
  }

  NetbufFree (Nbuf);
  return 0;

RESET_THEN_DROP:
  TcpSendReset (Tcb, Head, Len, Dst, Src);

DROP_CONNECTION:
  ASSERT (Tcb && Tcb->Sk);

  NetbufFree (Nbuf);
  TcpClose (Tcb);

  return -1;

SEND_RESET:

  TcpSendReset (Tcb, Head, Len, Dst, Src);

DISCARD:

  //
  // Tcb is a child of Parent, and it doesn't survive
  //
  TCP4_DEBUG_WARN (("Tcp4Input: Discard a packet\n"));
  NetbufFree (Nbuf);

  if (Parent && Tcb) {

    ASSERT (Tcb->Sk);
    TcpClose (Tcb);
  }

  return 0;
}

VOID
TcpIcmpInput (
  IN NET_BUF     *Nbuf,
  IN ICMP_ERROR  IcmpErr,
  IN UINT32      Src,
  IN UINT32      Dst
  )
/*++

Routine Description:

  Process the received ICMP error messages for TCP.

Arguments:

  Nbuf    - Buffer that contains part of the TCP segment without IP header
            truncated from the ICMP error packet.
  IcmpErr - The ICMP error code interpreted from ICMP error packet.
  Src     - Source address of the ICMP error message.
  Dst     - Destination address of the ICMP error message.

Returns:

  None.

--*/
{
  TCP_HEAD    *Head;
  TCP_CB      *Tcb;
  TCP_SEQNO   Seq;

  Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
  Tcb = TcpLocateTcb (
          Head->DstPort,
          Dst,
          Head->SrcPort,
          Src,
          FALSE
          );
  if (Tcb == NULL || Tcb->State == TCP_CLOSED) {

    goto CLEAN_EXIT;
  }

  //
  // Validate the sequence number.
  //
  Seq = NTOHL (Head->Seq);
  if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {

    goto CLEAN_EXIT;
  }

  if (mIcmpErrMap[IcmpErr].Notify) {

    SOCK_ERROR (Tcb->Sk, mIcmpErrMap[IcmpErr].Error);
  }

  if (mIcmpErrMap[IcmpErr].IsHard) {

    TcpClose (Tcb);
  }

CLEAN_EXIT:
  NetbufFree (Nbuf);
}

⌨️ 快捷键说明

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