mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			1031 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1031 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Misc support routines for TCP driver.
 | 
						|
 | 
						|
  (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
 | 
						|
  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "TcpMain.h"
 | 
						|
 | 
						|
LIST_ENTRY  mTcpRunQue = {
 | 
						|
  &mTcpRunQue,
 | 
						|
  &mTcpRunQue
 | 
						|
};
 | 
						|
 | 
						|
LIST_ENTRY  mTcpListenQue = {
 | 
						|
  &mTcpListenQue,
 | 
						|
  &mTcpListenQue
 | 
						|
};
 | 
						|
 | 
						|
TCP_SEQNO  mTcpGlobalIss = TCP_BASE_ISS;
 | 
						|
 | 
						|
CHAR16  *mTcpStateName[] = {
 | 
						|
  L"TCP_CLOSED",
 | 
						|
  L"TCP_LISTEN",
 | 
						|
  L"TCP_SYN_SENT",
 | 
						|
  L"TCP_SYN_RCVD",
 | 
						|
  L"TCP_ESTABLISHED",
 | 
						|
  L"TCP_FIN_WAIT_1",
 | 
						|
  L"TCP_FIN_WAIT_2",
 | 
						|
  L"TCP_CLOSING",
 | 
						|
  L"TCP_TIME_WAIT",
 | 
						|
  L"TCP_CLOSE_WAIT",
 | 
						|
  L"TCP_LAST_ACK"
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the Tcb local related members.
 | 
						|
 | 
						|
  @param[in, out]  Tcb               Pointer to the TCP_CB of this TCP instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpInitTcbLocal (
 | 
						|
  IN OUT TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Compute the checksum of the fixed parts of pseudo header
 | 
						|
  //
 | 
						|
  if (Tcb->Sk->IpVersion == IP_VERSION_4) {
 | 
						|
    Tcb->HeadSum = NetPseudoHeadChecksum (
 | 
						|
                     Tcb->LocalEnd.Ip.Addr[0],
 | 
						|
                     Tcb->RemoteEnd.Ip.Addr[0],
 | 
						|
                     0x06,
 | 
						|
                     0
 | 
						|
                     );
 | 
						|
  } else {
 | 
						|
    Tcb->HeadSum = NetIp6PseudoHeadChecksum (
 | 
						|
                     &Tcb->LocalEnd.Ip.v6,
 | 
						|
                     &Tcb->RemoteEnd.Ip.v6,
 | 
						|
                     0x06,
 | 
						|
                     0
 | 
						|
                     );
 | 
						|
  }
 | 
						|
 | 
						|
  Tcb->Iss    = TcpGetIss ();
 | 
						|
  Tcb->SndUna = Tcb->Iss;
 | 
						|
  Tcb->SndNxt = Tcb->Iss;
 | 
						|
 | 
						|
  Tcb->SndWl2 = Tcb->Iss;
 | 
						|
  Tcb->SndWnd = 536;
 | 
						|
 | 
						|
  Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk);
 | 
						|
 | 
						|
  //
 | 
						|
  // First window size is never scaled
 | 
						|
  //
 | 
						|
  Tcb->RcvWndScale   = 0;
 | 
						|
  Tcb->RetxmitSeqMax = 0;
 | 
						|
 | 
						|
  Tcb->ProbeTimerOn = FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the peer related members.
 | 
						|
 | 
						|
  @param[in, out]  Tcb    Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param[in]       Seg    Pointer to the segment that contains the peer's initial info.
 | 
						|
  @param[in]       Opt    Pointer to the options announced by the peer.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpInitTcbPeer (
 | 
						|
  IN OUT TCP_CB      *Tcb,
 | 
						|
  IN     TCP_SEG     *Seg,
 | 
						|
  IN     TCP_OPTION  *Opt
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  RcvMss;
 | 
						|
 | 
						|
  ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL));
 | 
						|
  ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));
 | 
						|
 | 
						|
  Tcb->SndWnd    = Seg->Wnd;
 | 
						|
  Tcb->SndWndMax = Tcb->SndWnd;
 | 
						|
  Tcb->SndWl1    = Seg->Seq;
 | 
						|
 | 
						|
  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
 | 
						|
    Tcb->SndWl2 = Seg->Ack;
 | 
						|
  } else {
 | 
						|
    Tcb->SndWl2 = Tcb->Iss + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {
 | 
						|
    Tcb->SndMss = (UINT16)MAX (64, Opt->Mss);
 | 
						|
 | 
						|
    RcvMss = TcpGetRcvMss (Tcb->Sk);
 | 
						|
    if (Tcb->SndMss > RcvMss) {
 | 
						|
      Tcb->SndMss = RcvMss;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // One end doesn't support MSS option, use default.
 | 
						|
    //
 | 
						|
    Tcb->RcvMss = 536;
 | 
						|
  }
 | 
						|
 | 
						|
  Tcb->CWnd = Tcb->SndMss;
 | 
						|
 | 
						|
  Tcb->Irs    = Seg->Seq;
 | 
						|
  Tcb->RcvNxt = Tcb->Irs + 1;
 | 
						|
 | 
						|
  Tcb->RcvWl2 = Tcb->RcvNxt;
 | 
						|
 | 
						|
  if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) {
 | 
						|
    Tcb->SndWndScale = Opt->WndScale;
 | 
						|
 | 
						|
    Tcb->RcvWndScale = TcpComputeScale (Tcb);
 | 
						|
    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // One end doesn't support window scale option. use zero.
 | 
						|
    //
 | 
						|
    Tcb->RcvWndScale = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {
 | 
						|
    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);
 | 
						|
    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);
 | 
						|
 | 
						|
    Tcb->TsRecent = Opt->TSVal;
 | 
						|
 | 
						|
    //
 | 
						|
    // Compute the effective SndMss per RFC1122
 | 
						|
    // section 4.2.2.6. If timestamp option is
 | 
						|
    // enabled, it will always occupy 12 bytes.
 | 
						|
    //
 | 
						|
    Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether one IP address equals the other.
 | 
						|
 | 
						|
  @param[in]   Ip1     Pointer to IP address to be checked.
 | 
						|
  @param[in]   Ip2     Pointer to IP address to be checked.
 | 
						|
  @param[in]   Version IP_VERSION_4 indicates the IP address is an IPv4 address,
 | 
						|
                       IP_VERSION_6 indicates the IP address is an IPv6 address.
 | 
						|
 | 
						|
  @retval      TRUE    Ip1 equals Ip2.
 | 
						|
  @retval      FALSE   Ip1 does not equal Ip2.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
TcpIsIpEqual (
 | 
						|
  IN EFI_IP_ADDRESS  *Ip1,
 | 
						|
  IN EFI_IP_ADDRESS  *Ip2,
 | 
						|
  IN UINT8           Version
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));
 | 
						|
 | 
						|
  if (Version == IP_VERSION_4) {
 | 
						|
    return (BOOLEAN)(Ip1->Addr[0] == Ip2->Addr[0]);
 | 
						|
  } else {
 | 
						|
    return (BOOLEAN)EFI_IP6_EQUAL (&Ip1->v6, &Ip2->v6);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether one IP address is filled with ZERO.
 | 
						|
 | 
						|
  @param[in]   Ip      Pointer to the IP address to be checked.
 | 
						|
  @param[in]   Version IP_VERSION_4 indicates the IP address is an IPv4 address,
 | 
						|
                       IP_VERSION_6 indicates the IP address is an IPv6 address.
 | 
						|
 | 
						|
  @retval      TRUE    Ip is all zero address.
 | 
						|
  @retval      FALSE   Ip is not all zero address.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
TcpIsIpZero (
 | 
						|
  IN EFI_IP_ADDRESS  *Ip,
 | 
						|
  IN UINT8           Version
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));
 | 
						|
 | 
						|
  if (Version == IP_VERSION_4) {
 | 
						|
    return (BOOLEAN)(Ip->Addr[0] == 0);
 | 
						|
  } else {
 | 
						|
    return (BOOLEAN)((Ip->Addr[0] == 0) && (Ip->Addr[1] == 0) &&
 | 
						|
                     (Ip->Addr[2] == 0) && (Ip->Addr[3] == 0));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Locate a listen TCB that matchs the Local and Remote.
 | 
						|
 | 
						|
  @param[in]  Local    Pointer to the local (IP, Port).
 | 
						|
  @param[in]  Remote   Pointer to the remote (IP, Port).
 | 
						|
  @param[in]  Version  IP_VERSION_4 indicates TCP is running on IP4 stack,
 | 
						|
                       IP_VERSION_6 indicates TCP is running on IP6 stack.
 | 
						|
 | 
						|
  @return  Pointer to the TCP_CB with the least number of wildcards,
 | 
						|
           if NULL no match is found.
 | 
						|
 | 
						|
**/
 | 
						|
TCP_CB *
 | 
						|
TcpLocateListenTcb (
 | 
						|
  IN TCP_PEER  *Local,
 | 
						|
  IN TCP_PEER  *Remote,
 | 
						|
  IN UINT8     Version
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY  *Entry;
 | 
						|
  TCP_CB      *Node;
 | 
						|
  TCP_CB      *Match;
 | 
						|
  INTN        Last;
 | 
						|
  INTN        Cur;
 | 
						|
 | 
						|
  Last  = 4;
 | 
						|
  Match = NULL;
 | 
						|
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
 | 
						|
    Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
 | 
						|
 | 
						|
    if ((Version != Node->Sk->IpVersion) ||
 | 
						|
        (Local->Port != Node->LocalEnd.Port) ||
 | 
						|
        !TCP_PEER_MATCH (Remote, &Node->RemoteEnd, Version) ||
 | 
						|
        !TCP_PEER_MATCH (Local, &Node->LocalEnd, Version)
 | 
						|
        )
 | 
						|
    {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Compute the number of wildcard
 | 
						|
    //
 | 
						|
    Cur = 0;
 | 
						|
    if (TcpIsIpZero (&Node->RemoteEnd.Ip, Version)) {
 | 
						|
      Cur++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Node->RemoteEnd.Port == 0) {
 | 
						|
      Cur++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (TcpIsIpZero (&Node->LocalEnd.Ip, Version)) {
 | 
						|
      Cur++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Cur < Last) {
 | 
						|
      if (Cur == 0) {
 | 
						|
        return Node;
 | 
						|
      }
 | 
						|
 | 
						|
      Last  = Cur;
 | 
						|
      Match = Node;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Match;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
 | 
						|
 | 
						|
  @param[in]  Addr     Pointer to the IP address needs to match.
 | 
						|
  @param[in]  Port     The port number needs to match.
 | 
						|
  @param[in]  Version  IP_VERSION_4 indicates TCP is running on IP4 stack,
 | 
						|
                       IP_VERSION_6 indicates TCP is running on IP6 stack.
 | 
						|
 | 
						|
 | 
						|
  @retval     TRUE     The Tcb which matches the <Addr Port> pair exists.
 | 
						|
  @retval     FALSE    Otherwise
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
TcpFindTcbByPeer (
 | 
						|
  IN EFI_IP_ADDRESS  *Addr,
 | 
						|
  IN TCP_PORTNO      Port,
 | 
						|
  IN UINT8           Version
 | 
						|
  )
 | 
						|
{
 | 
						|
  TCP_PORTNO  LocalPort;
 | 
						|
  LIST_ENTRY  *Entry;
 | 
						|
  TCP_CB      *Tcb;
 | 
						|
 | 
						|
  ASSERT ((Addr != NULL) && (Port != 0));
 | 
						|
 | 
						|
  LocalPort = HTONS (Port);
 | 
						|
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
 | 
						|
    Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
 | 
						|
 | 
						|
    if ((Version == Tcb->Sk->IpVersion) &&
 | 
						|
        TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&
 | 
						|
        (LocalPort == Tcb->LocalEnd.Port)
 | 
						|
        )
 | 
						|
    {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
 | 
						|
    Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
 | 
						|
 | 
						|
    if ((Version == Tcb->Sk->IpVersion) &&
 | 
						|
        TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&
 | 
						|
        (LocalPort == Tcb->LocalEnd.Port)
 | 
						|
        )
 | 
						|
    {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Locate the TCP_CB related to the socket pair.
 | 
						|
 | 
						|
  @param[in]  LocalPort      The local port number.
 | 
						|
  @param[in]  LocalIp        The local IP address.
 | 
						|
  @param[in]  RemotePort     The remote port number.
 | 
						|
  @param[in]  RemoteIp       The remote IP address.
 | 
						|
  @param[in]  Version        IP_VERSION_4 indicates TCP is running on IP4 stack,
 | 
						|
                             IP_VERSION_6 indicates TCP is running on IP6 stack.
 | 
						|
  @param[in]  Syn            If TRUE, the listen sockets are searched.
 | 
						|
 | 
						|
  @return Pointer to the related TCP_CB. If NULL, no match is found.
 | 
						|
 | 
						|
**/
 | 
						|
TCP_CB *
 | 
						|
TcpLocateTcb (
 | 
						|
  IN TCP_PORTNO      LocalPort,
 | 
						|
  IN EFI_IP_ADDRESS  *LocalIp,
 | 
						|
  IN TCP_PORTNO      RemotePort,
 | 
						|
  IN EFI_IP_ADDRESS  *RemoteIp,
 | 
						|
  IN UINT8           Version,
 | 
						|
  IN BOOLEAN         Syn
 | 
						|
  )
 | 
						|
{
 | 
						|
  TCP_PEER    Local;
 | 
						|
  TCP_PEER    Remote;
 | 
						|
  LIST_ENTRY  *Entry;
 | 
						|
  TCP_CB      *Tcb;
 | 
						|
 | 
						|
  Local.Port  = LocalPort;
 | 
						|
  Remote.Port = RemotePort;
 | 
						|
 | 
						|
  CopyMem (&Local.Ip, LocalIp, sizeof (EFI_IP_ADDRESS));
 | 
						|
  CopyMem (&Remote.Ip, RemoteIp, sizeof (EFI_IP_ADDRESS));
 | 
						|
 | 
						|
  //
 | 
						|
  // First check for exact match.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
 | 
						|
    Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
 | 
						|
 | 
						|
    if ((Version == Tcb->Sk->IpVersion) &&
 | 
						|
        TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd, Version) &&
 | 
						|
        TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd, Version)
 | 
						|
        )
 | 
						|
    {
 | 
						|
      RemoveEntryList (&Tcb->List);
 | 
						|
      InsertHeadList (&mTcpRunQue, &Tcb->List);
 | 
						|
 | 
						|
      return Tcb;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Only check the listen queue when the SYN flag is on.
 | 
						|
  //
 | 
						|
  if (Syn) {
 | 
						|
    return TcpLocateListenTcb (&Local, &Remote, Version);
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert a Tcb into the proper queue.
 | 
						|
 | 
						|
  @param[in]  Tcb               Pointer to the TCP_CB to be inserted.
 | 
						|
 | 
						|
  @retval 0                     The Tcb was inserted successfully.
 | 
						|
  @retval -1                    Error condition occurred.
 | 
						|
 | 
						|
**/
 | 
						|
INTN
 | 
						|
TcpInsertTcb (
 | 
						|
  IN TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY  *Entry;
 | 
						|
  LIST_ENTRY  *Head;
 | 
						|
  TCP_CB      *Node;
 | 
						|
 | 
						|
  ASSERT (
 | 
						|
    (Tcb != NULL) &&
 | 
						|
    (
 | 
						|
     (Tcb->State == TCP_LISTEN) ||
 | 
						|
     (Tcb->State == TCP_SYN_SENT) ||
 | 
						|
     (Tcb->State == TCP_SYN_RCVD) ||
 | 
						|
     (Tcb->State == TCP_CLOSED)
 | 
						|
    )
 | 
						|
    );
 | 
						|
 | 
						|
  if (Tcb->LocalEnd.Port == 0) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  Head = &mTcpRunQue;
 | 
						|
 | 
						|
  if (Tcb->State == TCP_LISTEN) {
 | 
						|
    Head = &mTcpListenQue;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check that the Tcb isn't already on the list.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, Head) {
 | 
						|
    Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
 | 
						|
 | 
						|
    if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd, Tcb->Sk->IpVersion) &&
 | 
						|
        TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd, Tcb->Sk->IpVersion)
 | 
						|
        )
 | 
						|
    {
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  InsertHeadList (Head, &Tcb->List);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clone a TCP_CB from Tcb.
 | 
						|
 | 
						|
  @param[in]  Tcb                   Pointer to the TCP_CB to be cloned.
 | 
						|
 | 
						|
  @return Pointer to the new cloned TCP_CB; if NULL, error condition occurred.
 | 
						|
 | 
						|
**/
 | 
						|
TCP_CB *
 | 
						|
TcpCloneTcb (
 | 
						|
  IN TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  TCP_CB  *Clone;
 | 
						|
 | 
						|
  Clone = AllocateZeroPool (sizeof (TCP_CB));
 | 
						|
 | 
						|
  if (Clone == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (Clone, Tcb, sizeof (TCP_CB));
 | 
						|
 | 
						|
  //
 | 
						|
  // Increase the reference count of the shared IpInfo.
 | 
						|
  //
 | 
						|
  NET_GET_REF (Tcb->IpInfo);
 | 
						|
 | 
						|
  InitializeListHead (&Clone->List);
 | 
						|
  InitializeListHead (&Clone->SndQue);
 | 
						|
  InitializeListHead (&Clone->RcvQue);
 | 
						|
 | 
						|
  Clone->Sk = SockClone (Tcb->Sk);
 | 
						|
  if (Clone->Sk == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "TcpCloneTcb: failed to clone a sock\n"));
 | 
						|
    FreePool (Clone);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  ((TCP_PROTO_DATA *)(Clone->Sk->ProtoReserved))->TcpPcb = Clone;
 | 
						|
 | 
						|
  return Clone;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compute an ISS to be used by a new connection.
 | 
						|
 | 
						|
  @return The resulting ISS.
 | 
						|
 | 
						|
**/
 | 
						|
TCP_SEQNO
 | 
						|
TcpGetIss (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  mTcpGlobalIss += TCP_ISS_INCREMENT_1;
 | 
						|
  return mTcpGlobalIss;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the local mss.
 | 
						|
 | 
						|
  @param[in]  Sock        Pointer to the socket to get mss.
 | 
						|
 | 
						|
  @return The mss size.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
TcpGetRcvMss (
 | 
						|
  IN SOCKET  *Sock
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_IP4_MODE_DATA  Ip4Mode;
 | 
						|
  EFI_IP6_MODE_DATA  Ip6Mode;
 | 
						|
  EFI_IP4_PROTOCOL   *Ip4;
 | 
						|
  EFI_IP6_PROTOCOL   *Ip6;
 | 
						|
  TCP_PROTO_DATA     *TcpProto;
 | 
						|
 | 
						|
  ASSERT (Sock != NULL);
 | 
						|
 | 
						|
  ZeroMem (&Ip4Mode, sizeof (EFI_IP4_MODE_DATA));
 | 
						|
  ZeroMem (&Ip6Mode, sizeof (EFI_IP6_MODE_DATA));
 | 
						|
 | 
						|
  TcpProto = (TCP_PROTO_DATA *)Sock->ProtoReserved;
 | 
						|
 | 
						|
  if (Sock->IpVersion == IP_VERSION_4) {
 | 
						|
    Ip4 = TcpProto->TcpService->IpIo->Ip.Ip4;
 | 
						|
    ASSERT (Ip4 != NULL);
 | 
						|
    Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL);
 | 
						|
 | 
						|
    return (UINT16)(Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));
 | 
						|
  } else {
 | 
						|
    Ip6 = TcpProto->TcpService->IpIo->Ip.Ip6;
 | 
						|
    ASSERT (Ip6 != NULL);
 | 
						|
    if (!EFI_ERROR (Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL))) {
 | 
						|
      if (Ip6Mode.AddressList != NULL) {
 | 
						|
        FreePool (Ip6Mode.AddressList);
 | 
						|
      }
 | 
						|
 | 
						|
      if (Ip6Mode.GroupTable != NULL) {
 | 
						|
        FreePool (Ip6Mode.GroupTable);
 | 
						|
      }
 | 
						|
 | 
						|
      if (Ip6Mode.RouteTable != NULL) {
 | 
						|
        FreePool (Ip6Mode.RouteTable);
 | 
						|
      }
 | 
						|
 | 
						|
      if (Ip6Mode.NeighborCache != NULL) {
 | 
						|
        FreePool (Ip6Mode.NeighborCache);
 | 
						|
      }
 | 
						|
 | 
						|
      if (Ip6Mode.PrefixTable != NULL) {
 | 
						|
        FreePool (Ip6Mode.PrefixTable);
 | 
						|
      }
 | 
						|
 | 
						|
      if (Ip6Mode.IcmpTypeList != NULL) {
 | 
						|
        FreePool (Ip6Mode.IcmpTypeList);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return (UINT16)(Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the Tcb's state.
 | 
						|
 | 
						|
  @param[in]  Tcb                   Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param[in]  State                 The state to be set.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpSetState (
 | 
						|
  IN TCP_CB  *Tcb,
 | 
						|
  IN UINT8   State
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));
 | 
						|
  ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));
 | 
						|
 | 
						|
  DEBUG (
 | 
						|
    (DEBUG_NET,
 | 
						|
     "Tcb (%p) state %s --> %s\n",
 | 
						|
     Tcb,
 | 
						|
     mTcpStateName[Tcb->State],
 | 
						|
     mTcpStateName[State])
 | 
						|
    );
 | 
						|
 | 
						|
  Tcb->State = State;
 | 
						|
 | 
						|
  switch (State) {
 | 
						|
    case TCP_ESTABLISHED:
 | 
						|
 | 
						|
      SockConnEstablished (Tcb->Sk);
 | 
						|
 | 
						|
      if (Tcb->Parent != NULL) {
 | 
						|
        //
 | 
						|
        // A new connection is accepted by a listening socket. Install
 | 
						|
        // the device path.
 | 
						|
        //
 | 
						|
        TcpInstallDevicePath (Tcb->Sk);
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case TCP_CLOSED:
 | 
						|
 | 
						|
      SockConnClosed (Tcb->Sk);
 | 
						|
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compute the TCP segment's checksum.
 | 
						|
 | 
						|
  @param[in]  Nbuf       Pointer to the buffer that contains the TCP segment.
 | 
						|
  @param[in]  HeadSum    The checksum value of the fixed part of pseudo header.
 | 
						|
 | 
						|
  @return The checksum value.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
TcpChecksum (
 | 
						|
  IN NET_BUF  *Nbuf,
 | 
						|
  IN UINT16   HeadSum
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  Checksum;
 | 
						|
 | 
						|
  Checksum = NetbufChecksum (Nbuf);
 | 
						|
  Checksum = NetAddChecksum (Checksum, HeadSum);
 | 
						|
 | 
						|
  Checksum = NetAddChecksum (
 | 
						|
               Checksum,
 | 
						|
               HTONS ((UINT16)Nbuf->TotalSize)
 | 
						|
               );
 | 
						|
 | 
						|
  return (UINT16)(~Checksum);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Translate the information from the head of the received TCP
 | 
						|
  segment Nbuf contents and fill it into a TCP_SEG structure.
 | 
						|
 | 
						|
  @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param[in, out]  Nbuf          Pointer to the buffer contains the TCP segment.
 | 
						|
 | 
						|
  @return Pointer to the TCP_SEG that contains the translated TCP head information.
 | 
						|
 | 
						|
**/
 | 
						|
TCP_SEG *
 | 
						|
TcpFormatNetbuf (
 | 
						|
  IN     TCP_CB   *Tcb,
 | 
						|
  IN OUT NET_BUF  *Nbuf
 | 
						|
  )
 | 
						|
{
 | 
						|
  TCP_SEG   *Seg;
 | 
						|
  TCP_HEAD  *Head;
 | 
						|
 | 
						|
  Seg  = TCPSEG_NETBUF (Nbuf);
 | 
						|
  Head = (TCP_HEAD *)NetbufGetByte (Nbuf, 0, NULL);
 | 
						|
  ASSERT (Head != 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 the 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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize an active connection.
 | 
						|
 | 
						|
  @param[in, out]  Tcb          Pointer to the TCP_CB that wants to initiate a
 | 
						|
                                connection.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpOnAppConnect (
 | 
						|
  IN OUT TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  TcpInitTcbLocal (Tcb);
 | 
						|
  TcpSetState (Tcb, TCP_SYN_SENT);
 | 
						|
 | 
						|
  TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
 | 
						|
  TcpToSendData (Tcb, 1);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initiate the connection close procedure, called when
 | 
						|
  applications want to close the connection.
 | 
						|
 | 
						|
  @param[in, out]  Tcb          Pointer to the TCP_CB of this TCP instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpOnAppClose (
 | 
						|
  IN OUT TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (Tcb != NULL);
 | 
						|
 | 
						|
  if (!IsListEmpty (&Tcb->RcvQue) || (GET_RCV_DATASIZE (Tcb->Sk) != 0)) {
 | 
						|
    DEBUG (
 | 
						|
      (DEBUG_WARN,
 | 
						|
       "TcpOnAppClose: connection reset because data is lost for TCB %p\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;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpToSendData (Tcb, 1);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the application's newly delivered data can be sent out.
 | 
						|
 | 
						|
  @param[in, out]  Tcb          Pointer to the TCP_CB of this TCP instance.
 | 
						|
 | 
						|
  @retval 0                     The data has been sent out successfully.
 | 
						|
  @retval -1                    The Tcb is not in a state that data is permitted to
 | 
						|
                                be sent out.
 | 
						|
 | 
						|
**/
 | 
						|
INTN
 | 
						|
TcpOnAppSend (
 | 
						|
  IN OUT TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  switch (Tcb->State) {
 | 
						|
    case TCP_CLOSED:
 | 
						|
      return -1;
 | 
						|
 | 
						|
    case TCP_LISTEN:
 | 
						|
      return -1;
 | 
						|
 | 
						|
    case TCP_SYN_SENT:
 | 
						|
    case TCP_SYN_RCVD:
 | 
						|
      return 0;
 | 
						|
 | 
						|
    case TCP_ESTABLISHED:
 | 
						|
    case TCP_CLOSE_WAIT:
 | 
						|
      TcpToSendData (Tcb, 0);
 | 
						|
      return 0;
 | 
						|
 | 
						|
    case TCP_FIN_WAIT_1:
 | 
						|
    case TCP_FIN_WAIT_2:
 | 
						|
    case TCP_CLOSING:
 | 
						|
    case TCP_LAST_ACK:
 | 
						|
    case TCP_TIME_WAIT:
 | 
						|
      return -1;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Application has consumed some data. Check whether
 | 
						|
  to send a window update ack or a delayed ack.
 | 
						|
 | 
						|
  @param[in]  Tcb        Pointer to the TCP_CB of this TCP instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpOnAppConsume (
 | 
						|
  IN TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  TcpOld;
 | 
						|
 | 
						|
  switch (Tcb->State) {
 | 
						|
    case TCP_ESTABLISHED:
 | 
						|
      TcpOld = TcpRcvWinOld (Tcb);
 | 
						|
      if (TcpRcvWinNow (Tcb) > TcpOld) {
 | 
						|
        if (TcpOld < Tcb->RcvMss) {
 | 
						|
          DEBUG (
 | 
						|
            (DEBUG_NET,
 | 
						|
             "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",
 | 
						|
             Tcb)
 | 
						|
            );
 | 
						|
 | 
						|
          TcpSendAck (Tcb);
 | 
						|
        } else if (Tcb->DelayedAck == 0) {
 | 
						|
          DEBUG (
 | 
						|
            (DEBUG_NET,
 | 
						|
             "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",
 | 
						|
             Tcb)
 | 
						|
            );
 | 
						|
 | 
						|
          Tcb->DelayedAck = 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Abort the connection by sending a reset segment. Called
 | 
						|
  when the application wants to abort the connection.
 | 
						|
 | 
						|
  @param[in]  Tcb                   Pointer to the TCP_CB of the TCP instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpOnAppAbort (
 | 
						|
  IN TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEBUG (
 | 
						|
    (DEBUG_WARN,
 | 
						|
     "TcpOnAppAbort: connection reset issued by application for TCB %p\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;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpSetState (Tcb, TCP_CLOSED);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reset the connection related with Tcb.
 | 
						|
 | 
						|
  @param[in]  Tcb         Pointer to the TCP_CB of the connection to be reset.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpResetConnection (
 | 
						|
  IN TCP_CB  *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  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  = (UINT8)(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, Tcb->Sk->IpVersion);
 | 
						|
 | 
						|
  NetbufFree (Nbuf);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Install the device path protocol on the TCP instance.
 | 
						|
 | 
						|
  @param[in]  Sock          Pointer to the socket representing the TCP instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The device path protocol was installed.
 | 
						|
  @retval other                 Failed to install the device path protocol.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TcpInstallDevicePath (
 | 
						|
  IN SOCKET  *Sock
 | 
						|
  )
 | 
						|
{
 | 
						|
  TCP_PROTO_DATA            *TcpProto;
 | 
						|
  TCP_SERVICE_DATA          *TcpService;
 | 
						|
  TCP_CB                    *Tcb;
 | 
						|
  IPv4_DEVICE_PATH          Ip4DPathNode;
 | 
						|
  IPv6_DEVICE_PATH          Ip6DPathNode;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  TCP_PORTNO                LocalPort;
 | 
						|
  TCP_PORTNO                RemotePort;
 | 
						|
 | 
						|
  TcpProto   = (TCP_PROTO_DATA *)Sock->ProtoReserved;
 | 
						|
  TcpService = TcpProto->TcpService;
 | 
						|
  Tcb        = TcpProto->TcpPcb;
 | 
						|
 | 
						|
  LocalPort  = NTOHS (Tcb->LocalEnd.Port);
 | 
						|
  RemotePort = NTOHS (Tcb->RemoteEnd.Port);
 | 
						|
  if (Sock->IpVersion == IP_VERSION_4) {
 | 
						|
    NetLibCreateIPv4DPathNode (
 | 
						|
      &Ip4DPathNode,
 | 
						|
      TcpService->ControllerHandle,
 | 
						|
      Tcb->LocalEnd.Ip.Addr[0],
 | 
						|
      LocalPort,
 | 
						|
      Tcb->RemoteEnd.Ip.Addr[0],
 | 
						|
      RemotePort,
 | 
						|
      EFI_IP_PROTO_TCP,
 | 
						|
      Tcb->UseDefaultAddr
 | 
						|
      );
 | 
						|
 | 
						|
    IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);
 | 
						|
 | 
						|
    DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&Ip4DPathNode;
 | 
						|
  } else {
 | 
						|
    NetLibCreateIPv6DPathNode (
 | 
						|
      &Ip6DPathNode,
 | 
						|
      TcpService->ControllerHandle,
 | 
						|
      &Tcb->LocalEnd.Ip.v6,
 | 
						|
      LocalPort,
 | 
						|
      &Tcb->RemoteEnd.Ip.v6,
 | 
						|
      RemotePort,
 | 
						|
      EFI_IP_PROTO_TCP
 | 
						|
      );
 | 
						|
 | 
						|
    DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&Ip6DPathNode;
 | 
						|
  }
 | 
						|
 | 
						|
  Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);
 | 
						|
  if (Sock->DevicePath == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &Sock->SockHandle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  Sock->DevicePath
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (Sock->DevicePath);
 | 
						|
    Sock->DevicePath = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |