tcp4misc.c

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

C
1,206
字号
  IN UINT16  HeadSum
  )
/*++

Routine Description:

  Compute the TCP segment's checksum.

Arguments:

  Nbuf    - Pointer to the buffer that contains the TCP segment.
  HeadSum - The checksum value of the fixed part of pseudo header.

Returns:

  The checksum value.

--*/
{
  UINT16  Checksum;

  Checksum  = NetbufChecksum (Nbuf);
  Checksum  = NetAddChecksum (Checksum, HeadSum);

  Checksum = NetAddChecksum (
              Checksum,
              HTONS ((UINT16) Nbuf->TotalSize)
              );

  return ~Checksum;
}

TCP_SEG *
TcpFormatNetbuf (
  IN TCP_CB  *Tcb,
  IN NET_BUF *Nbuf
  )
/*++

Routine Description:

  Translate the information from the head of the received TCP
  segment Nbuf contains and fill it into a TCP_SEG structure.

Arguments:

  Tcb   - Pointer to the TCP_CB of this TCP instance.
  Nbuf  - Pointer to the buffer contains the TCP segment.

Returns:

  Pointer to the TCP_SEG that contains the translated TCP head information.

--*/
{
  TCP_SEG   *Seg;
  TCP_HEAD  *Head;

  Seg       = TCPSEG_NETBUF (Nbuf);
  Head      = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
  Nbuf->Tcp = Head;

  Seg->Seq  = NTOHL (Head->Seq);
  Seg->Ack  = NTOHL (Head->Ack);
  Seg->End  = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));

  Seg->Urg  = NTOHS (Head->Urg);
  Seg->Wnd  = (NTOHS (Head->Wnd) << Tcb->SndWndScale);
  Seg->Flag = Head->Flag;

  //
  // SYN and FIN flag occupy one sequence space each.
  //
  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
    //
    // RFC requires that initial window not be scaled
    //
    Seg->Wnd = NTOHS (Head->Wnd);
    Seg->End++;
  }

  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
    Seg->End++;
  }

  return Seg;
}

VOID
TcpResetConnection (
  IN TCP_CB *Tcb
  )
/*++

Routine Description:

  Reset the connection related with Tcb.

Arguments:

  Tcb - Pointer to the TCP_CB of the connection to be reset.

Returns:

  None

--*/
{
  NET_BUF   *Nbuf;
  TCP_HEAD  *Nhead;

  Nbuf = NetbufAlloc (TCP_MAX_HEAD);

  if (Nbuf == NULL) {
    return ;
  }

  Nhead = (TCP_HEAD *) NetbufAllocSpace (
                        Nbuf,
                        sizeof (TCP_HEAD),
                        NET_BUF_TAIL
                        );

  ASSERT (Nhead != NULL);

  Nbuf->Tcp       = Nhead;

  Nhead->Flag     = TCP_FLG_RST;
  Nhead->Seq      = HTONL (Tcb->SndNxt);
  Nhead->Ack      = HTONL (Tcb->RcvNxt);
  Nhead->SrcPort  = Tcb->LocalEnd.Port;
  Nhead->DstPort  = Tcb->RemoteEnd.Port;
  Nhead->HeadLen  = (sizeof (TCP_HEAD) >> 2);
  Nhead->Res      = 0;
  Nhead->Wnd      = HTONS (0xFFFF);
  Nhead->Checksum = 0;
  Nhead->Urg      = 0;
  Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);

  TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);

  NetbufFree (Nbuf);
}

VOID
TcpOnAppConnect (
  IN TCP_CB  *Tcb
  )
/*++

Routine Description:

  Initialize an active connection, 

Arguments:

  Tcb - Pointer to the TCP_CB that wants to initiate
        a connection.

Returns:

  None

--*/
{
  TcpInitTcbLocal (Tcb);
  TcpSetState (Tcb, TCP_SYN_SENT);

  TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
  TcpToSendData (Tcb, 1);
}

VOID
TcpOnAppClose (
  IN TCP_CB *Tcb
  )
/*++

Routine Description:

  Initiate the connection close procedure, called when
  applications want to close the connection.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.

Returns:

  None.

--*/
{
  ASSERT (Tcb);

  if (!NetListIsEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk)) {

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

    TcpResetConnection (Tcb);
    TcpClose (Tcb);
    return;
  }

  switch (Tcb->State) {
  case TCP_CLOSED:
  case TCP_LISTEN:
  case TCP_SYN_SENT:
    TcpSetState (Tcb, TCP_CLOSED);
    break;

  case TCP_SYN_RCVD:
  case TCP_ESTABLISHED:
    TcpSetState (Tcb, TCP_FIN_WAIT_1);
    break;

  case TCP_CLOSE_WAIT:
    TcpSetState (Tcb, TCP_LAST_ACK);
    break;
  }

  TcpToSendData (Tcb, 1);
}

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

Routine Description:

  Check whether the application's newly delivered data
  can be sent out.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.

Returns:

  0   - Whether the data is sent out or is buffered for
        further sending.
  -1  - The Tcb is not in a state that data is permitted
        to be sent out.

--*/
{

  switch (Tcb->State) {
  case TCP_CLOSED:
    return -1;
    break;

  case TCP_LISTEN:
    return -1;
    break;

  case TCP_SYN_SENT:
  case TCP_SYN_RCVD:
    return 0;
    break;

  case TCP_ESTABLISHED:
  case TCP_CLOSE_WAIT:
    TcpToSendData (Tcb, 0);
    return 0;
    break;

  case TCP_FIN_WAIT_1:
  case TCP_FIN_WAIT_2:
  case TCP_CLOSING:
  case TCP_LAST_ACK:
  case TCP_TIME_WAIT:
    return -1;
    break;
  }

  return 0;
}

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

Routine Description:

  Application has consumed some data, check whether
  to send a window updata ack or a delayed ack.

Arguments:

  Tcb - Pointer to the TCP_CB of this TCP instance.

Returns:
  
--*/
{

  switch (Tcb->State) {
  case TCP_CLOSED:
    return -1;
    break;

  case TCP_LISTEN:
    return -1;
    break;

  case TCP_SYN_SENT:
  case TCP_SYN_RCVD:
    return 0;
    break;

  case TCP_ESTABLISHED:
    if (TcpRcvWinNow (Tcb) > TcpRcvWinOld (Tcb)) {

      if (TcpRcvWinOld (Tcb) < Tcb->RcvMss) {

        TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"
          " update for a window closed Tcb(%x)\n", Tcb));

        TcpSendAck (Tcb);
      } else if (Tcb->DelayedAck == 0) {

        TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"
          " ACK to update window for Tcb(%x)\n", Tcb));

        Tcb->DelayedAck = 1;
      }
    }

    break;

  case TCP_CLOSE_WAIT:
    return 0;
    break;

  case TCP_FIN_WAIT_1:
  case TCP_FIN_WAIT_2:
  case TCP_CLOSING:
  case TCP_LAST_ACK:
  case TCP_TIME_WAIT:
    return -1;
    break;
  }

  return -1;
}

VOID
TcpOnAppAbort (
  IN TCP_CB *Tcb
  )
/*++

Routine Description:

  Abort the connection by sending a reset segment, called
  when the application wants to abort the connection.

Arguments:

  Tcb - Pointer to the TCP_CB of the TCP instance.

Returns:

  None.

--*/
{
  TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "
    "issued by application for TCB %x\n", Tcb));

  switch (Tcb->State) {
  case TCP_SYN_RCVD:
  case TCP_ESTABLISHED:
  case TCP_FIN_WAIT_1:
  case TCP_FIN_WAIT_2:
  case TCP_CLOSE_WAIT:
    TcpResetConnection (Tcb);
    break;
  }

  TcpSetState (Tcb, TCP_CLOSED);
}

EFI_STATUS
TcpSetVariableData (
  IN TCP4_SERVICE_DATA  *Tcp4Service
  )
