]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/TcpDxe/TcpMisc.c
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpMisc.c
diff --git a/NetworkPkg/TcpDxe/TcpMisc.c b/NetworkPkg/TcpDxe/TcpMisc.c
new file mode 100644 (file)
index 0000000..492ec35
--- /dev/null
@@ -0,0 +1,1281 @@
+/** @file\r
+  Misc support routines for TCP driver.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TcpMain.h"\r
+\r
+LIST_ENTRY      mTcpRunQue = {\r
+  &mTcpRunQue,\r
+  &mTcpRunQue\r
+};\r
+\r
+LIST_ENTRY      mTcpListenQue = {\r
+  &mTcpListenQue,\r
+  &mTcpListenQue\r
+};\r
+\r
+TCP_SEQNO       mTcpGlobalIss = TCP_BASE_ISS;\r
+\r
+CHAR16          *mTcpStateName[] = {\r
+  L"TCP_CLOSED",\r
+  L"TCP_LISTEN",\r
+  L"TCP_SYN_SENT",\r
+  L"TCP_SYN_RCVD",\r
+  L"TCP_ESTABLISHED",\r
+  L"TCP_FIN_WAIT_1",\r
+  L"TCP_FIN_WAIT_2",\r
+  L"TCP_CLOSING",\r
+  L"TCP_TIME_WAIT",\r
+  L"TCP_CLOSE_WAIT",\r
+  L"TCP_LAST_ACK"\r
+};\r
+\r
+\r
+/**\r
+  Initialize the Tcb local related members.\r
+\r
+  @param[in, out]  Tcb               Pointer to the TCP_CB of this TCP instance.\r
+\r
+**/\r
+VOID\r
+TcpInitTcbLocal (\r
+  IN OUT TCP_CB *Tcb\r
+  )\r
+{\r
+  //\r
+  // Compute the checksum of the fixed parts of pseudo header\r
+  //\r
+  if (Tcb->Sk->IpVersion == IP_VERSION_4) {\r
+    Tcb->HeadSum = NetPseudoHeadChecksum (\r
+                    Tcb->LocalEnd.Ip.Addr[0],\r
+                    Tcb->RemoteEnd.Ip.Addr[0],\r
+                    0x06,\r
+                    0\r
+                    );\r
+  } else {\r
+    Tcb->HeadSum = NetIp6PseudoHeadChecksum (\r
+                    &Tcb->LocalEnd.Ip.v6,\r
+                    &Tcb->RemoteEnd.Ip.v6,\r
+                    0x06,\r
+                    0\r
+                    );\r
+  }\r
+\r
+  Tcb->Iss    = TcpGetIss ();\r
+  Tcb->SndUna = Tcb->Iss;\r
+  Tcb->SndNxt = Tcb->Iss;\r
+\r
+  Tcb->SndWl2 = Tcb->Iss;\r
+  Tcb->SndWnd = 536;\r
+\r
+  Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+\r
+  //\r
+  // First window size is never scaled\r
+  //\r
+  Tcb->RcvWndScale  = 0;\r
+\r
+  Tcb->ProbeTimerOn = FALSE;\r
+}\r
+\r
+/**\r
+  Initialize the peer related members.\r
+\r
+  @param[in, out]  Tcb    Pointer to the TCP_CB of this TCP instance.\r
+  @param[in]       Seg    Pointer to the segment that contains the peer's intial info.\r
+  @param[in]       Opt    Pointer to the options announced by the peer.\r
+\r
+**/\r
+VOID\r
+TcpInitTcbPeer (\r
+  IN OUT TCP_CB     *Tcb,\r
+  IN     TCP_SEG    *Seg,\r
+  IN     TCP_OPTION *Opt\r
+  )\r
+{\r
+  UINT16  RcvMss;\r
+\r
+  ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL));\r
+  ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));\r
+\r
+  Tcb->SndWnd     = Seg->Wnd;\r
+  Tcb->SndWndMax  = Tcb->SndWnd;\r
+  Tcb->SndWl1     = Seg->Seq;\r
+\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+    Tcb->SndWl2 = Seg->Ack;\r
+  } else {\r
+    Tcb->SndWl2 = Tcb->Iss + 1;\r
+  }\r
+\r
+  if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {\r
+    Tcb->SndMss = (UINT16) MAX (64, Opt->Mss);\r
+\r
+    RcvMss      = TcpGetRcvMss (Tcb->Sk);\r
+    if (Tcb->SndMss > RcvMss) {\r
+      Tcb->SndMss = RcvMss;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // One end doesn't support MSS option, use default.\r
+    //\r
+    Tcb->RcvMss = 536;\r
+  }\r
+\r
+  Tcb->CWnd   = Tcb->SndMss;\r
+\r
+  Tcb->Irs    = Seg->Seq;\r
+  Tcb->RcvNxt = Tcb->Irs + 1;\r
+\r
+  Tcb->RcvWl2 = Tcb->RcvNxt;\r
+\r
+  if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) {\r
+\r
+    Tcb->SndWndScale  = Opt->WndScale;\r
+\r
+    Tcb->RcvWndScale  = TcpComputeScale (Tcb);\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS);\r
+\r
+  } else {\r
+    //\r
+    // One end doesn't support window scale option. use zero.\r
+    //\r
+    Tcb->RcvWndScale = 0;\r
+  }\r
+\r
+  if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {\r
+\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);\r
+\r
+    //\r
+    // Compute the effective SndMss per RFC1122\r
+    // section 4.2.2.6. If timestamp option is\r
+    // enabled, it will always occupy 12 bytes.\r
+    //\r
+    Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether one IP address equals the other.\r
+\r
+  @param[in]   Ip1     Pointer to IP address to be checked.\r
+  @param[in]   Ip2     Pointer to IP address to be checked.\r
+  @param[in]   Version IP_VERSION_4 indicates the IP address is an IPv4 address,\r
+                       IP_VERSION_6 indicates the IP address is an IPv6 address.\r
+\r
+  @retval      TRUE    Ip1 equals Ip2.\r
+  @retval      FALSE   Ip1 does not equal Ip2.\r
+\r
+**/\r
+BOOLEAN\r
+TcpIsIpEqual (\r
+  IN EFI_IP_ADDRESS  *Ip1,\r
+  IN EFI_IP_ADDRESS  *Ip2,\r
+  IN UINT8           Version\r
+  )\r
+{\r
+  ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
+\r
+  if (Version == IP_VERSION_4) {\r
+    return (BOOLEAN) (Ip1->Addr[0] == Ip2->Addr[0]);\r
+  } else {\r
+    return (BOOLEAN) EFI_IP6_EQUAL (&Ip1->v6, &Ip2->v6);\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether one IP address is filled with ZERO.\r
+\r
+  @param[in]   Ip      Pointer to the IP address to be checked.\r
+  @param[in]   Version IP_VERSION_4 indicates the IP address is an IPv4 address,\r
+                       IP_VERSION_6 indicates the IP address is an IPv6 address.\r
+\r
+  @retval      TRUE    Ip is all zero address.\r
+  @retval      FALSE   Ip is not all zero address.\r
+\r
+**/\r
+BOOLEAN\r
+TcpIsIpZero (\r
+  IN EFI_IP_ADDRESS *Ip,\r
+  IN UINT8          Version\r
+  )\r
+{\r
+  ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
+\r
+  if (Version == IP_VERSION_4) {\r
+    return (BOOLEAN) (Ip->Addr[0] == 0);\r
+  } else {\r
+    return (BOOLEAN) ((Ip->Addr[0] == 0) && (Ip->Addr[1] == 0) &&\r
+      (Ip->Addr[2] == 0) && (Ip->Addr[3] == 0));\r
+  }\r
+}\r
+\r
+/**\r
+  Locate a listen TCB that matchs the Local and Remote.\r
+\r
+  @param[in]  Local    Pointer to the local (IP, Port).\r
+  @param[in]  Remote   Pointer to the remote (IP, Port).\r
+  @param[in]  Version  IP_VERSION_4 indicates TCP is running on IP4 stack,\r
+                       IP_VERSION_6 indicates TCP is running on IP6 stack.\r
+\r
+  @return  Pointer to the TCP_CB with the least number of wildcards,\r
+           if NULL no match is found.\r
+\r
+**/\r
+TCP_CB *\r
+TcpLocateListenTcb (\r
+  IN TCP_PEER    *Local,\r
+  IN TCP_PEER    *Remote,\r
+  IN UINT8       Version\r
+  )\r
+{\r
+  LIST_ENTRY      *Entry;\r
+  TCP_CB          *Node;\r
+  TCP_CB          *Match;\r
+  INTN            Last;\r
+  INTN            Cur;\r
+\r
+  Last  = 4;\r
+  Match = NULL;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+    Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    if ((Version != Node->Sk->IpVersion) ||\r
+        (Local->Port != Node->LocalEnd.Port) ||\r
+        !TCP_PEER_MATCH (Remote, &Node->RemoteEnd, Version) ||\r
+        !TCP_PEER_MATCH (Local, &Node->LocalEnd, Version)\r
+          ) {\r
+\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Compute the number of wildcard\r
+    //\r
+    Cur = 0;\r
+    if (TcpIsIpZero (&Node->RemoteEnd.Ip, Version)) {\r
+      Cur++;\r
+    }\r
+\r
+    if (Node->RemoteEnd.Port == 0) {\r
+      Cur++;\r
+    }\r
+\r
+    if (TcpIsIpZero (&Node->LocalEnd.Ip, Version)) {\r
+      Cur++;\r
+    }\r
+\r
+    if (Cur < Last) {\r
+      if (Cur == 0) {\r
+        return Node;\r
+      }\r
+\r
+      Last  = Cur;\r
+      Match = Node;\r
+    }\r
+  }\r
+\r
+  return Match;\r
+}\r
+\r
+/**\r
+  Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.\r
+\r
+  @param[in]  Addr     Pointer to the IP address needs to match.\r
+  @param[in]  Port     The port number needs to match.\r
+  @param[in]  Version  IP_VERSION_4 indicates TCP is running on IP4 stack,\r
+                       IP_VERSION_6 indicates TCP is running on IP6 stack.\r
+\r
+\r
+  @retval     TRUE     The Tcb which matches the <Addr Port> pair exists.\r
+  @retval     FALSE    Otherwise\r
+\r
+**/\r
+BOOLEAN\r
+TcpFindTcbByPeer (\r
+  IN EFI_IP_ADDRESS  *Addr,\r
+  IN TCP_PORTNO      Port,\r
+  IN UINT8           Version\r
+  )\r
+{\r
+  TCP_PORTNO      LocalPort;\r
+  LIST_ENTRY      *Entry;\r
+  TCP_CB          *Tcb;\r
+\r
+  ASSERT ((Addr != NULL) && (Port != 0));\r
+\r
+  LocalPort = HTONS (Port);\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+    Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    if ((Version == Tcb->Sk->IpVersion) &&\r
+      TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&\r
+        (LocalPort == Tcb->LocalEnd.Port)\r
+        ) {\r
+\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+    Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    if ((Version == Tcb->Sk->IpVersion) &&\r
+      TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&\r
+        (LocalPort == Tcb->LocalEnd.Port)\r
+        ) {\r
+\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Locate the TCP_CB related to the socket pair.\r
+\r
+  @param[in]  LocalPort      The local port number.\r
+  @param[in]  LocalIp        The local IP address.\r
+  @param[in]  RemotePort     The remote port number.\r
+  @param[in]  RemoteIp       The remote IP address.\r
+  @param[in]  Version        IP_VERSION_4 indicates TCP is running on IP4 stack,\r
+                             IP_VERSION_6 indicates TCP is running on IP6 stack.\r
+  @param[in]  Syn            If TRUE, the listen sockets are searched.\r
+\r
+  @return Pointer to the related TCP_CB. If NULL, no match is found.\r
+\r
+**/\r
+TCP_CB *\r
+TcpLocateTcb (\r
+  IN TCP_PORTNO      LocalPort,\r
+  IN EFI_IP_ADDRESS  *LocalIp,\r
+  IN TCP_PORTNO      RemotePort,\r
+  IN EFI_IP_ADDRESS  *RemoteIp,\r
+  IN UINT8           Version,\r
+  IN BOOLEAN         Syn\r
+  )\r
+{\r
+  TCP_PEER        Local;\r
+  TCP_PEER        Remote;\r
+  LIST_ENTRY      *Entry;\r
+  TCP_CB          *Tcb;\r
+\r
+  Local.Port  = LocalPort;\r
+  Remote.Port = RemotePort;\r
+\r
+  CopyMem (&Local.Ip, LocalIp, sizeof (EFI_IP_ADDRESS));\r
+  CopyMem (&Remote.Ip, RemoteIp, sizeof (EFI_IP_ADDRESS));\r
+\r
+  //\r
+  // First check for exact match.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+    Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    if ((Version == Tcb->Sk->IpVersion) &&\r
+        TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd, Version) &&\r
+        TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd, Version)\r
+          ) {\r
+\r
+      RemoveEntryList (&Tcb->List);\r
+      InsertHeadList (&mTcpRunQue, &Tcb->List);\r
+\r
+      return Tcb;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Only check the listen queue when the SYN flag is on.\r
+  //\r
+  if (Syn) {\r
+    return TcpLocateListenTcb (&Local, &Remote, Version);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Insert a Tcb into the proper queue.\r
+\r
+  @param[in]  Tcb               Pointer to the TCP_CB to be inserted.\r
+\r
+  @retval 0                     The Tcb was inserted successfully.\r
+  @retval -1                    Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpInsertTcb (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  LIST_ENTRY       *Entry;\r
+  LIST_ENTRY       *Head;\r
+  TCP_CB           *Node;\r
+  TCP_PROTO_DATA  *TcpProto;\r
+\r
+  ASSERT (\r
+    (Tcb != NULL) &&\r
+    (\r
+    (Tcb->State == TCP_LISTEN) ||\r
+    (Tcb->State == TCP_SYN_SENT) ||\r
+    (Tcb->State == TCP_SYN_RCVD) ||\r
+    (Tcb->State == TCP_CLOSED)\r
+    )\r
+    );\r
+\r
+  if (Tcb->LocalEnd.Port == 0) {\r
+    return -1;\r
+  }\r
+\r
+  Head = &mTcpRunQue;\r
+\r
+  if (Tcb->State == TCP_LISTEN) {\r
+    Head = &mTcpListenQue;\r
+  }\r
+\r
+  //\r
+  // Check that the Tcb isn't already on the list.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, Head) {\r
+    Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd, Tcb->Sk->IpVersion) &&\r
+        TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd, Tcb->Sk->IpVersion)\r
+          ) {\r
+\r
+      return -1;\r
+    }\r
+  }\r
+\r
+  InsertHeadList (Head, &Tcb->List);\r
+\r
+  TcpProto = (TCP_PROTO_DATA *) Tcb->Sk->ProtoReserved;\r
+  TcpSetVariableData (TcpProto->TcpService);\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Clone a TCP_CB from Tcb.\r
+\r
+  @param[in]  Tcb                   Pointer to the TCP_CB to be cloned.\r
+\r
+  @return Pointer to the new cloned TCP_CB; if NULL, error condition occurred.\r
+\r
+**/\r
+TCP_CB *\r
+TcpCloneTcb (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  TCP_CB             *Clone;\r
+\r
+  Clone = AllocateZeroPool (sizeof (TCP_CB));\r
+\r
+  if (Clone == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  CopyMem (Clone, Tcb, sizeof (TCP_CB));\r
+\r
+  //\r
+  // Increase the reference count of the shared IpInfo.\r
+  //\r
+  NET_GET_REF (Tcb->IpInfo);\r
+\r
+  InitializeListHead (&Clone->List);\r
+  InitializeListHead (&Clone->SndQue);\r
+  InitializeListHead (&Clone->RcvQue);\r
+\r
+  Clone->Sk = SockClone (Tcb->Sk);\r
+  if (Clone->Sk == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "TcpCloneTcb: failed to clone a sock\n"));\r
+    FreePool (Clone);\r
+    return NULL;\r
+  }\r
+\r
+  ((TCP_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
+\r
+  return Clone;\r
+}\r
+\r
+/**\r
+  Compute an ISS to be used by a new connection.\r
+\r
+  @return The resulting ISS.\r
+\r
+**/\r
+TCP_SEQNO\r
+TcpGetIss (\r
+  VOID\r
+  )\r
+{\r
+  mTcpGlobalIss += TCP_ISS_INCREMENT_1;\r
+  return mTcpGlobalIss;\r
+}\r
+\r
+/**\r
+  Get the local mss.\r
+\r
+  @param[in]  Sock        Pointer to the socket to get mss.\r
+\r
+  @return The mss size.\r
+\r
+**/\r
+UINT16\r
+TcpGetRcvMss (\r
+  IN SOCKET  *Sock\r
+  )\r
+{\r
+  EFI_IP4_MODE_DATA      Ip4Mode;\r
+  EFI_IP6_MODE_DATA      Ip6Mode;\r
+  EFI_IP4_PROTOCOL       *Ip4;\r
+  EFI_IP6_PROTOCOL       *Ip6;\r
+  TCP_PROTO_DATA         *TcpProto;\r
+\r
+  ASSERT (Sock != NULL);\r
+\r
+  ZeroMem (&Ip4Mode, sizeof (EFI_IP4_MODE_DATA));\r
+  ZeroMem (&Ip6Mode, sizeof (EFI_IP6_MODE_DATA));\r
+\r
+  TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+  if (Sock->IpVersion == IP_VERSION_4) {\r
+    Ip4 = TcpProto->TcpService->IpIo->Ip.Ip4;\r
+    ASSERT (Ip4 != NULL);\r
+    Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL);\r
+\r
+    return (UINT16) (Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
+  } else {\r
+    Ip6 = TcpProto->TcpService->IpIo->Ip.Ip6;\r
+    ASSERT (Ip6 != NULL);\r
+    Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL);\r
+\r
+    return (UINT16) (Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
+  }\r
+}\r
+\r
+/**\r
+  Set the Tcb's state.\r
+\r
+  @param[in]  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+  @param[in]  State                 The state to be set.\r
+\r
+**/\r
+VOID\r
+TcpSetState (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT8  State\r
+  )\r
+{\r
+  ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
+  ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
+\r
+  DEBUG (\r
+    (EFI_D_INFO,\r
+    "Tcb (%p) state %s --> %s\n",\r
+    Tcb,\r
+    mTcpStateName[Tcb->State],\r
+    mTcpStateName[State])\r
+    );\r
+\r
+  Tcb->State = State;\r
+\r
+  switch (State) {\r
+  case TCP_ESTABLISHED:\r
+\r
+    SockConnEstablished (Tcb->Sk);\r
+\r
+    if (Tcb->Parent != NULL) {\r
+      //\r
+      // A new connection is accepted by a listening socket. Install\r
+      // the device path.\r
+      //\r
+      TcpInstallDevicePath (Tcb->Sk);\r
+    }\r
+\r
+    break;\r
+\r
+  case TCP_CLOSED:\r
+\r
+    SockConnClosed (Tcb->Sk);\r
+\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Compute the TCP segment's checksum.\r
+\r
+  @param[in]  Nbuf       Pointer to the buffer that contains the TCP segment.\r
+  @param[in]  HeadSum    The checksum value of the fixed part of pseudo header.\r
+\r
+  @return The checksum value.\r
+\r
+**/\r
+UINT16\r
+TcpChecksum (\r
+  IN NET_BUF *Nbuf,\r
+  IN UINT16  HeadSum\r
+  )\r
+{\r
+  UINT16  Checksum;\r
+\r
+  Checksum  = NetbufChecksum (Nbuf);\r
+  Checksum  = NetAddChecksum (Checksum, HeadSum);\r
+\r
+  Checksum = NetAddChecksum (\r
+              Checksum,\r
+              HTONS ((UINT16) Nbuf->TotalSize)\r
+              );\r
+\r
+  return (UINT16) (~Checksum);\r
+}\r
+\r
+/**\r
+  Translate the information from the head of the received TCP\r
+  segment Nbuf contents and fill it into a TCP_SEG structure.\r
+\r
+  @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.\r
+  @param[in, out]  Nbuf          Pointer to the buffer contains the TCP segment.\r
+\r
+  @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
+\r
+**/\r
+TCP_SEG *\r
+TcpFormatNetbuf (\r
+  IN     TCP_CB  *Tcb,\r
+  IN OUT NET_BUF *Nbuf\r
+  )\r
+{\r
+  TCP_SEG   *Seg;\r
+  TCP_HEAD  *Head;\r
+\r
+  Seg       = TCPSEG_NETBUF (Nbuf);\r
+  Head      = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
+  ASSERT (Head != NULL);\r
+\r
+  Nbuf->Tcp = Head;\r
+\r
+  Seg->Seq  = NTOHL (Head->Seq);\r
+  Seg->Ack  = NTOHL (Head->Ack);\r
+  Seg->End  = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
+\r
+  Seg->Urg  = NTOHS (Head->Urg);\r
+  Seg->Wnd  = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
+  Seg->Flag = Head->Flag;\r
+\r
+  //\r
+  // SYN and FIN flag occupy one sequence space each.\r
+  //\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+    //\r
+    // RFC requires that the initial window not be scaled.\r
+    //\r
+    Seg->Wnd = NTOHS (Head->Wnd);\r
+    Seg->End++;\r
+  }\r
+\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+    Seg->End++;\r
+  }\r
+\r
+  return Seg;\r
+}\r
+\r
+/**\r
+  Initialize an active connection.\r
+\r
+  @param[in, out]  Tcb          Pointer to the TCP_CB that wants to initiate a\r
+                                connection.\r
+\r
+**/\r
+VOID\r
+TcpOnAppConnect (\r
+  IN OUT TCP_CB  *Tcb\r
+  )\r
+{\r
+  TcpInitTcbLocal (Tcb);\r
+  TcpSetState (Tcb, TCP_SYN_SENT);\r
+\r
+  TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
+  TcpToSendData (Tcb, 1);\r
+}\r
+\r
+/**\r
+  Initiate the connection close procedure, called when\r
+  applications want to close the connection.\r
+\r
+  @param[in, out]  Tcb          Pointer to the TCP_CB of this TCP instance.\r
+\r
+**/\r
+VOID\r
+TcpOnAppClose (\r
+  IN OUT TCP_CB *Tcb\r
+  )\r
+{\r
+  ASSERT (Tcb != NULL);\r
+\r
+  if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {\r
+\r
+    DEBUG (\r
+      (EFI_D_WARN,\r
+      "TcpOnAppClose: connection reset because data is lost for TCB %p\n",\r
+      Tcb)\r
+      );\r
+\r
+    TcpResetConnection (Tcb);\r
+    TcpClose (Tcb);\r
+    return;\r
+  }\r
+\r
+  switch (Tcb->State) {\r
+  case TCP_CLOSED:\r
+  case TCP_LISTEN:\r
+  case TCP_SYN_SENT:\r
+    TcpSetState (Tcb, TCP_CLOSED);\r
+    break;\r
+\r
+  case TCP_SYN_RCVD:\r
+  case TCP_ESTABLISHED:\r
+    TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
+    break;\r
+\r
+  case TCP_CLOSE_WAIT:\r
+    TcpSetState (Tcb, TCP_LAST_ACK);\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+\r
+  TcpToSendData (Tcb, 1);\r
+}\r
+\r
+/**\r
+  Check whether the application's newly delivered data can be sent out.\r
+\r
+  @param[in, out]  Tcb          Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @retval 0                     The data has been sent out successfully.\r
+  @retval -1                    The Tcb is not in a state that data is permitted to\r
+                                be sent out.\r
+\r
+**/\r
+INTN\r
+TcpOnAppSend (\r
+  IN OUT TCP_CB *Tcb\r
+  )\r
+{\r
+\r
+  switch (Tcb->State) {\r
+  case TCP_CLOSED:\r
+    return -1;\r
+\r
+  case TCP_LISTEN:\r
+    return -1;\r
+\r
+  case TCP_SYN_SENT:\r
+  case TCP_SYN_RCVD:\r
+    return 0;\r
+\r
+  case TCP_ESTABLISHED:\r
+  case TCP_CLOSE_WAIT:\r
+    TcpToSendData (Tcb, 0);\r
+    return 0;\r
+\r
+  case TCP_FIN_WAIT_1:\r
+  case TCP_FIN_WAIT_2:\r
+  case TCP_CLOSING:\r
+  case TCP_LAST_ACK:\r
+  case TCP_TIME_WAIT:\r
+    return -1;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Application has consumed some data. Check whether\r
+  to send a window update ack or a delayed ack.\r
+\r
+  @param[in]  Tcb        Pointer to the TCP_CB of this TCP instance.\r
+\r
+**/\r
+VOID\r
+TcpOnAppConsume (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  UINT32 TcpOld;\r
+\r
+  switch (Tcb->State) {\r
+  case TCP_ESTABLISHED:\r
+    TcpOld = TcpRcvWinOld (Tcb);\r
+    if (TcpRcvWinNow (Tcb) > TcpOld) {\r
+\r
+      if (TcpOld < Tcb->RcvMss) {\r
+\r
+        DEBUG (\r
+          (EFI_D_INFO,\r
+          "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",\r
+          Tcb)\r
+          );\r
+\r
+        TcpSendAck (Tcb);\r
+      } else if (Tcb->DelayedAck == 0) {\r
+\r
+        DEBUG (\r
+          (EFI_D_INFO,\r
+          "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",\r
+          Tcb)\r
+          );\r
+\r
+        Tcb->DelayedAck = 1;\r
+      }\r
+    }\r
+\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Abort the connection by sending a reset segment. Called\r
+  when the application wants to abort the connection.\r
+\r
+  @param[in]  Tcb                   Pointer to the TCP_CB of the TCP instance.\r
+\r
+**/\r
+VOID\r
+TcpOnAppAbort (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  DEBUG (\r
+    (EFI_D_WARN,\r
+    "TcpOnAppAbort: connection reset issued by application for TCB %p\n",\r
+    Tcb)\r
+    );\r
+\r
+  switch (Tcb->State) {\r
+  case TCP_SYN_RCVD:\r
+  case TCP_ESTABLISHED:\r
+  case TCP_FIN_WAIT_1:\r
+  case TCP_FIN_WAIT_2:\r
+  case TCP_CLOSE_WAIT:\r
+    TcpResetConnection (Tcb);\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+\r
+  TcpSetState (Tcb, TCP_CLOSED);\r
+}\r
+\r
+/**\r
+  Reset the connection related with Tcb.\r
+\r
+  @param[in]  Tcb         Pointer to the TCP_CB of the connection to be reset.\r
+\r
+**/\r
+VOID\r
+TcpResetConnection (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NET_BUF   *Nbuf;\r
+  TCP_HEAD  *Nhead;\r
+\r
+  Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+  if (Nbuf == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
+                        Nbuf,\r
+                        sizeof (TCP_HEAD),\r
+                        NET_BUF_TAIL\r
+                        );\r
+\r
+  ASSERT (Nhead != NULL);\r
+\r
+  Nbuf->Tcp       = Nhead;\r
+\r
+  Nhead->Flag     = TCP_FLG_RST;\r
+  Nhead->Seq      = HTONL (Tcb->SndNxt);\r
+  Nhead->Ack      = HTONL (Tcb->RcvNxt);\r
+  Nhead->SrcPort  = Tcb->LocalEnd.Port;\r
+  Nhead->DstPort  = Tcb->RemoteEnd.Port;\r
+  Nhead->HeadLen  = (UINT8) (sizeof (TCP_HEAD) >> 2);\r
+  Nhead->Res      = 0;\r
+  Nhead->Wnd      = HTONS (0xFFFF);\r
+  Nhead->Checksum = 0;\r
+  Nhead->Urg      = 0;\r
+  Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
+\r
+  TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);\r
+\r
+  NetbufFree (Nbuf);\r
+}\r
+\r
+/**\r
+  Set the Tcp variable data.\r
+\r
+  @param[in]  TcpService        Tcp service data.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set the variable.\r
+  @retval other                 Set variable failed.\r
+\r
+**/\r
+EFI_STATUS\r
+TcpSetVariableData (\r
+  IN TCP_SERVICE_DATA  *TcpService\r
+  )\r
+{\r
+  EFI_GUID                *ServiceBindingGuid;\r
+  UINT32                  NumConfiguredInstance;\r
+  LIST_ENTRY              *Entry;\r
+  TCP_CB                  *TcpPcb;\r
+  TCP_PROTO_DATA          *TcpProto;\r
+  UINTN                   VariableDataSize;\r
+  EFI_TCP4_VARIABLE_DATA  *Tcp4VariableData;\r
+  EFI_TCP4_SERVICE_POINT  *Tcp4ServicePoint;\r
+  EFI_TCP6_VARIABLE_DATA  *Tcp6VariableData;\r
+  EFI_TCP6_SERVICE_POINT  *Tcp6ServicePoint;\r
+  VOID                    *VariableData;\r
+  CHAR16                  *NewMacString;\r
+  EFI_STATUS              Status;\r
+\r
+  if (TcpService->IpVersion == IP_VERSION_4) {\r
+    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+  } else {\r
+    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+  }\r
+\r
+  NumConfiguredInstance = 0;\r
+  Tcp4VariableData      = NULL;\r
+  Tcp6VariableData      = NULL;\r
+\r
+  //\r
+  // Go through the running queue to count the instances.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+    TcpPcb    = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    TcpProto  = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == TcpService) {\r
+      //\r
+      // This tcp instance belongs to the TcpService.\r
+      //\r
+      NumConfiguredInstance++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Go through the listening queue to count the instances.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+    TcpPcb    = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    TcpProto  = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == TcpService) {\r
+      //\r
+      // This tcp instance belongs to the TcpService.\r
+      //\r
+      NumConfiguredInstance++;\r
+    }\r
+  }\r
+\r
+  Tcp4ServicePoint = NULL;\r
+  Tcp6ServicePoint = NULL;\r
+\r
+  //\r
+  // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
+  // we should add extra buffers for the service points only if the number of configured\r
+  // children is more than one.\r
+  //\r
+  if (TcpService->IpVersion == IP_VERSION_4) {\r
+    VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
+\r
+    if (NumConfiguredInstance > 1) {\r
+      VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
+    }\r
+\r
+    Tcp4VariableData = AllocateZeroPool (VariableDataSize);\r
+    if (Tcp4VariableData == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Tcp4VariableData->DriverHandle  = TcpService->DriverBindingHandle;\r
+    Tcp4VariableData->ServiceCount  = NumConfiguredInstance;\r
+\r
+    Tcp4ServicePoint                = &Tcp4VariableData->Services[0];\r
+    VariableData                    = Tcp4VariableData;\r
+  } else {\r
+    VariableDataSize = sizeof (EFI_TCP6_VARIABLE_DATA);\r
+\r
+    if (NumConfiguredInstance > 1) {\r
+      VariableDataSize += sizeof (EFI_TCP6_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
+    }\r
+\r
+    Tcp6VariableData = AllocateZeroPool (VariableDataSize);\r
+    if (Tcp6VariableData == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Tcp6VariableData->DriverHandle  = TcpService->DriverBindingHandle;\r
+    Tcp6VariableData->ServiceCount  = NumConfiguredInstance;\r
+\r
+    Tcp6ServicePoint                = &Tcp6VariableData->Services[0];\r
+    VariableData                    = Tcp6VariableData;\r
+  }\r
+\r
+  //\r
+  // Go through the running queue to fill the service points.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+    TcpPcb    = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    TcpProto  = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == TcpService) {\r
+      //\r
+      // This tcp instance belongs to the TcpService.\r
+      //\r
+      if (TcpService->IpVersion == IP_VERSION_4) {\r
+        Tcp4ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;\r
+        CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
+        Tcp4ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);\r
+        CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
+        Tcp4ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+        Tcp4ServicePoint++;\r
+      } else {\r
+        Tcp6ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;\r
+        IP6_COPY_ADDRESS (&Tcp6ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip);\r
+        Tcp6ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);\r
+        IP6_COPY_ADDRESS (&Tcp6ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip);\r
+        Tcp6ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+        Tcp6ServicePoint++;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Go through the listening queue to fill the service points.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+    TcpPcb    = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    TcpProto  = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == TcpService) {\r
+      //\r
+      // This tcp instance belongs to the TcpService.\r
+      //\r
+      if (TcpService->IpVersion == IP_VERSION_4) {\r
+        Tcp4ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;\r
+        CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
+        Tcp4ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);\r
+        CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
+        Tcp4ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+        Tcp4ServicePoint++;\r
+      } else {\r
+        Tcp6ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;\r
+        IP6_COPY_ADDRESS (&Tcp6ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip);\r
+        Tcp6ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);\r
+        IP6_COPY_ADDRESS (&Tcp6ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip);\r
+        Tcp6ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+        Tcp6ServicePoint++;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get the mac string.\r
+  //\r
+  Status = NetLibGetMacString (\r
+             TcpService->ControllerHandle,\r
+             TcpService->DriverBindingHandle,\r
+             &NewMacString\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (TcpService->MacString != NULL) {\r
+    //\r
+    // The variable is set already. We're going to update it.\r
+    //\r
+    if (StrCmp (TcpService->MacString, NewMacString) != 0) {\r
+      //\r
+      // The mac address is changed. Delete the previous variable first.\r
+      //\r
+      gRT->SetVariable (\r
+             TcpService->MacString,\r
+             ServiceBindingGuid,\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             NULL\r
+             );\r
+    }\r
+\r
+    FreePool (TcpService->MacString);\r
+  }\r
+\r
+  TcpService->MacString = NewMacString;\r
+\r
+  Status = gRT->SetVariable (\r
+                  TcpService->MacString,\r
+                  ServiceBindingGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  VariableDataSize,\r
+                  VariableData\r
+                  );\r
+\r
+ON_ERROR:\r
+\r
+  FreePool (VariableData);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Clear the variable and free the resource.\r
+\r
+  @param[in]  TcpService            Tcp service data.\r
+\r
+**/\r
+VOID\r
+TcpClearVariableData (\r
+  IN TCP_SERVICE_DATA  *TcpService\r
+  )\r
+{\r
+  EFI_GUID  *ServiceBindingGuid;\r
+\r
+  ASSERT (TcpService->MacString != NULL);\r
+\r
+  if (TcpService->IpVersion == IP_VERSION_4) {\r
+    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+  } else {\r
+    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+  }\r
+\r
+  gRT->SetVariable (\r
+         TcpService->MacString,\r
+         ServiceBindingGuid,\r
+         EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+         0,\r
+         NULL\r
+         );\r
+\r
+  FreePool (TcpService->MacString);\r
+  TcpService->MacString = NULL;\r
+}\r
+\r
+/**\r
+  Install the device path protocol on the TCP instance.\r
+\r
+  @param[in]  Sock          Pointer to the socket representing the TCP instance.\r
+\r
+  @retval EFI_SUCCESS           The device path protocol was installed.\r
+  @retval other                 Failed to install the device path protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+TcpInstallDevicePath (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  TCP_PROTO_DATA           *TcpProto;\r
+  TCP_SERVICE_DATA         *TcpService;\r
+  TCP_CB                   *Tcb;\r
+  IPv4_DEVICE_PATH         Ip4DPathNode;\r
+  IPv6_DEVICE_PATH         Ip6DPathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+  EFI_STATUS               Status;\r
+  TCP_PORTNO               LocalPort;\r
+  TCP_PORTNO               RemotePort;\r
+\r
+  TcpProto   = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
+  TcpService = TcpProto->TcpService;\r
+  Tcb        = TcpProto->TcpPcb;\r
+\r
+  LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
+  RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
+  if (Sock->IpVersion == IP_VERSION_4) {\r
+    NetLibCreateIPv4DPathNode (\r
+      &Ip4DPathNode,\r
+      TcpService->ControllerHandle,\r
+      Tcb->LocalEnd.Ip.Addr[0],\r
+      LocalPort,\r
+      Tcb->RemoteEnd.Ip.Addr[0],\r
+      RemotePort,\r
+      EFI_IP_PROTO_TCP,\r
+      Tcb->UseDefaultAddr\r
+      );\r
+\r
+    DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode;\r
+  } else {\r
+    NetLibCreateIPv6DPathNode (\r
+      &Ip6DPathNode,\r
+      TcpService->ControllerHandle,\r
+      &Tcb->LocalEnd.Ip.v6,\r
+      LocalPort,\r
+      &Tcb->RemoteEnd.Ip.v6,\r
+      RemotePort,\r
+      EFI_IP_PROTO_TCP\r
+      );\r
+\r
+    DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode;\r
+  }\r
+\r
+  Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);\r
+  if (Sock->DevicePath == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Sock->SockHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  Sock->DevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Sock->DevicePath);\r
+    Sock->DevicePath = NULL;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r