/*++

Routine Description:

  Set the Tdp4 variable data.

Arguments:

  Tcp4Service - Tcp4 service data.

Returns:

  EFI_OUT_OF_RESOURCES - There are not enough resources to set the variable.
  other                - Set variable failed.

--*/
{
  UINT32                  NumConfiguredInstance;
  NET_LIST_ENTRY          *Entry;
  TCP_CB                  *TcpPcb;
  TCP4_PROTO_DATA         *TcpProto;
  UINTN                   VariableDataSize;
  EFI_TCP4_VARIABLE_DATA  *Tcp4VariableData;
  EFI_TCP4_SERVICE_POINT  *Tcp4ServicePoint;
  CHAR16                  *NewMacString;
  EFI_STATUS              Status;

  NumConfiguredInstance = 0;

  //
  // Go through the running queue to count the instances.
  //
  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
    TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);

    TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;

    if (TcpProto->TcpService == Tcp4Service) {
      //
      // This tcp instance belongs to the Tcp4Service.
      //
      NumConfiguredInstance++;
    }
  }

  //
  // Go through the listening queue to count the instances.
  //
  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
    TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);

    TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;

    if (TcpProto->TcpService == Tcp4Service) {
      //
      // This tcp instance belongs to the Tcp4Service.
      //
      NumConfiguredInstance++;
    }
  }

  //
  // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,
  // we should add extra buffer for the service points only if the number of configured
  // children is more than 1.
  //
  VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);

  if (NumConfiguredInstance > 1) {
    VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);
  }
  
  Tcp4VariableData = NetAllocatePool (VariableDataSize);
  if (Tcp4VariableData == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;
  Tcp4VariableData->ServiceCount = NumConfiguredInstance;

  Tcp4ServicePoint = &Tcp4VariableData->Services[0];

  //
  // Go through the running queue to fill the service points.
  //
  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
    TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);

    TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;

    if (TcpProto->TcpService == Tcp4Service) {
      //
      // This tcp instance belongs to the Tcp4Service.
      //
      Tcp4ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;
      EFI_IP4 (Tcp4ServicePoint->LocalAddress)  = TcpPcb->LocalEnd.Ip;
      Tcp4ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);
      EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;
      Tcp4ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);

      Tcp4ServicePoint++;
    }
  }

  //
  // Go through the listening queue to fill the service points.
  //
  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
    TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);

    TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;

    if (TcpProto->TcpService == Tcp4Service) {
      //
      // This tcp instance belongs to the Tcp4Service.
      //
      Tcp4ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;
      EFI_IP4 (Tcp4ServicePoint->LocalAddress)  = TcpPcb->LocalEnd.Ip;
      Tcp4ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);
      EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;
      Tcp4ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);

      Tcp4ServicePoint++;
    }
  }

  //
  // Get the mac string.
  //
  Status = NetLibGetMacString (
             Tcp4Service->ControllerHandle,
             Tcp4Service->DriverBindingHandle,
             &NewMacString
             );
  if (EFI_ERROR (Status)) {
    goto ON_ERROR;
  }

  if (Tcp4Service->MacString != NULL) {
    //
    // The variable is set already, we're going to update it.
    //
    if (EfiStrCmp (Tcp4Service->MacString, NewMacString) != 0) {
      //
      // The mac address is changed, delete the previous variable first.
      //
      gRT->SetVariable (
             Tcp4Service->MacString,
             &gEfiTcp4ServiceBindingProtocolGuid,
             EFI_VARIABLE_BOOTSERVICE_ACCESS,
             0,
             NULL
             );
    }

    NetFreePool (Tcp4Service->MacString);
  }

  Tcp4Service->MacString = NewMacString;

  Status = gRT->SetVariable (
                  Tcp4Service->MacString,
                  &gEfiTcp4ServiceBindingProtocolGuid,
                  EFI_VARIABLE_BOOTSERVICE_ACCESS,
                  VariableDataSize,
                  (VOID *) Tcp4VariableData
                  );

ON_ERROR:

  NetFreePool (Tcp4VariableData);

  return Status;
}

VOID
TcpClearVariableData (
  IN TCP4_SERVICE_DATA  *Tcp4Service
  )
/*++

Routine Description:

  Clear the variable and free the resource.

Arguments:

  Tcp4Service - Tcp4 service data.

Returns:

  None.

--*/
{
  ASSERT (Tcp4Service->MacString != NULL);

  gRT->SetVariable (
         Tcp4Service->MacString,
         &gEfiTcp4ServiceBindingProtocolGuid,
         EFI_VARIABLE_BOOTSERVICE_ACCESS,
         0,
         NULL
         );

  NetFreePool (Tcp4Service->MacString);
  Tcp4Service->MacString = NULL;
}

⌨️ 快捷键说明

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