]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Import SnpDxe, Tcp4Dxe, Udp4Dxe and MnpDxe.
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 24 Jul 2007 08:06:37 +0000 (08:06 +0000)
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 24 Jul 2007 08:06:37 +0000 (08:06 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3416 6f19259b-4bc3-4df7-8a09-765794883524

66 files changed:
MdeModulePkg/Include/Library/IpIoLib.h
MdeModulePkg/Include/Library/NetLib.h
MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
MdeModulePkg/Library/DxeNetLib/NetDebug.c [new file with mode: 0644]
MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/Network/MnpDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpDebug.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/callback.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/get_status.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/initialize.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/nvdata.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/receive.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/reset.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/shutdown.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/snp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/snp.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/start.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/station_address.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/statistics.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/stop.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/transmit.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/SockInterface.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Socket.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dispatcher.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Func.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Io.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Proto.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Timer.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c [new file with mode: 0644]

index 15cfbf8f43724d96111552a7ca4ce8a43b13e173..894e07bed4f08cabff6480931b45a24d49935ee7 100644 (file)
@@ -171,7 +171,7 @@ typedef struct _IP_IO_SEND_ENTRY {
   EFI_IP4_COMPLETION_TOKEN  *SndToken;
 } IP_IO_SEND_ENTRY;
 
-typedef struct _EFI_IP4_OVERRIDE_DATA IP_IO_OVERRIDE;
+typedef EFI_IP4_OVERRIDE_DATA IP_IO_OVERRIDE;
 
 typedef struct _IP_IO_IP_INFO {
   IP4_ADDR                  Addr;
index 215a2fb094feff8806db67bf4a0fc6850ce8aa28..6bc343185563001f24c09b4520e1cfb9bd56c541 100644 (file)
@@ -809,4 +809,79 @@ NetPseudoHeadChecksum (
   IN UINT8                  Proto,
   IN UINT16                 Len
   );
+
+//\r
+// The debug level definition. This value is also used as the\r
+// syslog's servity level. Don't change it.\r
+//\r
+enum {\r
+  NETDEBUG_LEVEL_TRACE   = 5,\r
+  NETDEBUG_LEVEL_WARNING = 4,\r
+  NETDEBUG_LEVEL_ERROR   = 3,\r
+};\r
+\r
+#ifdef EFI_NETWORK_STACK_DEBUG\r
+\r
+//\r
+// The debug output expects the ASCII format string, Use %a to print ASCII\r
+// string, and %s to print UNICODE string. PrintArg must be enclosed in ().\r
+// For example: NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name));\r
+//\r
+#define NET_DEBUG_TRACE(Module, PrintArg) \\r
+  NetDebugOutput ( \\r
+    NETDEBUG_LEVEL_TRACE, \\r
+    Module, \\r
+    __FILE__, \\r
+    __LINE__, \\r
+    NetDebugASPrint PrintArg \\r
+    )\r
+\r
+#define NET_DEBUG_WARNING(Module, PrintArg) \\r
+  NetDebugOutput ( \\r
+    NETDEBUG_LEVEL_WARNING, \\r
+    Module, \\r
+    __FILE__, \\r
+    __LINE__, \\r
+    NetDebugASPrint PrintArg \\r
+    )\r
+\r
+#define NET_DEBUG_ERROR(Module, PrintArg) \\r
+  NetDebugOutput ( \\r
+    NETDEBUG_LEVEL_ERROR, \\r
+    Module, \\r
+    __FILE__, \\r
+    __LINE__, \\r
+    NetDebugASPrint PrintArg \\r
+    )\r
+\r
+#else\r
+#define NET_DEBUG_TRACE(Module, PrintString)\r
+#define NET_DEBUG_WARNING(Module, PrintString)\r
+#define NET_DEBUG_ERROR(Module, PrintString)\r
+#endif\r
+\r
+UINT8 *\r
+NetDebugASPrint (\r
+  UINT8                     *Format,\r
+  ...\r
+  );\r
+\r
+EFI_STATUS\r
+NetDebugOutput (\r
+  UINT32                    Level,\r
+  UINT8                     *Module,\r
+  UINT8                     *File,\r
+  UINT32                    Line,\r
+  UINT8                     *Message\r
+  );\r
+\r
+//\r
+// Network debug message is sent out as syslog.\r
+//\r
+enum {\r
+  NET_SYSLOG_FACILITY       = 16,             // Syslog local facility local use\r
+  NET_SYSLOG_PACKET_LEN     = 512,\r
+  NET_DEBUG_MSG_LEN         = 470,            // 512 - (ether+ip+udp head length)\r
+  NET_SYSLOG_TX_TIMEOUT     = 500 *1000 *10,  // 500ms\r
+};
 #endif
index 9430d8abba66623eda7b87351d2d3f1212c62961..f7aa52a0bfb101fce0f1fef40bf8f05b564d3e5e 100644 (file)
 \r
 \r
 [LibraryClasses]\r
-  MemoryAllocationLib\r
-  UefiLib\r
+  IpIoLib\r
   BaseLib\r
-  UefiBootServicesTableLib\r
-  UefiRuntimeServicesTableLib\r
-  BaseMemoryLib\r
   DebugLib\r
-  PrintLib\r
-\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
 \r
 [Protocols]\r
   gEfiIp4ProtocolGuid                           # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverDiagnosticsProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiUdp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiLoadedImageProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED\r
   gEfiIp4ServiceBindingProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverConfigurationProtocolGuid           # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiSimpleNetworkProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverBindingProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiComponentNameProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-\r
index be9ff1b379eda68281d6cf7caf06fb882b90e8ff..3ae0a04ee4fffb0756ae7f156ac372b0c1e7d0c5 100644 (file)
@@ -35,6 +35,7 @@
 [Sources.common]\r
   DxeNetLib.c\r
   NetBuffer.c\r
+  NetDebug.c\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
 \r
 \r
 [LibraryClasses]\r
-  MemoryAllocationLib\r
-  UefiLib\r
-  BaseLib\r
-  UefiBootServicesTableLib\r
-  UefiRuntimeServicesTableLib\r
-  BaseMemoryLib\r
-  DebugLib\r
-  PrintLib\r
-\r
+   NetLib
+   BaseLib
+   DebugLib
+   BaseMemoryLib
+   UefiBootServicesTableLib
+   UefiRuntimeServicesTableLib
+   UefiLib
+   MemoryAllocationLib
 \r
 [Protocols]\r
-  gEfiIp4ProtocolGuid                           # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverDiagnosticsProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiUdp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiLoadedImageProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiIp4ServiceBindingProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverConfigurationProtocolGuid           # PROTOCOL ALWAYS_CONSUMED\r
   gEfiSimpleNetworkProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverBindingProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiComponentNameProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
 \r
diff --git a/MdeModulePkg/Library/DxeNetLib/NetDebug.c b/MdeModulePkg/Library/DxeNetLib/NetDebug.c
new file mode 100644 (file)
index 0000000..afcc1b3
--- /dev/null
@@ -0,0 +1,536 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  NetDebug.c\r
+\r
+Abstract:\r
+\r
+  Network debug facility. The debug information is wrapped in\r
+  SYSLOG packets, then sent over SNP. This debug facility can't\r
+  be used by SNP. Apply caution when used in MNP and non-network\r
+  module because SNP is most likely not "thread safe". We assume\r
+  that the SNP supports the EHTERNET.\r
+\r
+\r
+**/\r
+\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SimpleNetwork.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/NetLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+\r
+//\r
+// Any error level digitally larger than mNetDebugLevelMax\r
+// will be silently discarded.\r
+//\r
+UINTN  mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;\r
+UINT32 mSyslogPacketSeq  = 0xDEADBEEF;\r
+\r
+//\r
+// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp\r
+// here to direct the syslog packets to the syslog deamon. The\r
+// default is broadcast to both the ethernet and IP.\r
+//\r
+UINT8  mSyslogDstMac [NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
+UINT32 mSyslogDstIp                       = 0xffffffff;\r
+UINT32 mSyslogSrcIp                       = 0;\r
+\r
+UINT8 *\r
+MonthName[] = {\r
+  "Jan",\r
+  "Feb",\r
+  "Mar",\r
+  "Apr",\r
+  "May",\r
+  "Jun",\r
+  "Jul",\r
+  "Aug",\r
+  "Sep",\r
+  "Oct",\r
+  "Nov",\r
+  "Dec"\r
+};\r
+\r
+\r
+/**\r
+  Locate the handles that support SNP, then open one of them\r
+  to send the syslog packets. The caller isn't required to close\r
+  the SNP after use because the SNP is opened by HandleProtocol.\r
+\r
+  None\r
+\r
+  @return The point to SNP if one is properly openned. Otherwise NULL\r
+\r
+**/\r
+EFI_SIMPLE_NETWORK_PROTOCOL *\r
+SyslogLocateSnp (\r
+  VOID\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_STATUS                  Status;\r
+  EFI_HANDLE                  *Handles;\r
+  UINTN                       HandleCount;\r
+  UINTN                       Index;\r
+\r
+  //\r
+  // Locate the handles which has SNP installed.\r
+  //\r
+  Handles = NULL;\r
+  Status  = gBS->LocateHandleBuffer (\r
+                   ByProtocol,\r
+                   &gEfiSimpleNetworkProtocolGuid,\r
+                   NULL,\r
+                   &HandleCount,\r
+                   &Handles\r
+                   );\r
+\r
+  if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Try to open one of the ethernet SNP protocol to send packet\r
+  //\r
+  Snp = NULL;\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    Handles[Index],\r
+                    &gEfiSimpleNetworkProtocolGuid,\r
+                    (VOID **) &Snp\r
+                    );\r
+\r
+    if ((Status == EFI_SUCCESS) && (Snp != NULL) &&\r
+        (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&\r
+        (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {\r
+\r
+      break;\r
+    }\r
+\r
+    Snp = NULL;\r
+  }\r
+\r
+  gBS->FreePool (Handles);\r
+  return Snp;\r
+}\r
+\r
+\r
+/**\r
+  Transmit a syslog packet synchronously through SNP. The Packet\r
+  already has the ethernet header prepended. This function should\r
+  fill in the source MAC because it will try to locate a SNP each\r
+  time it is called to avoid the problem if SNP is unloaded.\r
+  This code snip is copied from MNP.\r
+\r
+  @param  Packet                The Syslog packet\r
+  @param  Length                The length of the packet\r
+\r
+  @retval EFI_DEVICE_ERROR      Failed to locate a usable SNP protocol\r
+  @retval EFI_TIMEOUT           Timeout happened to send the packet.\r
+  @retval EFI_SUCCESS           Packet is sent.\r
+\r
+**/\r
+EFI_STATUS\r
+SyslogSendPacket (\r
+  IN UINT8                    *Packet,\r
+  IN UINT32                   Length\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  ETHER_HEAD                  *Ether;\r
+  EFI_STATUS                  Status;\r
+  EFI_EVENT                   TimeoutEvent;\r
+  UINT8                       *TxBuf;\r
+\r
+  Snp = SyslogLocateSnp ();\r
+\r
+  if (Snp == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Ether = (ETHER_HEAD *) Packet;\r
+  CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);\r
+\r
+  //\r
+  // Start the timeout event.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER,\r
+                  TPL_NOTIFY,\r
+                  NULL,\r
+                  NULL,\r
+                  &TimeoutEvent\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  for (;;) {\r
+    //\r
+    // Transmit the packet through SNP.\r
+    //\r
+    Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);\r
+\r
+    if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
+    // if Status is EFI_NOT_READY, the transmit engine of the network\r
+    // interface is busy. Both need to sync SNP.\r
+    //\r
+    TxBuf = NULL;\r
+\r
+    do {\r
+      //\r
+      // Get the recycled transmit buffer status.\r
+      //\r
+      Snp->GetStatus (Snp, NULL, &TxBuf);\r
+\r
+      if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+        Status = EFI_TIMEOUT;\r
+        break;\r
+      }\r
+\r
+    } while (TxBuf == NULL);\r
+\r
+    if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Status is EFI_NOT_READY. Restart the timer event and\r
+    // call Snp->Transmit again.\r
+    //\r
+    gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
+  }\r
+\r
+  gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
+\r
+ON_EXIT:\r
+  gBS->CloseEvent (TimeoutEvent);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Compute checksum for a bulk of data. This code is copied from the\r
+  Netbuffer library.\r
+\r
+  @param  Bulk                  Pointer to the data.\r
+  @param  Len                   Length of the data, in bytes.\r
+\r
+  @retval UINT16                The computed checksum.\r
+\r
+**/\r
+UINT16\r
+SyslogChecksum (\r
+  IN UINT8                  *Bulk,\r
+  IN UINT32                 Len\r
+  )\r
+{\r
+  register UINT32           Sum;\r
+\r
+  Sum = 0;\r
+\r
+  while (Len > 1) {\r
+    Sum += *(UINT16 *) Bulk;\r
+    Bulk += 2;\r
+    Len -= 2;\r
+  }\r
+\r
+  //\r
+  // Add left-over byte, if any\r
+  //\r
+  if (Len > 0) {\r
+    Sum += *(UINT8 *) Bulk;\r
+  }\r
+\r
+  //\r
+  // Fold 32-bit sum to 16 bits\r
+  //\r
+  while (Sum >> 16) {\r
+    Sum = (Sum & 0xffff) + (Sum >> 16);\r
+  }\r
+\r
+  return (UINT16) ~Sum;\r
+}\r
+\r
+\r
+/**\r
+  Build a syslog packet, including the Ethernet/Ip/Udp headers\r
+  and user's message.\r
+\r
+  @param  Buf                   The buffer to put the packet data\r
+  @param  BufLen                The lenght of the Buf\r
+  @param  Level                 Syslog servity level\r
+  @param  Module                The module that generates the log\r
+  @param  File                  The file that contains the current log\r
+  @param  Line                  The line of code in the File that contains the\r
+                                current log\r
+  @param  Message               The log message\r
+\r
+  @return The length of the syslog packet built.\r
+\r
+**/\r
+UINT32\r
+SyslogBuildPacket (\r
+  UINT8                     *Buf,\r
+  UINT32                    BufLen,\r
+  UINT32                    Level,\r
+  UINT8                     *Module,\r
+  UINT8                     *File,\r
+  UINT32                    Line,\r
+  UINT8                     *Message\r
+  )\r
+{\r
+  ETHER_HEAD                *Ether;\r
+  IP4_HEAD                  *Ip4;\r
+  EFI_UDP4_HEADER           *Udp4;\r
+  EFI_TIME                  Time;\r
+  UINT32                    Pri;\r
+  UINT32                    Len;\r
+\r
+  //\r
+  // Fill in the Ethernet header. Leave alone the source MAC.\r
+  // SyslogSendPacket will fill in the address for us.\r
+  //\r
+  Ether = (ETHER_HEAD *) Buf;\r
+  CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);\r
+  ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);\r
+\r
+  Ether->EtherType = HTONS (0x0800);    // IP protocol\r
+\r
+  Buf             += sizeof (ETHER_HEAD);\r
+  BufLen          -= sizeof (ETHER_HEAD);\r
+\r
+  //\r
+  // Fill in the IP header\r
+  //\r
+  Ip4              = (IP4_HEAD *) Buf;\r
+  Ip4->HeadLen     = 5;\r
+  Ip4->Ver         = 4;\r
+  Ip4->Tos         = 0;\r
+  Ip4->TotalLen    = 0;\r
+  Ip4->Id          = (UINT16) mSyslogPacketSeq;\r
+  Ip4->Fragment    = 0;\r
+  Ip4->Ttl         = 16;\r
+  Ip4->Protocol    = 0x11;\r
+  Ip4->Checksum    = 0;\r
+  Ip4->Src         = mSyslogSrcIp;\r
+  Ip4->Dst         = mSyslogDstIp;\r
+\r
+  Buf             += sizeof (IP4_HEAD);\r
+  BufLen          -= sizeof (IP4_HEAD);\r
+\r
+  //\r
+  // Fill in the UDP header, Udp checksum is optional. Leave it zero.\r
+  //\r
+  Udp4             = (EFI_UDP4_HEADER*) Buf;\r
+  Udp4->SrcPort    = HTONS (514);\r
+  Udp4->DstPort    = HTONS (514);\r
+  Udp4->Length     = 0;\r
+  Udp4->Checksum   = 0;\r
+\r
+  Buf             += sizeof (EFI_UDP4_HEADER);\r
+  BufLen          -= sizeof (EFI_UDP4_HEADER);\r
+\r
+  //\r
+  // Build the syslog message body with <PRI> Timestamp  machine module Message\r
+  //\r
+  Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);\r
+  gRT->GetTime (&Time, NULL);\r
+\r
+  //\r
+  // Use %a to format the ASCII strings, %s to format UNICODE strings\r
+  //\r
+  Len  = 0;\r
+  Len += (UINT32) AsciiSPrint (\r
+                    Buf,\r
+                    BufLen,\r
+                    "<%d> %a %d %d:%d:%d ",\r
+                    Pri,\r
+                    MonthName [Time.Month-1],\r
+                    Time.Day,\r
+                    Time.Hour,\r
+                    Time.Minute,\r
+                    Time.Second\r
+                    );\r
+  Len--;\r
+\r
+  Len += (UINT32) AsciiSPrint (\r
+                    Buf + Len,\r
+                    BufLen - Len,\r
+                    "Tiano %a: %a (Line: %d File: %a)",\r
+                    Module,\r
+                    Message,\r
+                    Line,\r
+                    File\r
+                    );\r
+  Len--;\r
+\r
+  //\r
+  // OK, patch the IP length/checksum and UDP length fields.\r
+  //\r
+  Len           += sizeof (EFI_UDP4_HEADER);\r
+  Udp4->Length   = HTONS ((UINT16) Len);\r
+\r
+  Len           += sizeof (IP4_HEAD);\r
+  Ip4->TotalLen  = HTONS ((UINT16) Len);\r
+  Ip4->Checksum  = SyslogChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD));\r
+\r
+  return Len + sizeof (ETHER_HEAD);\r
+}\r
+\r
+\r
+/**\r
+  Allocate a buffer, then format the message to it. This is a\r
+  help function for the NET_DEBUG_XXX macros. The PrintArg of\r
+  these macros treats the variable length print parameters as a\r
+  single parameter, and pass it to the NetDebugASPrint. For\r
+  example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))\r
+  if extracted to:\r
+  NetDebugOutput (\r
+  NETDEBUG_LEVEL_TRACE,\r
+  "Tcp",\r
+  __FILE__,\r
+  __LINE__,\r
+  NetDebugASPrint ("State transit to %a\n", Name)\r
+  )\r
+  This is exactly what we want.\r
+\r
+  @param  Format                The ASCII format string.\r
+  @param  ...                   The variable length parameter whose format is\r
+                                determined  by the Format string.\r
+\r
+  @return The buffer containing the formatted message, or NULL if failed to\r
+  @return allocate memory.\r
+\r
+**/\r
+UINT8 *\r
+NetDebugASPrint (\r
+  UINT8                     *Format,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                   Marker;\r
+  UINT8                     *Buf;\r
+\r
+  Buf = AllocatePool (NET_DEBUG_MSG_LEN);\r
+\r
+  if (Buf == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  VA_START (Marker, Format);\r
+  AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);\r
+  VA_END (Marker);\r
+\r
+  return Buf;\r
+}\r
+\r
+\r
+/**\r
+  Output a debug message to syslog. This function will locate a\r
+  instance of SNP then send the message through it. Because it\r
+  isn't open the SNP BY_DRIVER, apply caution when using it.\r
+\r
+  @param  Level                 The servity level of the message.\r
+  @param  Module                The Moudle that generates the log.\r
+  @param  File                  The file that contains the log.\r
+  @param  Line                  The exact line that contains the log.\r
+  @param  Message               The user message to log.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the packet\r
+  @retval EFI_SUCCESS           The log is discard because that it is more verbose\r
+                                than the mNetDebugLevelMax. Or, it has been sent\r
+                                out.\r
+\r
+**/\r
+EFI_STATUS\r
+NetDebugOutput (\r
+  UINT32                    Level,\r
+  UINT8                     *Module,\r
+  UINT8                     *File,\r
+  UINT32                    Line,\r
+  UINT8                     *Message\r
+  )\r
+{\r
+  UINT8                     *Packet;\r
+  UINT32                    Len;\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // Check whether the message should be sent out\r
+  //\r
+  if (Message == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (Level > mNetDebugLevelMax) {\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Allocate a maxium of 1024 bytes, the caller should ensure\r
+  // that the message plus the ethernet/ip/udp header is shorter\r
+  // than this\r
+  //\r
+  Packet = AllocatePool (NET_SYSLOG_PACKET_LEN);\r
+\r
+  if (Packet == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Build the message: Ethernet header + IP header + Udp Header + user data\r
+  //\r
+  Len = SyslogBuildPacket (\r
+          Packet,\r
+          NET_SYSLOG_PACKET_LEN,\r
+          Level,\r
+          Module,\r
+          File,\r
+          Line,\r
+          Message\r
+          );\r
+\r
+  mSyslogPacketSeq++;\r
+  Status = SyslogSendPacket (Packet, Len);\r
+  gBS->FreePool (Packet);\r
+\r
+ON_EXIT:\r
+  gBS->FreePool (Message);\r
+  return Status;\r
+}\r
index 421eaa011a95023d797e62b379aa217d142dc9eb..3b286980f630ae03e8db54f0aad3c4a4c036f72b 100644 (file)
 \r
 \r
 [LibraryClasses]\r
-  MemoryAllocationLib\r
-  UefiLib\r
+  UdpIoLib\r
   BaseLib\r
-  UefiBootServicesTableLib\r
-  UefiRuntimeServicesTableLib\r
-  BaseMemoryLib\r
   DebugLib\r
-  PrintLib\r
-\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
 \r
 [Protocols]\r
-  gEfiIp4ProtocolGuid                           # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverDiagnosticsProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
   gEfiUdp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiLoadedImageProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiIp4ServiceBindingProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverConfigurationProtocolGuid           # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiSimpleNetworkProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiDriverBindingProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
-  gEfiComponentNameProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
-\r
+  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED
\ No newline at end of file
index b461ecc56bbc055e7f6d59616a9547002a12d0bc..4947db5851d888eeee157a439754f9d760bc3803 100644 (file)
   $(WORKSPACE)/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
 \r
   $(WORKSPACE)/MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf\r
+  $(WORKSPACE)/MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf\r
+  $(WORKSPACE)/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf\r
+  $(WORKSPACE)/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf\r
+  $(WORKSPACE)/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf\r
 \r
   $(WORKSPACE)/MdeModulePkg/Application/HelloWorld/HelloWorld.inf\r
 \r
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/ComponentName.c b/MdeModulePkg/Universal/Network/MnpDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..209861c
--- /dev/null
@@ -0,0 +1,162 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "MnpDriver.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gMnpComponentName = {\r
+  MnpComponentNameGetDriverName,\r
+  MnpComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mMnpDriverNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"MNP Network Service Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller\r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a\r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language\r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCES            - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned\r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gMnpComponentName.SupportedLanguages,\r
+          mMnpDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by\r
+                       This is managing.  This handle specifies the controller\r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name\r
+                       of.  This is an optional parameter that may be NULL.  It\r
+                       will be NULL for device drivers.  It will also be NULL\r
+                       for a bus drivers that wish to retrieve the name of the\r
+                       bus controller.  It will not be NULL for a bus driver\r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language\r
+                       identifier.  This is the language of the controller name\r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The\r
+                       number of languages supported by a driver is up to the\r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by\r
+                       ControllerHandle and ChildHandle in the language specified\r
+                       by Language from the point of view of the driver specified\r
+                       by This.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the user readable name in the\r
+                            language specified by Language for the driver\r
+                            specified by This was returned in DriverName.\r
+    EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This is not currently managing\r
+                            the controller specified by ControllerHandle and\r
+                            ChildHandle.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c
new file mode 100644 (file)
index 0000000..c842991
--- /dev/null
@@ -0,0 +1,1466 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  MnpConfig.c\r
+\r
+Abstract:\r
+\r
+  Implementation of Managed Network Protocol private services.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "MnpImpl.h"\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL    mMnpServiceBindingProtocol = {\r
+  MnpServiceBindingCreateChild,\r
+  MnpServiceBindingDestroyChild\r
+};\r
+\r
+EFI_MANAGED_NETWORK_PROTOCOL    mMnpProtocolTemplate = {\r
+  MnpGetModeData,\r
+  MnpConfigure,\r
+  MnpMcastIpToMac,\r
+  MnpGroups,\r
+  MnpTransmit,\r
+  MnpReceive,\r
+  MnpCancel,\r
+  MnpPoll\r
+};\r
+\r
+EFI_MANAGED_NETWORK_CONFIG_DATA mMnpDefaultConfigData = {\r
+  10000,\r
+  10000,\r
+  0,\r
+  FALSE,\r
+  FALSE,\r
+  FALSE,\r
+  FALSE,\r
+  FALSE,\r
+  FALSE,\r
+  FALSE\r
+};\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpAddFreeNbuf (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData,\r
+  IN UINTN             Count\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStartSnp (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStopSnp (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStart (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData,\r
+  IN BOOLEAN           IsConfigUpdate,\r
+  IN BOOLEAN           EnableSystemPoll\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStop (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpConfigReceiveFilters (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpGroupOpAddCtrlBlk (\r
+  IN MNP_INSTANCE_DATA        *Instance,\r
+  IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk,\r
+  IN MNP_GROUP_ADDRESS        *GroupAddress OPTIONAL,\r
+  IN EFI_MAC_ADDRESS          *MacAddress,\r
+  IN UINT32                   HwAddressSize\r
+  );\r
+\r
+STATIC\r
+BOOLEAN\r
+MnpGroupOpDelCtrlBlk (\r
+  IN MNP_INSTANCE_DATA        *Instance,\r
+  IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk\r
+  );\r
+\r
+\r
+/**\r
+  Add some NET_BUF into MnpServiceData->FreeNbufQue. The buffer length of\r
+  the NET_BUF is specified by MnpServiceData->BufferLength.\r
+\r
+  @param  MnpServiceData        Pointer to the MNP_SERVICE_DATA.\r
+  @param  Count                 Number of NET_BUFFERs to add.\r
+\r
+  @retval EFI_SUCCESS           The specified amount of NET_BUFs are allocated and\r
+                                added into MnpServiceData->FreeNbufQue.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate a NET_BUF structure.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpAddFreeNbuf (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData,\r
+  IN UINTN             Count\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  NET_BUF     *Nbuf;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+  ASSERT ((Count > 0) && (MnpServiceData->BufferLength > 0));\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+\r
+    Nbuf = NetbufAlloc (MnpServiceData->BufferLength);\r
+    if (Nbuf == NULL) {\r
+\r
+      MNP_DEBUG_ERROR (("MnpAddFreeNbuf: NetBufAlloc failed.\n"));\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+\r
+    NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
+  }\r
+\r
+  MnpServiceData->NbufCnt += Index;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Allocate a free NET_BUF from MnpServiceData->FreeNbufQue. If there is none\r
+  in the queue, first try to allocate some and add them into the queue, then\r
+  fetch the NET_BUF from the updated FreeNbufQue.\r
+\r
+  @param  MnpServiceData        Pointer to the MNP_SERVICE_DATA.\r
+\r
+  @return Pointer to the allocated free NET_BUF structure, if NULL the operation is failed.\r
+\r
+**/\r
+NET_BUF *\r
+MnpAllocNbuf (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  NET_BUF_QUEUE *FreeNbufQue;\r
+  NET_BUF       *Nbuf;\r
+  EFI_TPL       OldTpl;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  FreeNbufQue = &MnpServiceData->FreeNbufQue;\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+  //\r
+  // Check whether there are available buffers, or else try to add some.\r
+  //\r
+  if (FreeNbufQue->BufNum == 0) {\r
+\r
+    if ((MnpServiceData->NbufCnt + MNP_NET_BUFFER_INCREASEMENT) > MNP_MAX_NET_BUFFER_NUM) {\r
+\r
+      MNP_DEBUG_ERROR (\r
+        ("MnpAllocNbuf: The maximum NET_BUF size is reached for MNP driver instance %p.\n",\r
+        MnpServiceData)\r
+        );\r
+\r
+      Nbuf = NULL;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = MnpAddFreeNbuf (MnpServiceData, MNP_NET_BUFFER_INCREASEMENT);\r
+    if (EFI_ERROR (Status)) {\r
+\r
+      MNP_DEBUG_ERROR (\r
+        ("MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n",\r
+        Status)\r
+        );\r
+      //\r
+      // Don't return NULL, perhaps MnpAddFreeNbuf does add some NET_BUFs but\r
+      // the amount is less than MNP_NET_BUFFER_INCREASEMENT.\r
+      //\r
+    }\r
+  }\r
+\r
+  Nbuf = NetbufQueRemove (FreeNbufQue);\r
+\r
+  //\r
+  // Increase the RefCnt.\r
+  //\r
+  if (Nbuf != NULL) {\r
+    NET_GET_REF (Nbuf);\r
+  }\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+  Try to reclaim the Nbuf into the buffer pool.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  Nbuf                  Pointer to the NET_BUF to free.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+MnpFreeNbuf (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData,\r
+  IN NET_BUF           *Nbuf\r
+  )\r
+{\r
+  EFI_TPL  OldTpl;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+  ASSERT (Nbuf->RefCnt > 1);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+  NET_PUT_REF (Nbuf);\r
+\r
+  if (Nbuf->RefCnt == 1) {\r
+    //\r
+    // Trim all buffer contained in the Nbuf, then append it to the NbufQue.\r
+    //\r
+    NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_TAIL);\r
+    NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
+  }\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+}\r
+\r
+\r
+/**\r
+  Initialize the mnp service context data.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  Snp                   Pointer to the simple network protocol.\r
+\r
+  @retval EFI_SUCCESS           The mnp service context is initialized.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpInitializeServiceData (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData,\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_HANDLE        ControllerHandle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
+  EFI_SIMPLE_NETWORK_MODE      *SnpMode;\r
+\r
+  MnpServiceData->Signature = MNP_SERVICE_DATA_SIGNATURE;\r
+\r
+  MnpServiceData->ControllerHandle = ControllerHandle;\r
+\r
+  //\r
+  // Copy the ServiceBinding structure.\r
+  //\r
+  MnpServiceData->ServiceBinding = mMnpServiceBindingProtocol;\r
+\r
+  //\r
+  // Open the Simple Network protocol.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  (VOID **) &Snp,\r
+                  ImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get MTU from Snp.\r
+  //\r
+  SnpMode             = Snp->Mode;\r
+  MnpServiceData->Snp = Snp;\r
+  MnpServiceData->Mtu = SnpMode->MaxPacketSize;\r
+\r
+  //\r
+  // Initialize the lists.\r
+  //\r
+  NetListInit (&MnpServiceData->GroupAddressList);\r
+  NetListInit (&MnpServiceData->ChildrenList);\r
+\r
+  //\r
+  // Get the buffer length used to allocate NET_BUF to hold data received\r
+  // from SNP. Do this before fill the FreeNetBufQue.\r
+  //\r
+  MnpServiceData->BufferLength = MnpServiceData->Mtu + SnpMode->MediaHeaderSize + NET_ETHER_FCS_SIZE;\r
+\r
+  //\r
+  // Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.\r
+  //\r
+  NetbufQueInit (&MnpServiceData->FreeNbufQue);\r
+  Status = MnpAddFreeNbuf (MnpServiceData, MNP_INIT_NET_BUFFER_NUM);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpInitializeServiceData: MnpAddFreeNbuf failed, %r.\n", Status));\r
+    goto ERROR;\r
+  }\r
+  //\r
+  // Get one NET_BUF from the FreeNbufQue for rx cache.\r
+  //\r
+  MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);\r
+  NetbufAllocSpace (\r
+    MnpServiceData->RxNbufCache,\r
+    MnpServiceData->BufferLength,\r
+    NET_BUF_TAIL\r
+    );\r
+\r
+  //\r
+  // Allocate buffer pool for tx.\r
+  //\r
+  MnpServiceData->TxBuf = NetAllocatePool (MnpServiceData->Mtu + SnpMode->MediaHeaderSize);\r
+  if (MnpServiceData->TxBuf == NULL) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpInitializeServiceData: NetAllocatePool failed.\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+\r
+    goto ERROR;\r
+  }\r
+\r
+  //\r
+  // Create the system poll timer.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+                  NET_TPL_LOCK,\r
+                  MnpSystemPoll,\r
+                  MnpServiceData,\r
+                  &MnpServiceData->PollTimer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpInitializeServiceData: CreateEvent for poll timer failed.\n"));\r
+    goto ERROR;\r
+  }\r
+\r
+  //\r
+  // Create the timer for packet timeout check.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+                  NET_TPL_EVENT,\r
+                  MnpCheckPacketTimeout,\r
+                  MnpServiceData,\r
+                  &MnpServiceData->TimeoutCheckTimer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpInitializeServiceData: CreateEvent for packet timeout check failed.\n"));\r
+    goto ERROR;\r
+  }\r
+\r
+  //\r
+  // Create the timer for tx timeout check.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER,\r
+                  NET_TPL_SLOW_TIMER,\r
+                  NULL,\r
+                  NULL,\r
+                  &MnpServiceData->TxTimeoutEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpInitializeServiceData: CreateEvent for tx timeout event failed.\n"));\r
+  }\r
+\r
+ERROR:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Free the dynamic allocated resources if necessary.\r
+    //\r
+    if (MnpServiceData->TimeoutCheckTimer != NULL) {\r
+\r
+      gBS->CloseEvent (MnpServiceData->TimeoutCheckTimer);\r
+    }\r
+\r
+    if (MnpServiceData->PollTimer != NULL) {\r
+\r
+      gBS->CloseEvent (MnpServiceData->PollTimer);\r
+    }\r
+\r
+    if (MnpServiceData->TxBuf != NULL) {\r
+\r
+      NetFreePool (MnpServiceData->TxBuf);\r
+    }\r
+\r
+    if (MnpServiceData->RxNbufCache != NULL) {\r
+\r
+      MnpFreeNbuf (MnpServiceData, MnpServiceData->RxNbufCache);\r
+    }\r
+\r
+    if (MnpServiceData->FreeNbufQue.BufNum != 0) {\r
+\r
+      NetbufQueFlush (&MnpServiceData->FreeNbufQue);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Flush the mnp service context data.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+MnpFlushServiceData (\r
+  MNP_SERVICE_DATA  *MnpServiceData\r
+  )\r
+{\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  //\r
+  // The GroupAddressList must be empty.\r
+  //\r
+  ASSERT (NetListIsEmpty (&MnpServiceData->GroupAddressList));\r
+\r
+  //\r
+  // Close the event.\r
+  //\r
+  gBS->CloseEvent (&MnpServiceData->TxTimeoutEvent);\r
+  gBS->CloseEvent (&MnpServiceData->TimeoutCheckTimer);\r
+  gBS->CloseEvent (&MnpServiceData->PollTimer);\r
+\r
+  //\r
+  // Free the tx buffer.\r
+  //\r
+  NetFreePool (MnpServiceData->TxBuf);\r
+\r
+  //\r
+  // Free the RxNbufCache.\r
+  //\r
+  MnpFreeNbuf (MnpServiceData, MnpServiceData->RxNbufCache);\r
+\r
+  //\r
+  // Flush the FreeNbufQue.\r
+  //\r
+  MnpServiceData->NbufCnt -= MnpServiceData->FreeNbufQue.BufNum;\r
+  NetbufQueFlush (&MnpServiceData->FreeNbufQue);\r
+\r
+  DEBUG_CODE (\r
+\r
+    if (MnpServiceData->NbufCnt != 0) {\r
+\r
+    MNP_DEBUG_WARN (("MnpFlushServiceData: Memory leak, MnpServiceData->NbufCnt != 0.\n"));\r
+  }\r
+  );\r
+}\r
+\r
+\r
+/**\r
+  Initialize the mnp instance context data.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  Instance              Pointer to the mnp instance context data to\r
+                                initialize.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+MnpInitializeInstanceData (\r
+  IN MNP_SERVICE_DATA   *MnpServiceData,\r
+  IN MNP_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+  ASSERT (Instance != NULL);\r
+\r
+  //\r
+  // Set the signature.\r
+  //\r
+  Instance->Signature = MNP_INSTANCE_DATA_SIGNATURE;\r
+\r
+  //\r
+  // Copy the MNP Protocol interfaces from the template.\r
+  //\r
+  Instance->ManagedNetwork = mMnpProtocolTemplate;\r
+\r
+  //\r
+  // Copy the default config data.\r
+  //\r
+  Instance->ConfigData = mMnpDefaultConfigData;\r
+\r
+  //\r
+  // Initialize the lists.\r
+  //\r
+  NetListInit (&Instance->GroupCtrlBlkList);\r
+  NetListInit (&Instance->RcvdPacketQueue);\r
+  NetListInit (&Instance->RxDeliveredPacketQueue);\r
+\r
+  //\r
+  // Initialize the RxToken Map.\r
+  //\r
+  NetMapInit (&Instance->RxTokenMap);\r
+\r
+  //\r
+  // Save the MnpServiceData info.\r
+  //\r
+  Instance->MnpServiceData = MnpServiceData;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the token specified by Arg maches the token in Item.\r
+\r
+  @param  Map                   Pointer to the NET_MAP.\r
+  @param  Item                  Pointer to the NET_MAP_ITEM\r
+  @param  Arg                   Pointer to the Arg, it's a pointer to the token to\r
+                                check.\r
+\r
+  @retval EFI_SUCCESS           The token specified by Arg is different from the\r
+                                token in Item.\r
+  @retval EFI_ACCESS_DENIED     The token specified by Arg is the same as that in\r
+                                Item.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpTokenExist (\r
+  IN NET_MAP       *Map,\r
+  IN NET_MAP_ITEM  *Item,\r
+  IN VOID          *Arg\r
+  )\r
+{\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token;\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenInItem;\r
+\r
+  Token       = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Arg;\r
+  TokenInItem = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
+\r
+  if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
+    //\r
+    // The token is the same either the two tokens equals or the Events in\r
+    // the two tokens are the same.\r
+    //\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Cancel the token specified by Arg if it matches the token in Item.\r
+\r
+  @param  Map                   Pointer to the NET_MAP.\r
+  @param  Item                  Pointer to the NET_MAP_ITEM\r
+  @param  Arg                   Pointer to the Arg, it's a pointer to the token to\r
+                                cancel.\r
+\r
+  @retval EFI_SUCCESS           The Arg is NULL, and the token in Item is\r
+                                cancelled, or the Arg isn't NULL, and the token in\r
+                                Item is different from the Arg.\r
+  @retval EFI_ABORTED           The Arg isn't NULL, the token in Item mathces the\r
+                                Arg, and the token is cancelled.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpCancelTokens (\r
+  IN NET_MAP       *Map,\r
+  IN NET_MAP_ITEM  *Item,\r
+  IN VOID          *Arg\r
+  )\r
+{\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenToCancel;\r
+\r
+  if ((Arg != NULL) && (Item->Key != Arg)) {\r
+    //\r
+    // The token in Item is not the token specified by Arg.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  TokenToCancel         = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
+\r
+  //\r
+  // Cancel this token with status set to EFI_ABORTED.\r
+  //\r
+  TokenToCancel->Status = EFI_ABORTED;\r
+  gBS->SignalEvent (TokenToCancel->Event);\r
+\r
+  //\r
+  // Remove the item from the map.\r
+  //\r
+  NetMapRemoveItem (Map, Item, NULL);\r
+\r
+  if (Arg != NULL) {\r
+    //\r
+    // Only abort the token specified by Arg if Arg isn't NULL.\r
+    //\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Start and initialize the simple network.\r
+\r
+  @param  Snp                   Pointer to the simple network protocol.\r
+\r
+  @retval EFI_SUCCESS           The simple network protocol is started.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStartSnp (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (Snp != NULL);\r
+\r
+  //\r
+  // Start the simple network.\r
+  //\r
+  Status = Snp->Start (Snp);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Initialize the simple network.\r
+    //\r
+    Status  = Snp->Initialize (Snp, 0, 0);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop the simple network.\r
+\r
+  @param  Snp                   Pointer to the simple network protocol.\r
+\r
+  @retval EFI_SUCCESS           The simple network is stopped.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStopSnp (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (Snp != NULL);\r
+\r
+  //\r
+  // Shut down the simple network.\r
+  //\r
+  Status = Snp->Shutdown (Snp);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Stop the simple network.\r
+    //\r
+    Status = Snp->Stop (Snp);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start the managed network, this function is called when one instance is configured\r
+  or reconfigured.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  IsConfigUpdate        The instance is reconfigured or it's the first time\r
+                                 the instanced is configured.\r
+  @param  EnableSystemPoll      Enable the system polling or not.\r
+\r
+  @retval EFI_SUCCESS           The managed network is started and some\r
+                                configuration is updated.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStart (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData,\r
+  IN BOOLEAN           IsConfigUpdate,\r
+  IN BOOLEAN           EnableSystemPoll\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  EFI_TIMER_DELAY TimerOpType;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (!IsConfigUpdate) {\r
+    //\r
+    // If it's not a configuration update, increase the configured children number.\r
+    //\r
+    MnpServiceData->ConfiguredChildrenNumber++;\r
+\r
+    if (MnpServiceData->ConfiguredChildrenNumber == 1) {\r
+      //\r
+      // It's the first configured child, start the simple network.\r
+      //\r
+      Status = MnpStartSnp (MnpServiceData->Snp);\r
+      if (EFI_ERROR (Status)) {\r
+\r
+        MNP_DEBUG_ERROR (("MnpStart: MnpStartSnp failed, %r.\n", Status));\r
+        goto ErrorExit;\r
+      }\r
+\r
+      //\r
+      // Start the timeout timer.\r
+      //\r
+      Status = gBS->SetTimer (\r
+                      MnpServiceData->TimeoutCheckTimer,\r
+                      TimerPeriodic,\r
+                      MNP_TIMEOUT_CHECK_INTERVAL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+\r
+        MNP_DEBUG_ERROR (\r
+          ("MnpStart, gBS->SetTimer for TimeoutCheckTimer %r.\n",\r
+          Status)\r
+          );\r
+        goto ErrorExit;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (MnpServiceData->EnableSystemPoll ^ EnableSystemPoll) {\r
+    //\r
+    // The EnableSystemPoll differs with the current state, disable or enable\r
+    // the system poll.\r
+    //\r
+    TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;\r
+\r
+    Status      = gBS->SetTimer (MnpServiceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);\r
+    if (EFI_ERROR (Status)) {\r
+\r
+      MNP_DEBUG_ERROR (("MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));\r
+      goto ErrorExit;\r
+    }\r
+\r
+    MnpServiceData->EnableSystemPoll = EnableSystemPoll;\r
+  }\r
+\r
+  //\r
+  // Change the receive filters if need.\r
+  //\r
+  Status = MnpConfigReceiveFilters (MnpServiceData);\r
+\r
+ErrorExit:\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop the managed network.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+\r
+  @retval EFI_SUCCESS           The managed network is stopped.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStop (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+  ASSERT (MnpServiceData->ConfiguredChildrenNumber > 0);\r
+\r
+  //\r
+  // Configure the receive filters.\r
+  //\r
+  MnpConfigReceiveFilters (MnpServiceData);\r
+\r
+  //\r
+  // Decrease the children number.\r
+  //\r
+  MnpServiceData->ConfiguredChildrenNumber--;\r
+\r
+  if (MnpServiceData->ConfiguredChildrenNumber > 0) {\r
+    //\r
+    // If there are other configured chilren, return and keep the timers and\r
+    // simple network unchanged.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // No configured children now.\r
+  //\r
+\r
+  if (MnpServiceData->EnableSystemPoll) {\r
+    //\r
+    //  The system poll in on, cancel the poll timer.\r
+    //\r
+    Status  = gBS->SetTimer (MnpServiceData->PollTimer, TimerCancel, 0);\r
+    MnpServiceData->EnableSystemPoll = FALSE;\r
+  }\r
+\r
+  //\r
+  // Cancel the timeout timer.\r
+  //\r
+  Status  = gBS->SetTimer (MnpServiceData->TimeoutCheckTimer, TimerCancel, 0);\r
+\r
+  //\r
+  // Stop the simple network.\r
+  //\r
+  Status  = MnpStopSnp (MnpServiceData->Snp);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Flush the instance's received data.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+MnpFlushRcvdDataQueue (\r
+  IN MNP_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  EFI_TPL          OldTpl;\r
+  MNP_RXDATA_WRAP *RxDataWrap;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+  while (!NetListIsEmpty (&Instance->RcvdPacketQueue)) {\r
+    //\r
+    // Remove all the Wraps.\r
+    //\r
+    RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
+\r
+    //\r
+    // Recycle the RxDataWrap.\r
+    //\r
+    MnpRecycleRxData (NULL, (VOID *) RxDataWrap);\r
+    Instance->RcvdPacketQueueSize--;\r
+  }\r
+\r
+  ASSERT (Instance->RcvdPacketQueueSize == 0);\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+}\r
+\r
+\r
+/**\r
+  Configure the Instance using ConfigData.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+  @param  ConfigData            Pointer to the configuration data used to configure\r
+                                the isntance.\r
+\r
+  @retval EFI_SUCCESS           The Instance is configured.\r
+  @retval EFI_UNSUPPORTED       EnableReceiveTimestamps is on and the\r
+                                implementation doesn't support it.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpConfigureInstance (\r
+  IN MNP_INSTANCE_DATA                *Instance,\r
+  IN EFI_MANAGED_NETWORK_CONFIG_DATA  *ConfigData OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  MNP_SERVICE_DATA                *MnpServiceData;\r
+  EFI_MANAGED_NETWORK_CONFIG_DATA *OldConfigData;\r
+  EFI_MANAGED_NETWORK_CONFIG_DATA *NewConfigData;\r
+  BOOLEAN                         IsConfigUpdate;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  if ((ConfigData != NULL) && ConfigData->EnableReceiveTimestamps) {\r
+    //\r
+    // Don't support timestamp.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status          = EFI_SUCCESS;\r
+\r
+  MnpServiceData  = Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  IsConfigUpdate  = (BOOLEAN) ((Instance->Configured) && (ConfigData != NULL));\r
+\r
+  OldConfigData   = &Instance->ConfigData;\r
+  NewConfigData   = ConfigData;\r
+  if (NewConfigData == NULL) {\r
+    //\r
+    // Restore back the default config data if a reset of this instance\r
+    // is required.\r
+    //\r
+    NewConfigData = &mMnpDefaultConfigData;\r
+  }\r
+\r
+  //\r
+  // Reset the instance's receive filter.\r
+  //\r
+  Instance->ReceiveFilter = 0;\r
+\r
+  //\r
+  // Clear the receive counters according to the old ConfigData.\r
+  //\r
+  if (OldConfigData->EnableUnicastReceive) {\r
+    MnpServiceData->UnicastCount--;\r
+  }\r
+\r
+  if (OldConfigData->EnableMulticastReceive) {\r
+    MnpServiceData->MulticastCount--;\r
+  }\r
+\r
+  if (OldConfigData->EnableBroadcastReceive) {\r
+    MnpServiceData->BroadcastCount--;\r
+  }\r
+\r
+  if (OldConfigData->EnablePromiscuousReceive) {\r
+    MnpServiceData->PromiscuousCount--;\r
+  }\r
+\r
+  //\r
+  // Set the receive filter counters and the receive filter of the\r
+  // instance according to the new ConfigData.\r
+  //\r
+  if (NewConfigData->EnableUnicastReceive) {\r
+    MnpServiceData->UnicastCount++;\r
+    Instance->ReceiveFilter |= MNP_RECEIVE_UNICAST;\r
+  }\r
+\r
+  if (NewConfigData->EnableMulticastReceive) {\r
+    MnpServiceData->MulticastCount++;\r
+  }\r
+\r
+  if (NewConfigData->EnableBroadcastReceive) {\r
+    MnpServiceData->BroadcastCount++;\r
+    Instance->ReceiveFilter |= MNP_RECEIVE_BROADCAST;\r
+  }\r
+\r
+  if (NewConfigData->EnablePromiscuousReceive) {\r
+    MnpServiceData->PromiscuousCount++;\r
+  }\r
+\r
+  if (OldConfigData->FlushQueuesOnReset) {\r
+\r
+    MnpFlushRcvdDataQueue (Instance);\r
+  }\r
+\r
+  if (ConfigData == NULL) {\r
+\r
+    NetMapIterate (&Instance->RxTokenMap, MnpCancelTokens, NULL);\r
+  }\r
+\r
+  if (!NewConfigData->EnableMulticastReceive) {\r
+\r
+    MnpGroupOp (Instance, FALSE, NULL, NULL);\r
+  }\r
+\r
+  //\r
+  // Save the new configuration data.\r
+  //\r
+  *OldConfigData        = *NewConfigData;\r
+\r
+  Instance->Configured  = (BOOLEAN) (ConfigData != NULL);\r
+\r
+  if (Instance->Configured) {\r
+    //\r
+    // The instance is configured, start the Mnp.\r
+    //\r
+    Status = MnpStart (\r
+              MnpServiceData,\r
+              IsConfigUpdate,\r
+              !NewConfigData->DisableBackgroundPolling\r
+              );\r
+  } else {\r
+    //\r
+    // The instance is changed to the unconfigured state, stop the Mnp.\r
+    //\r
+    Status = MnpStop (MnpServiceData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Configure the Snp receive filters according to the instances' receive filter\r
+  settings.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+\r
+  @retval EFI_SUCCESS           The receive filters is configured.\r
+  @retval EFI_OUT_OF_RESOURCES  The receive filters can't be configured due to lack\r
+                                of memory resource.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpConfigReceiveFilters (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_MAC_ADDRESS             *MCastFilter;\r
+  UINT32                      MCastFilterCnt;\r
+  UINT32                      EnableFilterBits;\r
+  UINT32                      DisableFilterBits;\r
+  BOOLEAN                     ResetMCastFilters;\r
+  NET_LIST_ENTRY              *Entry;\r
+  UINT32                      Index;\r
+  MNP_GROUP_ADDRESS           *GroupAddress;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  Snp = MnpServiceData->Snp;\r
+\r
+  //\r
+  // Initialize the enable filter and disable filter.\r
+  //\r
+  EnableFilterBits  = 0;\r
+  DisableFilterBits = Snp->Mode->ReceiveFilterMask;\r
+\r
+  if (MnpServiceData->UnicastCount != 0) {\r
+    //\r
+    // Enable unicast if any instance wants to receive unicast.\r
+    //\r
+    EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+  }\r
+\r
+  if (MnpServiceData->BroadcastCount != 0) {\r
+    //\r
+    // Enable broadcast if any instance wants to receive broadcast.\r
+    //\r
+    EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+  }\r
+\r
+  MCastFilter       = NULL;\r
+  MCastFilterCnt    = 0;\r
+  ResetMCastFilters = TRUE;\r
+\r
+  if ((MnpServiceData->MulticastCount != 0) && (MnpServiceData->GroupAddressCount != 0)) {\r
+    //\r
+    // There are instances configured to receive multicast and already some group\r
+    // addresses are joined.\r
+    //\r
+\r
+    ResetMCastFilters = FALSE;\r
+\r
+    if (MnpServiceData->GroupAddressCount <= Snp->Mode->MaxMCastFilterCount) {\r
+      //\r
+      // The joind group address is less than simple network's maximum count.\r
+      // Just configure the snp to do the multicast filtering.\r
+      //\r
+\r
+      EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+\r
+      //\r
+      // Allocate pool for the mulicast addresses.\r
+      //\r
+      MCastFilterCnt  = MnpServiceData->GroupAddressCount;\r
+      MCastFilter     = NetAllocatePool (sizeof (EFI_MAC_ADDRESS) * MCastFilterCnt);\r
+      if (MCastFilter == NULL) {\r
+\r
+        MNP_DEBUG_ERROR (("MnpConfigReceiveFilters: Failed to allocate memory resource for MCastFilter.\n"));\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      //\r
+      // Fill the multicast HW address buffer.\r
+      //\r
+      Index = 0;\r
+      NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
+\r
+        GroupAddress            = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
+        *(MCastFilter + Index)  = GroupAddress->Address;\r
+        Index++;\r
+\r
+        ASSERT (Index <= MCastFilterCnt);\r
+      }\r
+    } else {\r
+      //\r
+      // The maximum multicast is reached, set the filter to be promiscuous\r
+      // multicast.\r
+      //\r
+\r
+      if (Snp->Mode->ReceiveFilterMask & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
+        EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+      } else {\r
+        //\r
+        // Either MULTICAST or PROMISCUOUS_MULTICAST is not supported by Snp,\r
+        // set the NIC to be promiscuous although this will tremendously degrade\r
+        // the performance.\r
+        //\r
+        EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (MnpServiceData->PromiscuousCount != 0) {\r
+    //\r
+    // Enable promiscuous if any instance wants to receive promiscuous.\r
+    //\r
+    EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+  }\r
+\r
+  //\r
+  // Set the disable filter.\r
+  //\r
+  DisableFilterBits ^= EnableFilterBits;\r
+\r
+  //\r
+  // Configure the receive filters of SNP.\r
+  //\r
+  Status = Snp->ReceiveFilters (\r
+                  Snp,\r
+                  EnableFilterBits,\r
+                  DisableFilterBits,\r
+                  ResetMCastFilters,\r
+                  MCastFilterCnt,\r
+                  MCastFilter\r
+                  );\r
+  DEBUG_CODE (\r
+    if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (\r
+      ("MnpConfigReceiveFilters: Snp->ReceiveFilters failed, %r.\n",\r
+      Status)\r
+      );\r
+  }\r
+  );\r
+\r
+  if (MCastFilter != NULL) {\r
+    //\r
+    // Free the buffer used to hold the group addresses.\r
+    //\r
+    NetFreePool (MCastFilter);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Add a group address control block which controls the MacAddress for\r
+  this instance.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+  @param  CtrlBlk               Pointer to the group address control block.\r
+  @param  GroupAddress          Pointer to the group adress.\r
+  @param  MacAddress            Pointer to the mac address.\r
+  @param  HwAddressSize         The hardware address size.\r
+\r
+  @retval EFI_SUCCESS           The group address control block is added.\r
+  @retval EFI_OUT_OF_RESOURCE   Failed due to lack of memory resources.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpGroupOpAddCtrlBlk (\r
+  IN MNP_INSTANCE_DATA        *Instance,\r
+  IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk,\r
+  IN MNP_GROUP_ADDRESS        *GroupAddress OPTIONAL,\r
+  IN EFI_MAC_ADDRESS          *MacAddress,\r
+  IN UINT32                   HwAddressSize\r
+  )\r
+{\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  MnpServiceData = Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  if (GroupAddress == NULL) {\r
+\r
+    ASSERT (MacAddress != NULL);\r
+\r
+    //\r
+    // Allocate a new GroupAddress to be added into MNP's GroupAddressList.\r
+    //\r
+    GroupAddress = NetAllocatePool (sizeof (MNP_GROUP_ADDRESS));\r
+    if (GroupAddress == NULL) {\r
+\r
+      MNP_DEBUG_ERROR (("MnpGroupOpFormCtrlBlk: Failed to allocate memory resource.\n"));\r
+\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    GroupAddress->Address = *MacAddress;\r
+    GroupAddress->RefCnt  = 0;\r
+    NetListInsertTail (\r
+      &MnpServiceData->GroupAddressList,\r
+      &GroupAddress->AddrEntry\r
+      );\r
+    MnpServiceData->GroupAddressCount++;\r
+  }\r
+\r
+  //\r
+  // Increase the RefCnt.\r
+  //\r
+  GroupAddress->RefCnt++;\r
+\r
+  //\r
+  // Add the CtrlBlk into the instance's GroupCtrlBlkList.\r
+  //\r
+  CtrlBlk->GroupAddress = GroupAddress;\r
+  NetListInsertTail (&Instance->GroupCtrlBlkList, &CtrlBlk->CtrlBlkEntry);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Delete a group control block from the instance. If the controlled group address's\r
+  reference count reaches zero, the group address is removed too.\r
+\r
+  @param  Instance              Pointer to the instance context data.\r
+  @param  CtrlBlk               Pointer to the group control block to delete.\r
+\r
+  @return The group address controlled by the control block is no longer used or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+MnpGroupOpDelCtrlBlk (\r
+  IN MNP_INSTANCE_DATA        *Instance,\r
+  IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk\r
+  )\r
+{\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+  MNP_GROUP_ADDRESS *GroupAddress;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  MnpServiceData = Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  //\r
+  // Remove and free the CtrlBlk.\r
+  //\r
+  GroupAddress = CtrlBlk->GroupAddress;\r
+  NetListRemoveEntry (&CtrlBlk->CtrlBlkEntry);\r
+  NetFreePool (CtrlBlk);\r
+\r
+  ASSERT (GroupAddress->RefCnt > 0);\r
+\r
+  //\r
+  // Count down the RefCnt.\r
+  //\r
+  GroupAddress->RefCnt--;\r
+\r
+  if (GroupAddress->RefCnt == 0) {\r
+    //\r
+    // Free this GroupAddress entry if no instance uses it.\r
+    //\r
+    MnpServiceData->GroupAddressCount--;\r
+    NetListRemoveEntry (&GroupAddress->AddrEntry);\r
+    NetFreePool (GroupAddress);\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Do the group operations for this instance.\r
+\r
+  @param  Instance              Pointer to the instance context data.\r
+  @param  JoinFlag              Set to TRUE to join a group. Set to TRUE to leave a\r
+                                group/groups.\r
+  @param  MacAddress            Pointer to the group address to join or leave.\r
+  @param  CtrlBlk               Pointer to the group control block if JoinFlag if\r
+                                FALSE.\r
+\r
+  @retval EFI_SUCCESS           The group operation finished.\r
+  @retval Other                 Some error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpGroupOp (\r
+  IN MNP_INSTANCE_DATA        *Instance,\r
+  IN BOOLEAN                  JoinFlag,\r
+  IN EFI_MAC_ADDRESS          *MacAddress OPTIONAL,\r
+  IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk OPTIONAL\r
+  )\r
+{\r
+  MNP_SERVICE_DATA        *MnpServiceData;\r
+  NET_LIST_ENTRY          *Entry;\r
+  NET_LIST_ENTRY          *NextEntry;\r
+  MNP_GROUP_ADDRESS       *GroupAddress;\r
+  EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+  MNP_GROUP_CONTROL_BLOCK *NewCtrlBlk;\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 AddressExist;\r
+  BOOLEAN                 NeedUpdate;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  MnpServiceData  = Instance->MnpServiceData;\r
+  SnpMode         = MnpServiceData->Snp->Mode;\r
+\r
+  if (JoinFlag) {\r
+    //\r
+    // A new gropu address is to be added.\r
+    //\r
+\r
+    GroupAddress  = NULL;\r
+    AddressExist  = FALSE;\r
+\r
+    //\r
+    // Allocate memory for the control block.\r
+    //\r
+    NewCtrlBlk    = NetAllocatePool (sizeof (MNP_GROUP_CONTROL_BLOCK));\r
+    if (NewCtrlBlk == NULL) {\r
+\r
+      MNP_DEBUG_ERROR (("MnpGroupOp: Failed to allocate memory resource.\n"));\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
+      //\r
+      // Check whether the MacAddress is already joined by other instances.\r
+      //\r
+      GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
+      if (0 == NetCompareMem (\r
+                MacAddress,\r
+                &GroupAddress->Address,\r
+                SnpMode->HwAddressSize\r
+                )) {\r
+\r
+        AddressExist = TRUE;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (!AddressExist) {\r
+      GroupAddress = NULL;\r
+    }\r
+\r
+    //\r
+    // Add the GroupAddress for this instance.\r
+    //\r
+    Status = MnpGroupOpAddCtrlBlk (\r
+              Instance,\r
+              NewCtrlBlk,\r
+              GroupAddress,\r
+              MacAddress,\r
+              SnpMode->HwAddressSize\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+\r
+      return Status;\r
+    }\r
+\r
+    NeedUpdate = TRUE;\r
+  } else {\r
+\r
+    if (MacAddress != NULL) {\r
+\r
+      ASSERT (CtrlBlk != NULL);\r
+\r
+      //\r
+      // Leave the specific multicast mac address.\r
+      //\r
+      NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, CtrlBlk);\r
+    } else {\r
+      //\r
+      // Leave all multicast mac addresses.\r
+      //\r
+      NeedUpdate = FALSE;\r
+\r
+      NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->GroupCtrlBlkList) {\r
+\r
+        NewCtrlBlk = NET_LIST_USER_STRUCT (\r
+                      Entry,\r
+                      MNP_GROUP_CONTROL_BLOCK,\r
+                      CtrlBlkEntry\r
+                      );\r
+        //\r
+        // Update is required if the group address left is no longer used\r
+        // by other instances.\r
+        //\r
+        NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, NewCtrlBlk);\r
+      }\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (NeedUpdate) {\r
+    //\r
+    // Reconfigure the receive filters if necessary.\r
+    //\r
+    Status = MnpConfigReceiveFilters (MnpServiceData);\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDebug.h b/MdeModulePkg/Universal/Network/MnpDxe/MnpDebug.h
new file mode 100644 (file)
index 0000000..72eb59b
--- /dev/null
@@ -0,0 +1,28 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  MnpDebug.h
+
+Abstract:
+
+
+**/
+
+#ifndef _MNP_DEBUG_H_
+#define _MNP_DEBUG_H_
+
+#define MNP_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE ("Mnp", PrintArg)
+#define MNP_DEBUG_WARN(PrintArg)  NET_DEBUG_WARNING ("Mnp", PrintArg)
+#define MNP_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR ("Mnp", PrintArg)
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.c
new file mode 100644 (file)
index 0000000..07be21d
--- /dev/null
@@ -0,0 +1,560 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  MnpDriver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "MnpDriver.h"\r
+#include "MnpDebug.h"\r
+#include "MnpImpl.h"\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = {\r
+  MnpDriverBindingSupported,\r
+  MnpDriverBindingStart,\r
+  MnpDriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to test.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCES             This driver supports this device.\r
+  @retval EFI_ALREADY_STARTED    This driver is already running on this device.\r
+  @retval other                  This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Test to see if MNP is already installed.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  //\r
+  // Test to see if SNP is installed.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start this driver on ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCES             This driver is added to ControllerHandle.\r
+  @retval EFI_ALREADY_STARTED    This driver is already running on\r
+                                 ControllerHandle.\r
+  @retval other                  This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+  BOOLEAN           MnpInitialized;\r
+\r
+  MnpInitialized  = FALSE;\r
+\r
+  MnpServiceData  = NetAllocateZeroPool (sizeof (MNP_SERVICE_DATA));\r
+  if (MnpServiceData == NULL) {\r
+    MNP_DEBUG_ERROR (("MnpDriverBindingStart(): Failed to allocate the "\r
+      L"Mnp Service Data.\n"));\r
+\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Initialize the Mnp Service Data.\r
+  //\r
+  Status = MnpInitializeServiceData (MnpServiceData, This->DriverBindingHandle, ControllerHandle);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpDriverBindingStart: MnpInitializeServiceData "\r
+      L"failed, %r.\n",Status));\r
+    goto ErrorExit;\r
+  }\r
+\r
+  MnpInitialized = TRUE;\r
+\r
+  //\r
+  // Install the MNP Service Binding Protocol.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ControllerHandle,\r
+                  &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+                  &MnpServiceData->ServiceBinding,\r
+                  NULL\r
+                  );\r
+\r
+ErrorExit:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    if (MnpInitialized) {\r
+      //\r
+      // Flush the Mnp Service Data.\r
+      //\r
+      MnpFlushServiceData (MnpServiceData);\r
+    }\r
+\r
+    //\r
+    // Close the Simple Network Protocol.\r
+    //\r
+    gBS->CloseProtocol (\r
+          ControllerHandle,\r
+          &gEfiSimpleNetworkProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          ControllerHandle\r
+          );\r
+\r
+    NetFreePool (MnpServiceData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to stop driver on.\r
+  @param  NumberOfChildren       Number of Handles in ChildHandleBuffer. If number\r
+                                 of children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer      List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCES             This driver is removed ControllerHandle.\r
+  @retval other                  This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
+  MNP_SERVICE_DATA              *MnpServiceData;\r
+  MNP_INSTANCE_DATA             *Instance;\r
+\r
+  //\r
+  // Retrieve the MNP service binding protocol from the ControllerHandle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+                  (VOID **) &ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (\r
+      ("MnpDriverBindingStop: Locate MNP Service Binding Protocol failed, %r.\n",\r
+      Status)\r
+      );\r
+    goto EXIT;\r
+  }\r
+\r
+  MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (ServiceBinding);\r
+\r
+  while (!NetListIsEmpty (&MnpServiceData->ChildrenList)) {\r
+    //\r
+    // Don't use NetListRemoveHead here, the remove opreration will be done\r
+    // in ServiceBindingDestroyChild.\r
+    //\r
+    Instance = NET_LIST_HEAD (\r
+                &MnpServiceData->ChildrenList,\r
+                MNP_INSTANCE_DATA,\r
+                InstEntry\r
+                );\r
+\r
+    ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
+  }\r
+\r
+  //\r
+  // Uninstall the MNP Service Binding Protocol.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  ControllerHandle,\r
+                  &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+                  ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpDriverBindingStop: Uninstall MNP Service Binding Protocol failed, %r.\n"));\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Close the openned Snp protocol.\r
+  //\r
+  Status = gBS->CloseProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpDriverBindingStop: Close SNP Protocol failed, %r.\n", Status));\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Flush the Mnp service data.\r
+  //\r
+  MnpFlushServiceData (MnpServiceData);\r
+\r
+  NetFreePool (MnpServiceData);\r
+\r
+EXIT:\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Creates a child handle with a set of I/O services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Pointer to the handle of the child to create. If\r
+                                 it is NULL, then a new handle is created. If it is\r
+                                 not NULL, then the I/O services are  added to the\r
+                                 existing child handle.\r
+\r
+  @retval EFI_SUCCES             The child handle was created with the I/O\r
+                                 services.\r
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources availabe to create\r
+                                 the child.\r
+  @retval other                  The child handle was not created.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    *ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  MNP_SERVICE_DATA   *MnpServiceData;\r
+  MNP_INSTANCE_DATA  *Instance;\r
+  VOID               *Snp;\r
+  EFI_TPL            OldTpl;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Allocate buffer for the new instance.\r
+  //\r
+  Instance = NetAllocateZeroPool (sizeof (MNP_INSTANCE_DATA));\r
+  if (Instance == NULL) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpServiceBindingCreateChild: Faild to allocate memory for the new instance.\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Init the instance data.\r
+  //\r
+  MnpInitializeInstanceData (MnpServiceData, Instance);\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiManagedNetworkProtocolGuid,\r
+                  &Instance->ManagedNetwork,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (\r
+      ("MnpServiceBindingCreateChild: Failed to install the MNP protocol, %r.\n",\r
+      Status)\r
+      );\r
+    goto ErrorExit;\r
+  }\r
+\r
+  //\r
+  // Save the instance's childhandle.\r
+  //\r
+  Instance->Handle = *ChildHandle;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  MnpServiceData->ControllerHandle,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  (VOID **) &Snp,\r
+                  gMnpDriverBinding.DriverBindingHandle,\r
+                  Instance->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  //\r
+  // Add the child instance into ChildrenList.\r
+  //\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  NetListInsertTail (&MnpServiceData->ChildrenList, &Instance->InstEntry);\r
+  MnpServiceData->ChildrenNumber++;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+ErrorExit:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    if (Instance->Handle != NULL) {\r
+\r
+      gBS->UninstallMultipleProtocolInterfaces (\r
+            &gEfiManagedNetworkProtocolGuid,\r
+            &Instance->ManagedNetwork,\r
+            NULL\r
+            );\r
+    }\r
+\r
+    NetFreePool (Instance);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Destroys a child handle with a set of I/O services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Handle of the child to destroy.\r
+\r
+  @retval EFI_SUCCES             The I/O services were removed from the child\r
+                                 handle.\r
+  @retval EFI_UNSUPPORTED        The child handle does not support the I/O services\r
+                                  that are being removed.\r
+  @retval EFI_INVALID_PARAMETER  Child handle is not a valid EFI Handle.\r
+  @retval EFI_ACCESS_DENIED      The child handle could not be destroyed because\r
+                                 its  I/O services are being used.\r
+  @retval other                  The child handle was not destroyed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  MNP_SERVICE_DATA              *MnpServiceData;\r
+  EFI_MANAGED_NETWORK_PROTOCOL  *ManagedNetwork;\r
+  MNP_INSTANCE_DATA             *Instance;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Try to retrieve ManagedNetwork Protocol from ChildHandle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiManagedNetworkProtocolGuid,\r
+                  (VOID **) &ManagedNetwork,\r
+                  gMnpDriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (ManagedNetwork);\r
+\r
+  //\r
+  // MnpServiceBindingDestroyChild may be called twice: first called by\r
+  // MnpServiceBindingStop, second called by uninstalling the MNP protocol\r
+  // in this ChildHandle. Use destroyed to make sure the resource clean code\r
+  // will only excecute once.\r
+  //\r
+  if (Instance->Destroyed) {\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Instance->Destroyed = TRUE;\r
+\r
+  //\r
+  // Close the Simple Network protocol.\r
+  //\r
+  gBS->CloseProtocol (\r
+         MnpServiceData->ControllerHandle,\r
+         &gEfiSimpleNetworkProtocolGuid,\r
+         gMnpDriverBinding.DriverBindingHandle,\r
+         ChildHandle\r
+         );\r
+\r
+  //\r
+  // Uninstall the ManagedNetwork protocol.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiManagedNetworkProtocolGuid,\r
+                  &Instance->ManagedNetwork,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (\r
+      ("MnpServiceBindingDestroyChild: Failed to uninstall the ManagedNetwork protocol, %r.\n",\r
+      Status)\r
+      );\r
+\r
+    Instance->Destroyed = FALSE;\r
+    return Status;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // Reset the configuration.\r
+  //\r
+  ManagedNetwork->Configure (ManagedNetwork, NULL);\r
+\r
+  //\r
+  // Try to flush the RcvdPacketQueue.\r
+  //\r
+  MnpFlushRcvdDataQueue (Instance);\r
+\r
+  //\r
+  // Clean the RxTokenMap.\r
+  //\r
+  NetMapClean (&Instance->RxTokenMap);\r
+\r
+  //\r
+  // Remove this instance from the ChildrenList.\r
+  //\r
+  NetListRemoveEntry (&Instance->InstEntry);\r
+  MnpServiceData->ChildrenNumber--;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  NetFreePool (Instance);\r
+\r
+  return Status;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (MnpDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The entry point for Mnp driver which installs the driver binding and component name\r
+  protocol on its ImageHandle.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The image handle of the driver.\r
+  SystemTable - The system table.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - If the driver binding and component name protocols are successfully\r
+                installed, otherwise if failed.\r
+\r
+--*/\r
+{\r
+  return NetLibInstallAllDriverProtocols (\r
+          ImageHandle,\r
+          SystemTable,\r
+          &gMnpDriverBinding,\r
+          ImageHandle,\r
+          &gMnpComponentName,\r
+          NULL,\r
+          NULL\r
+          );\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h b/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h
new file mode 100644 (file)
index 0000000..48ad096
--- /dev/null
@@ -0,0 +1,136 @@
+/** @file
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  MnpDriver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _MNP_DRIVER_H_
+#define _MNP_DRIVER_H_
+#include <PiDxe.h>\r
+\r
+#include <Protocol/ManagedNetwork.h>\r
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/ServiceBinding.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/NetLib.h>
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include "MnpDebug.h"
+
+//
+// Required Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL  gMnpDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL  gMnpComponentName;
+
+#define MNP_SERVICE_DATA_SIGNATURE  EFI_SIGNATURE_32 ('M', 'n', 'p', 'S')
+
+typedef struct _MNP_SERVICE_DATA {
+  UINT32                        Signature;
+
+  EFI_HANDLE                    ControllerHandle;
+
+  EFI_SERVICE_BINDING_PROTOCOL  ServiceBinding;
+  EFI_SIMPLE_NETWORK_PROTOCOL   *Snp;
+
+  UINT32                        Mtu;
+
+  NET_LIST_ENTRY                ChildrenList;
+  UINTN                         ChildrenNumber;
+  UINTN                         ConfiguredChildrenNumber;
+
+  NET_LIST_ENTRY                GroupAddressList;
+  UINT32                        GroupAddressCount;
+
+  EFI_EVENT                     TxTimeoutEvent;
+
+  NET_BUF_QUEUE                 FreeNbufQue;
+  INTN                          NbufCnt;
+
+  EFI_EVENT                     PollTimer;
+  BOOLEAN                       EnableSystemPoll;
+
+  EFI_EVENT                     TimeoutCheckTimer;
+
+  UINT32                        UnicastCount;
+  UINT32                        BroadcastCount;
+  UINT32                        MulticastCount;
+  UINT32                        PromiscuousCount;
+
+  //
+  // The size of the data buffer in the MNP_PACKET_BUFFER used to
+  // store a packet.
+  //
+  UINT32                        BufferLength;
+  NET_BUF                       *RxNbufCache;
+  UINT8                         *TxBuf;
+} MNP_SERVICE_DATA;
+
+#define MNP_SERVICE_DATA_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  MNP_SERVICE_DATA, \
+  ServiceBinding, \
+  MNP_SERVICE_DATA_SIGNATURE \
+  )
+
+EFI_STATUS
+EFIAPI
+MnpDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+MnpDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+MnpDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+EFI_STATUS
+EFIAPI
+MnpServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  );
+
+EFI_STATUS
+EFIAPI
+MnpServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf b/MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
new file mode 100644 (file)
index 0000000..26512cd
--- /dev/null
@@ -0,0 +1,63 @@
+#/** @file\r
+# Component name for module Mnp\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. 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
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = MnpDxe\r
+  FILE_GUID                      = 025BBFC7-E6A9-4b8b-82AD-6815A1AEAF4A\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = MnpDriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  MnpDebug.h\r
+  MnpMain.c\r
+  MnpIo.c\r
+  MnpDriver.h\r
+  ComponentName.c\r
+  MnpDriver.c\r
+  MnpConfig.c\r
+  MnpImpl.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  NetLib\r
+\r
+\r
+[Protocols]\r
+  gEfiManagedNetworkServiceBindingProtocolGuid  # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSimpleNetworkProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiManagedNetworkProtocolGuid                # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.msa b/MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.msa
new file mode 100644 (file)
index 0000000..3ef22dd
--- /dev/null
@@ -0,0 +1,70 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>MnpDxe</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>025BBFC7-E6A9-4b8b-82AD-6815A1AEAF4A</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Mnp</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <License>All rights reserved. This program and the accompanying materials
+      are licensed and made available under the terms and conditions of the BSD License
+      which accompanies this distribution.  The full text of the license may be found at
+      http://opensource.org/licenses/bsd-license.php
+
+      THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+      WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>MnpDxe</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>MnpImpl.h</Filename>\r
+    <Filename>MnpConfig.c</Filename>\r
+    <Filename>MnpDriver.c</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>MnpDriver.h</Filename>\r
+    <Filename>MnpIo.c</Filename>\r
+    <Filename>MnpMain.c</Filename>\r
+    <Filename>MnpDebug.h</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiManagedNetworkProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiManagedNetworkServiceBindingProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>MnpDriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h b/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h
new file mode 100644 (file)
index 0000000..cdb081d
--- /dev/null
@@ -0,0 +1,274 @@
+/** @file
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  MnpImpl.h
+
+Abstract:
+
+
+**/
+
+#ifndef _MNP_IMPL_H_
+#define _MNP_IMPL_H_
+
+#include "MnpDriver.h"
+#include "MnpDebug.h"
+
+#define NET_ETHER_FCS_SIZE            4
+
+#define MNP_SYS_POLL_INTERVAL         (2 * TICKS_PER_MS)    // 2 milliseconds
+#define MNP_TIMEOUT_CHECK_INTERVAL    (50 * TICKS_PER_MS)   // 50 milliseconds
+#define MNP_TX_TIMEOUT_TIME           (500 * TICKS_PER_MS)  // 500 milliseconds
+#define MNP_INIT_NET_BUFFER_NUM       512
+#define MNP_NET_BUFFER_INCREASEMENT   64
+#define MNP_MAX_NET_BUFFER_NUM        65536
+
+#define MNP_MAX_RCVD_PACKET_QUE_SIZE  256
+
+#define MNP_RECEIVE_UNICAST           0x01
+#define MNP_RECEIVE_BROADCAST         0x02
+
+#define UNICAST_PACKET                MNP_RECEIVE_UNICAST
+#define BROADCAST_PACKET              MNP_RECEIVE_BROADCAST
+
+#define MNP_INSTANCE_DATA_SIGNATURE   EFI_SIGNATURE_32 ('M', 'n', 'p', 'I')
+
+#define MNP_INSTANCE_DATA_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  MNP_INSTANCE_DATA, \
+  ManagedNetwork, \
+  MNP_INSTANCE_DATA_SIGNATURE \
+  )
+
+typedef struct _MNP_INSTANCE_DATA {
+  UINT32                          Signature;
+
+  MNP_SERVICE_DATA                *MnpServiceData;
+
+  EFI_HANDLE                      Handle;
+
+  NET_LIST_ENTRY                  InstEntry;
+
+  EFI_MANAGED_NETWORK_PROTOCOL    ManagedNetwork;
+
+  BOOLEAN                         Configured;
+  BOOLEAN                         Destroyed;
+
+  NET_LIST_ENTRY                  GroupCtrlBlkList;
+
+  NET_MAP                         RxTokenMap;
+
+  NET_LIST_ENTRY                  RxDeliveredPacketQueue;
+  NET_LIST_ENTRY                  RcvdPacketQueue;
+  UINTN                           RcvdPacketQueueSize;
+
+  EFI_MANAGED_NETWORK_CONFIG_DATA ConfigData;
+
+  UINT8                           ReceiveFilter;
+} MNP_INSTANCE_DATA;
+
+typedef struct _MNP_GROUP_ADDRESS {
+  NET_LIST_ENTRY  AddrEntry;
+  EFI_MAC_ADDRESS Address;
+  INTN            RefCnt;
+} MNP_GROUP_ADDRESS;
+
+typedef struct _MNP_GROUP_CONTROL_BLOCK {
+  NET_LIST_ENTRY    CtrlBlkEntry;
+  MNP_GROUP_ADDRESS *GroupAddress;
+} MNP_GROUP_CONTROL_BLOCK;
+
+typedef struct _MNP_RXDATA_WRAP {
+  NET_LIST_ENTRY                    WrapEntry;
+  MNP_INSTANCE_DATA                 *Instance;
+  EFI_MANAGED_NETWORK_RECEIVE_DATA  RxData;
+  NET_BUF                           *Nbuf;
+  UINT64                            TimeoutTick;
+} MNP_RXDATA_WRAP;
+
+EFI_STATUS
+MnpInitializeServiceData (
+  IN MNP_SERVICE_DATA  *MnpServiceData,
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_HANDLE        ControllerHandle
+  );
+
+VOID
+MnpFlushServiceData (
+  MNP_SERVICE_DATA  *MnpServiceData
+  );
+
+VOID
+MnpInitializeInstanceData (
+  IN MNP_SERVICE_DATA   *MnpServiceData,
+  IN MNP_INSTANCE_DATA  *Instance
+  );
+
+EFI_STATUS
+MnpTokenExist (
+  IN NET_MAP       *Map,
+  IN NET_MAP_ITEM  *Item,
+  IN VOID          *Arg
+  );
+
+EFI_STATUS
+MnpCancelTokens (
+  IN NET_MAP       *Map,
+  IN NET_MAP_ITEM  *Item,
+  IN VOID          *Arg
+  );
+
+VOID
+MnpFlushRcvdDataQueue (
+  IN MNP_INSTANCE_DATA  *Instance
+  );
+
+EFI_STATUS
+MnpConfigureInstance (
+  IN MNP_INSTANCE_DATA                *Instance,
+  IN EFI_MANAGED_NETWORK_CONFIG_DATA  *ConfigData OPTIONAL
+  );
+
+EFI_STATUS
+MnpGroupOp (
+  IN MNP_INSTANCE_DATA        *Instance,
+  IN BOOLEAN                  JoinFlag,
+  IN EFI_MAC_ADDRESS          *MacAddr OPTIONAL,
+  IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk OPTIONAL
+  );
+
+BOOLEAN
+MnpIsValidTxToken (
+  IN MNP_INSTANCE_DATA                     *Instance,
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token
+  );
+
+VOID
+MnpBuildTxPacket (
+  IN  MNP_SERVICE_DATA                   *MnpServiceData,
+  IN  EFI_MANAGED_NETWORK_TRANSMIT_DATA  *TxData,
+  OUT UINT8                              **PktBuf,
+  OUT UINT32                             *PktLen
+  );
+
+EFI_STATUS
+MnpSyncSendPacket (
+  IN MNP_SERVICE_DATA                      *MnpServiceData,
+  IN UINT8                                 *Packet,
+  IN UINT32                                Length,
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token
+  );
+
+EFI_STATUS
+MnpInstanceDeliverPacket (
+  IN MNP_INSTANCE_DATA  *Instance
+  );
+
+VOID
+EFIAPI
+MnpRecycleRxData (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+EFI_STATUS
+MnpReceivePacket (
+  IN MNP_SERVICE_DATA  *MnpServiceData
+  );
+
+NET_BUF *
+MnpAllocNbuf (
+  IN MNP_SERVICE_DATA  *MnpServiceData
+  );
+
+VOID
+MnpFreeNbuf (
+  IN MNP_SERVICE_DATA  *MnpServiceData,
+  IN NET_BUF           *Nbuf
+  );
+
+VOID
+EFIAPI
+MnpCheckPacketTimeout (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+VOID
+EFIAPI
+MnpSystemPoll (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+EFI_STATUS
+EFIAPI
+MnpGetModeData (
+  IN  EFI_MANAGED_NETWORK_PROTOCOL     *This,
+  OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData OPTIONAL,
+  OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+MnpConfigure (
+  IN EFI_MANAGED_NETWORK_PROTOCOL     *This,
+  IN EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+MnpMcastIpToMac (
+  IN  EFI_MANAGED_NETWORK_PROTOCOL  *This,
+  IN  BOOLEAN                       Ipv6Flag,
+  IN  EFI_IP_ADDRESS                *IpAddress,
+  OUT EFI_MAC_ADDRESS               *MacAddress
+  );
+
+EFI_STATUS
+EFIAPI
+MnpGroups (
+  IN EFI_MANAGED_NETWORK_PROTOCOL  *This,
+  IN BOOLEAN                       JoinFlag,
+  IN EFI_MAC_ADDRESS               *MacAddress OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+MnpTransmit (
+  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token
+  );
+
+EFI_STATUS
+EFIAPI
+MnpCancel (
+  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+MnpReceive (
+  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token
+  );
+
+EFI_STATUS
+EFIAPI
+MnpPoll (
+  IN EFI_MANAGED_NETWORK_PROTOCOL  *This
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
new file mode 100644 (file)
index 0000000..cde2359
--- /dev/null
@@ -0,0 +1,1087 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  MnpIo.c\r
+\r
+Abstract:\r
+\r
+  Implementation of Managed Network Protocol I/O functions.\r
+\r
+\r
+**/\r
+\r
+#include <Library/NetLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include "MnpImpl.h"\r
+\r
+\r
+/**\r
+  Validates the Mnp transmit token.\r
+\r
+  @param  Instance              Pointer to the Mnp instance context data.\r
+  @param  Token                 Pointer to the transmit token to check.\r
+\r
+  @return The Token is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+MnpIsValidTxToken (\r
+  IN MNP_INSTANCE_DATA                     *Instance,\r
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  MNP_SERVICE_DATA                  *MnpServiceData;\r
+  EFI_SIMPLE_NETWORK_MODE           *SnpMode;\r
+  EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
+  UINT32                            Index;\r
+  UINT32                            TotalLength;\r
+  EFI_MANAGED_NETWORK_FRAGMENT_DATA *FragmentTable;\r
+\r
+  MnpServiceData = Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  SnpMode = MnpServiceData->Snp->Mode;\r
+  TxData  = Token->Packet.TxData;\r
+\r
+  if ((Token->Event == NULL) || (TxData == NULL) || (TxData->FragmentCount == 0)) {\r
+    //\r
+    // The token is invalid if the Event is NULL, or the TxData is NULL, or\r
+    // the fragment count is zero.\r
+    //\r
+    MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid Token.\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  if ((TxData->DestinationAddress != NULL) && (TxData->HeaderLength != 0)) {\r
+    //\r
+    // The token is invalid if the HeaderLength isn't zero while the DestinationAddress\r
+    // is NULL (The destination address is already put into the packet).\r
+    //\r
+    MNP_DEBUG_WARN (("MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  TotalLength   = 0;\r
+  FragmentTable = TxData->FragmentTable;\r
+  for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+\r
+    if ((FragmentTable[Index].FragmentLength == 0) || (FragmentTable[Index].FragmentBuffer == NULL)) {\r
+      //\r
+      // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.\r
+      //\r
+      MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));\r
+      return FALSE;\r
+    }\r
+\r
+    TotalLength += FragmentTable[Index].FragmentLength;\r
+  }\r
+\r
+  if ((TxData->DestinationAddress == NULL) && (FragmentTable[0].FragmentLength < TxData->HeaderLength)) {\r
+    //\r
+    // Media header is split between fragments.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if (TotalLength != (TxData->DataLength + TxData->HeaderLength)) {\r
+    //\r
+    // The length calculated from the fragment information doesn't equal to the\r
+    // sum of the DataLength and the HeaderLength.\r
+    //\r
+    MNP_DEBUG_WARN (("MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  if (TxData->DataLength > MnpServiceData->Mtu) {\r
+    //\r
+    // The total length is larger than the MTU.\r
+    //\r
+    MNP_DEBUG_WARN (("MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Build the packet to transmit from the TxData passed in.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  TxData                Pointer to the transmit data containing the\r
+                                information to build the packet.\r
+  @param  PktBuf                Pointer to record the address of the packet.\r
+  @param  PktLen                Pointer to a UINT32 variable used to record the\r
+                                packet's length.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+MnpBuildTxPacket (\r
+  IN  MNP_SERVICE_DATA                   *MnpServiceData,\r
+  IN  EFI_MANAGED_NETWORK_TRANSMIT_DATA  *TxData,\r
+  OUT UINT8                              **PktBuf,\r
+  OUT UINT32                             *PktLen\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+  UINT8                   *DstPos;\r
+  UINT16                  Index;\r
+\r
+  if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) {\r
+    //\r
+    // Media header is in FragmentTable and there is only one fragment,\r
+    // use fragment buffer directly.\r
+    //\r
+    *PktBuf = TxData->FragmentTable[0].FragmentBuffer;\r
+    *PktLen = TxData->FragmentTable[0].FragmentLength;\r
+  } else {\r
+    //\r
+    // Either media header isn't in FragmentTable or there is more than\r
+    // one fragment, copy the data into the packet buffer. Reserve the\r
+    // media header space if necessary.\r
+    //\r
+    SnpMode = MnpServiceData->Snp->Mode;\r
+    DstPos  = MnpServiceData->TxBuf;\r
+\r
+    *PktLen = 0;\r
+    if (TxData->DestinationAddress != NULL) {\r
+      //\r
+      // If dest address is not NULL, move DstPos to reserve space for the\r
+      // media header. Add the media header length to buflen.\r
+      //\r
+      DstPos += SnpMode->MediaHeaderSize;\r
+      *PktLen += SnpMode->MediaHeaderSize;\r
+    }\r
+\r
+    for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+      //\r
+      // Copy the data.\r
+      //\r
+      NetCopyMem (\r
+        DstPos,\r
+        TxData->FragmentTable[Index].FragmentBuffer,\r
+        TxData->FragmentTable[Index].FragmentLength\r
+        );\r
+      DstPos += TxData->FragmentTable[Index].FragmentLength;\r
+    }\r
+\r
+    //\r
+    // Set the buffer pointer and the buffer length.\r
+    //\r
+    *PktBuf = MnpServiceData->TxBuf;\r
+    *PktLen += TxData->DataLength + TxData->HeaderLength;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Synchronously send out the packet.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  Packet                Pointer to the pakcet buffer.\r
+  @param  Length                The length of the packet.\r
+  @param  Token                 Pointer to the token the packet generated from.\r
+\r
+  @retval EFI_SUCCESS           The packet is sent out.\r
+  @retval EFI_TIMEOUT           Time out occurs, the packet isn't sent.\r
+  @retval EFI_DEVICE_ERROR      An unexpected network error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpSyncSendPacket (\r
+  IN MNP_SERVICE_DATA                      *MnpServiceData,\r
+  IN UINT8                                 *Packet,\r
+  IN UINT32                                Length,\r
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL       *Snp;\r
+  EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
+  UINT32                            HeaderSize;\r
+  UINT8                             *TxBuf;\r
+\r
+  Snp         = MnpServiceData->Snp;\r
+  TxData      = Token->Packet.TxData;\r
+\r
+  HeaderSize  = Snp->Mode->MediaHeaderSize - TxData->HeaderLength;\r
+\r
+  //\r
+  // Start the timeout event.\r
+  //\r
+  Status = gBS->SetTimer (\r
+                  MnpServiceData->TxTimeoutEvent,\r
+                  TimerRelative,\r
+                  MNP_TX_TIMEOUT_TIME\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    goto SIGNAL_TOKEN;\r
+  }\r
+\r
+  for (;;) {\r
+    //\r
+    // Transmit the packet through SNP.\r
+    //\r
+    Status = Snp->Transmit (\r
+                    Snp,\r
+                    HeaderSize,\r
+                    Length,\r
+                    Packet,\r
+                    TxData->SourceAddress,\r
+                    TxData->DestinationAddress,\r
+                    &TxData->ProtocolType\r
+                    );\r
+    if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
+\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
+    // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.\r
+    // Both need to sync SNP.\r
+    //\r
+    TxBuf = NULL;\r
+    do {\r
+      //\r
+      // Get the recycled transmit buffer status.\r
+      //\r
+      Snp->GetStatus (Snp, NULL, &TxBuf);\r
+\r
+      if (!EFI_ERROR (gBS->CheckEvent (MnpServiceData->TxTimeoutEvent))) {\r
+\r
+        Status = EFI_TIMEOUT;\r
+        break;\r
+      }\r
+    } while (TxBuf == NULL);\r
+\r
+    if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
+\r
+      break;\r
+    } else {\r
+      //\r
+      // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.\r
+      //\r
+      gBS->SetTimer (\r
+            MnpServiceData->TxTimeoutEvent,\r
+            TimerRelative,\r
+            MNP_TX_TIMEOUT_TIME\r
+            );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Cancel the timer event.\r
+  //\r
+  gBS->SetTimer (MnpServiceData->TxTimeoutEvent, TimerCancel, 0);\r
+\r
+SIGNAL_TOKEN:\r
+\r
+  Token->Status = Status;\r
+  gBS->SignalEvent (Token->Event);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Try to deliver the received packet to the instance.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+\r
+  @retval EFI_SUCCESS           The received packet is delivered, or there is no\r
+                                packet to deliver, or there is no available receive\r
+                                token.\r
+  @retval EFI_OUT_OF_RESOURCES  The deliver fails due to lack of memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpInstanceDeliverPacket (\r
+  IN MNP_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  MNP_SERVICE_DATA                      *MnpServiceData;\r
+  MNP_RXDATA_WRAP                       *RxDataWrap;\r
+  NET_BUF                               *DupNbuf;\r
+  EFI_MANAGED_NETWORK_RECEIVE_DATA      *RxData;\r
+  EFI_SIMPLE_NETWORK_MODE               *SnpMode;\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *RxToken;\r
+\r
+  MnpServiceData = Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  if (NetMapIsEmpty (&Instance->RxTokenMap) || NetListIsEmpty (&Instance->RcvdPacketQueue)) {\r
+    //\r
+    // No pending received data or no available receive token, return.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ASSERT (Instance->RcvdPacketQueueSize != 0);\r
+\r
+  RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
+  if (RxDataWrap->Nbuf->RefCnt > 2) {\r
+    //\r
+    // There are other instances share this Nbuf, duplicate to get a\r
+    // copy to allow the instance to do R/W operations.\r
+    //\r
+    DupNbuf = MnpAllocNbuf (MnpServiceData);\r
+    if (DupNbuf == NULL) {\r
+      MNP_DEBUG_WARN (("MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));\r
+\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Duplicate the net buffer.\r
+    //\r
+    NetbufDuplicate (RxDataWrap->Nbuf, DupNbuf, 0);\r
+    MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);\r
+    RxDataWrap->Nbuf = DupNbuf;\r
+  }\r
+\r
+  //\r
+  // All resources are OK, remove the packet from the queue.\r
+  //\r
+  NetListRemoveHead (&Instance->RcvdPacketQueue);\r
+  Instance->RcvdPacketQueueSize--;\r
+\r
+  RxData  = &RxDataWrap->RxData;\r
+  SnpMode = MnpServiceData->Snp->Mode;\r
+\r
+  //\r
+  // Set all the buffer pointers.\r
+  //\r
+  RxData->MediaHeader         = NetbufGetByte (RxDataWrap->Nbuf, 0, NULL);\r
+  RxData->DestinationAddress  = RxData->MediaHeader;\r
+  RxData->SourceAddress       = (UINT8 *) RxData->MediaHeader + SnpMode->HwAddressSize;\r
+  RxData->PacketData          = (UINT8 *) RxData->MediaHeader + SnpMode->MediaHeaderSize;\r
+\r
+  //\r
+  // Insert this RxDataWrap into the delivered queue.\r
+  //\r
+  NetListInsertTail (&Instance->RxDeliveredPacketQueue, &RxDataWrap->WrapEntry);\r
+\r
+  //\r
+  // Get the receive token from the RxTokenMap.\r
+  //\r
+  RxToken = NetMapRemoveHead (&Instance->RxTokenMap, NULL);\r
+\r
+  //\r
+  // Signal this token's event.\r
+  //\r
+  RxToken->Packet.RxData  = &RxDataWrap->RxData;\r
+  RxToken->Status         = EFI_SUCCESS;\r
+  gBS->SignalEvent (RxToken->Event);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Deliver the received packet for the instances belonging to the MnpServiceData.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpDeliverPacket (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  )\r
+{\r
+  NET_LIST_ENTRY    *Entry;\r
+  MNP_INSTANCE_DATA *Instance;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
+    Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
+    NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+    //\r
+    // Try to deliver packet for this instance.\r
+    //\r
+    MnpInstanceDeliverPacket (Instance);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Recycle the RxData and other resources used to hold and deliver the received\r
+  packet.\r
+\r
+  @param  Event                 The event this notify function registered to.\r
+  @param  Context               Pointer to the context data registerd to the Event.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MnpRecycleRxData (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  MNP_RXDATA_WRAP   *RxDataWrap;\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+\r
+  ASSERT (Context != NULL);\r
+\r
+  RxDataWrap = (MNP_RXDATA_WRAP *) Context;\r
+  NET_CHECK_SIGNATURE (RxDataWrap->Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  ASSERT (RxDataWrap->Nbuf != NULL);\r
+\r
+  MnpServiceData = RxDataWrap->Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  //\r
+  // Free this Nbuf.\r
+  //\r
+  MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);\r
+  RxDataWrap->Nbuf = NULL;\r
+\r
+  //\r
+  // Close the recycle event.\r
+  //\r
+  gBS->CloseEvent (RxDataWrap->RxData.RecycleEvent);\r
+\r
+  //\r
+  // Remove this Wrap entry from the list.\r
+  //\r
+  NetListRemoveEntry (&RxDataWrap->WrapEntry);\r
+\r
+  NetFreePool (RxDataWrap);\r
+}\r
+\r
+\r
+/**\r
+  Queue the received packet into instance's receive queue.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+  @param  RxDataWrap            Pointer to the Wrap structure containing the\r
+                                received data and other information.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpQueueRcvdPacket (\r
+  IN MNP_INSTANCE_DATA  *Instance,\r
+  IN MNP_RXDATA_WRAP    *RxDataWrap\r
+  )\r
+{\r
+  MNP_RXDATA_WRAP *OldRxDataWrap;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  //\r
+  // Check the queue size. If it exceeds the limit, drop one packet\r
+  // from the head.\r
+  //\r
+  if (Instance->RcvdPacketQueueSize == MNP_MAX_RCVD_PACKET_QUE_SIZE) {\r
+\r
+    MNP_DEBUG_WARN (("MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));\r
+\r
+    //\r
+    // Get the oldest packet.\r
+    //\r
+    OldRxDataWrap = NET_LIST_HEAD (\r
+                      &Instance->RcvdPacketQueue,\r
+                      MNP_RXDATA_WRAP,\r
+                      WrapEntry\r
+                      );\r
+\r
+    //\r
+    // Recycle this OldRxDataWrap, this entry will be removed by the callee.\r
+    //\r
+    MnpRecycleRxData (NULL, (VOID *) OldRxDataWrap);\r
+    Instance->RcvdPacketQueueSize--;\r
+  }\r
+\r
+  //\r
+  // Update the timeout tick using the configured parameter.\r
+  //\r
+  RxDataWrap->TimeoutTick = Instance->ConfigData.ReceivedQueueTimeoutValue;\r
+\r
+  //\r
+  // Insert this Wrap into the instance queue.\r
+  //\r
+  NetListInsertTail (&Instance->RcvdPacketQueue, &RxDataWrap->WrapEntry);\r
+  Instance->RcvdPacketQueueSize++;\r
+}\r
+\r
+\r
+/**\r
+  Match the received packet with the instance receive filters.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+  @param  RxData                Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
+  @param  GroupAddress          Pointer to the GroupAddress, the GroupAddress is\r
+                                non-NULL and it contains the destination multicast\r
+                                mac address of the received packet if the packet\r
+                                destinated to a multicast mac address.\r
+  @param  PktAttr               The received packets attribute.\r
+\r
+  @return The received packet matches the instance's receive filters or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+MnpMatchPacket (\r
+  IN MNP_INSTANCE_DATA                 *Instance,\r
+  IN EFI_MANAGED_NETWORK_RECEIVE_DATA  *RxData,\r
+  IN MNP_GROUP_ADDRESS                 *GroupAddress OPTIONAL,\r
+  IN UINT8                             PktAttr\r
+  )\r
+{\r
+  EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;\r
+  NET_LIST_ENTRY                  *Entry;\r
+  MNP_GROUP_CONTROL_BLOCK         *GroupCtrlBlk;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  ConfigData = &Instance->ConfigData;\r
+\r
+  if (ConfigData->EnablePromiscuousReceive) {\r
+    //\r
+    // Always match if this instance is configured to be promiscuous.\r
+    //\r
+    return TRUE;\r
+  }\r
+  //\r
+  // Check the protocol type.\r
+  //\r
+  if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // The protocol type is matched, check receive filter, include unicast and broadcast.\r
+  //\r
+  if ((Instance->ReceiveFilter & PktAttr) != 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // Check multicast addresses.\r
+  //\r
+  if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {\r
+\r
+    ASSERT (GroupAddress != NULL);\r
+\r
+    NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {\r
+\r
+      GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);\r
+      if (GroupCtrlBlk->GroupAddress == GroupAddress) {\r
+        //\r
+        // The instance is configured to receiveing packets destinated to this\r
+        // multicast address.\r
+        //\r
+        return TRUE;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // No match.\r
+  //\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Analyse the received packets.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  Nbuf                  Pointer to the net buffer holding the received\r
+                                packet.\r
+  @param  RxData                Pointer to the buffer used to save the analysed\r
+                                result in EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
+  @param  GroupAddress          Pointer to pointer to a MNP_GROUP_ADDRESS used to\r
+                                pass out the address of the multicast address the\r
+                                received packet destinated to.\r
+  @param  PktAttr               Pointer to the buffer used to save the analysed\r
+                                packet attribute.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpAnalysePacket (\r
+  IN  MNP_SERVICE_DATA                  *MnpServiceData,\r
+  IN  NET_BUF                           *Nbuf,\r
+  IN  EFI_MANAGED_NETWORK_RECEIVE_DATA  *RxData,\r
+  OUT MNP_GROUP_ADDRESS                 **GroupAddress,\r
+  OUT UINT8                             *PktAttr\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+  UINT8                   *BufPtr;\r
+  NET_LIST_ENTRY          *Entry;\r
+\r
+  SnpMode = MnpServiceData->Snp->Mode;\r
+\r
+  //\r
+  // Get the packet buffer.\r
+  //\r
+  BufPtr = NetbufGetByte (Nbuf, 0, NULL);\r
+  ASSERT (BufPtr != NULL);\r
+\r
+  //\r
+  // Set the initial values.\r
+  //\r
+  RxData->BroadcastFlag   = FALSE;\r
+  RxData->MulticastFlag   = FALSE;\r
+  RxData->PromiscuousFlag = FALSE;\r
+  *PktAttr                = UNICAST_PACKET;\r
+\r
+  if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {\r
+    //\r
+    // This packet isn't destinated to our current mac address, it't not unicast.\r
+    //\r
+    *PktAttr = 0;\r
+\r
+    if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {\r
+      //\r
+      // It's broadcast.\r
+      //\r
+      RxData->BroadcastFlag = TRUE;\r
+      *PktAttr              = BROADCAST_PACKET;\r
+    } else if ((*BufPtr & 0x01) == 0x1) {\r
+      //\r
+      // It's multicast, try to match the multicast filters.\r
+      //\r
+      NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
+\r
+        *GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
+        if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {\r
+          RxData->MulticastFlag = TRUE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (!RxData->MulticastFlag) {\r
+        //\r
+        // No match, set GroupAddress to NULL. This multicast packet must\r
+        // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.\r
+        //\r
+        *GroupAddress           = NULL;\r
+        RxData->PromiscuousFlag = TRUE;\r
+\r
+        if (MnpServiceData->PromiscuousCount == 0) {\r
+          //\r
+          // Skip the below code, there is no receiver of this packet.\r
+          //\r
+          return ;\r
+        }\r
+      }\r
+    } else {\r
+      RxData->PromiscuousFlag = TRUE;\r
+    }\r
+  }\r
+\r
+  NetZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));\r
+\r
+  //\r
+  // Fill the common parts of RxData.\r
+  //\r
+  RxData->PacketLength  = Nbuf->TotalSize;\r
+  RxData->HeaderLength  = SnpMode->MediaHeaderSize;\r
+  RxData->AddressLength = SnpMode->HwAddressSize;\r
+  RxData->DataLength    = RxData->PacketLength - RxData->HeaderLength;\r
+  RxData->ProtocolType  = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));\r
+}\r
+\r
+\r
+/**\r
+  Wrap the RxData.\r
+\r
+  @param  Instance              Pointer to the mnp instance context data.\r
+  @param  RxData                Pointer to the receive data to wrap.\r
+\r
+  @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.\r
+\r
+**/\r
+STATIC\r
+MNP_RXDATA_WRAP *\r
+MnpWrapRxData (\r
+  IN MNP_INSTANCE_DATA                 *Instance,\r
+  IN EFI_MANAGED_NETWORK_RECEIVE_DATA  *RxData\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  MNP_RXDATA_WRAP *RxDataWrap;\r
+\r
+  //\r
+  // Allocate memory.\r
+  //\r
+  RxDataWrap = NetAllocatePool (sizeof (MNP_RXDATA_WRAP));\r
+  if (RxDataWrap == NULL) {\r
+    MNP_DEBUG_ERROR (("MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));\r
+    return NULL;\r
+  }\r
+\r
+  RxDataWrap->Instance = Instance;\r
+\r
+  //\r
+  // Fill the RxData in RxDataWrap,\r
+  //\r
+  RxDataWrap->RxData = *RxData;\r
+\r
+  //\r
+  // Create the recycle event.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  NET_TPL_RECYCLE,\r
+                  MnpRecycleRxData,\r
+                  RxDataWrap,\r
+                  &RxDataWrap->RxData.RecycleEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    MNP_DEBUG_ERROR (("MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));\r
+    NetFreePool (RxDataWrap);\r
+    return NULL;\r
+  }\r
+\r
+  return RxDataWrap;\r
+}\r
+\r
+\r
+/**\r
+  Enqueue the received the packets to the instances belonging to the\r
+  MnpServiceData.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+  @param  Nbuf                  Pointer to the net buffer representing the received\r
+                                packet.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpEnqueuePacket (\r
+  IN MNP_SERVICE_DATA   *MnpServiceData,\r
+  IN NET_BUF            *Nbuf\r
+  )\r
+{\r
+  NET_LIST_ENTRY                    *Entry;\r
+  MNP_INSTANCE_DATA                 *Instance;\r
+  EFI_MANAGED_NETWORK_RECEIVE_DATA  RxData;\r
+  UINT8                             PktAttr;\r
+  MNP_GROUP_ADDRESS                 *GroupAddress;\r
+  MNP_RXDATA_WRAP                   *RxDataWrap;\r
+\r
+  //\r
+  // First, analyse the packet header.\r
+  //\r
+  MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);\r
+\r
+  if (RxData.PromiscuousFlag && (MnpServiceData->PromiscuousCount == 0)) {\r
+    //\r
+    // No receivers, no more action need.\r
+    //\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Iterate the children to find match.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
+\r
+    Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
+    NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+    if (!Instance->Configured) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check the packet against the instance receive filters.\r
+    //\r
+    if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {\r
+\r
+      //\r
+      // Wrap the RxData.\r
+      //\r
+      RxDataWrap = MnpWrapRxData (Instance, &RxData);\r
+      if (RxDataWrap == NULL) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Associate RxDataWrap with Nbuf and increase the RefCnt.\r
+      //\r
+      RxDataWrap->Nbuf = Nbuf;\r
+      NET_GET_REF (RxDataWrap->Nbuf);\r
+\r
+      //\r
+      // Queue the packet into the instance queue.\r
+      //\r
+      MnpQueueRcvdPacket (Instance, RxDataWrap);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Try to receive a packet and deliver it.\r
+\r
+  @param  MnpServiceData        Pointer to the mnp service context data.\r
+\r
+  @retval EFI_SUCCESS           add return value to function comment\r
+  @retval EFI_NOT_STARTED       The simple network protocol is not started.\r
+  @retval EFI_NOT_READY         No packet received.\r
+  @retval EFI_DEVICE_ERROR      An unexpected error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpReceivePacket (\r
+  IN MNP_SERVICE_DATA  *MnpServiceData\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  NET_BUF                     *Nbuf;\r
+  UINT8                       *BufPtr;\r
+  UINTN                       BufLen;\r
+  UINTN                       HeaderSize;\r
+  UINT32                      Trimmed;\r
+\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  Snp = MnpServiceData->Snp;\r
+  if (Snp->Mode->State != EfiSimpleNetworkInitialized) {\r
+    //\r
+    // The simple network protocol is not started.\r
+    //\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (NetListIsEmpty (&MnpServiceData->ChildrenList)) {\r
+    //\r
+    // There is no child, no need to receive packets.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (MnpServiceData->RxNbufCache == NULL) {\r
+    //\r
+    // Try to get a new buffer as there may be buffers recycled.\r
+    //\r
+    MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);\r
+\r
+    if (MnpServiceData->RxNbufCache == NULL) {\r
+      //\r
+      // No availabe buffer in the buffer pool.\r
+      //\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    NetbufAllocSpace (\r
+      MnpServiceData->RxNbufCache,\r
+      MnpServiceData->BufferLength,\r
+      NET_BUF_TAIL\r
+      );\r
+  }\r
+\r
+  Nbuf    = MnpServiceData->RxNbufCache;\r
+  BufLen  = Nbuf->TotalSize;\r
+  BufPtr  = NetbufGetByte (Nbuf, 0, NULL);\r
+  ASSERT (BufPtr != NULL);\r
+\r
+  //\r
+  // Receive packet through Snp.\r
+  //\r
+  Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    DEBUG_CODE (\r
+      if (Status != EFI_NOT_READY) {\r
+      MNP_DEBUG_ERROR (("MnpReceivePacket: Snp->Receive() = %r.\n", Status));\r
+    }\r
+    );\r
+\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Sanity check.\r
+  //\r
+  if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {\r
+\r
+    MNP_DEBUG_WARN (\r
+      ("MnpReceivePacket: Size error, HL:TL = %d:%d.\n",\r
+      HeaderSize,\r
+      BufLen)\r
+      );\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Trimmed = 0;\r
+  if (Nbuf->TotalSize != BufLen) {\r
+    //\r
+    // Trim the packet from tail.\r
+    //\r
+    Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);\r
+    ASSERT (Nbuf->TotalSize == BufLen);\r
+  }\r
+\r
+  //\r
+  // Enqueue the packet to the matched instances.\r
+  //\r
+  MnpEnqueuePacket (MnpServiceData, Nbuf);\r
+\r
+  if (Nbuf->RefCnt > 2) {\r
+    //\r
+    // RefCnt > 2 indicates there is at least one receiver of this packet.\r
+    // Free the current RxNbufCache and allocate a new one.\r
+    //\r
+    MnpFreeNbuf (MnpServiceData, Nbuf);\r
+\r
+    Nbuf                        = MnpAllocNbuf (MnpServiceData);\r
+    MnpServiceData->RxNbufCache = Nbuf;\r
+    if (Nbuf == NULL) {\r
+      MNP_DEBUG_ERROR (("MnpReceivePacket: Alloc packet for receiving cache failed.\n"));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    NetbufAllocSpace (Nbuf, MnpServiceData->BufferLength, NET_BUF_TAIL);\r
+  } else {\r
+    //\r
+    // No receiver for this packet.\r
+    //\r
+    NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);\r
+    goto EXIT;\r
+  }\r
+  //\r
+  // Deliver the queued packets.\r
+  //\r
+  MnpDeliverPacket (MnpServiceData);\r
+\r
+EXIT:\r
+\r
+  ASSERT (Nbuf->TotalSize == MnpServiceData->BufferLength);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Remove the received packets if timeout occurs.\r
+\r
+  @param  Event                 The event this notify function registered to.\r
+  @param  Context               Pointer to the context data registered to the\r
+                                event.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MnpCheckPacketTimeout (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+  NET_LIST_ENTRY    *Entry;\r
+  NET_LIST_ENTRY    *RxEntry;\r
+  NET_LIST_ENTRY    *NextEntry;\r
+  MNP_INSTANCE_DATA *Instance;\r
+  MNP_RXDATA_WRAP   *RxDataWrap;\r
+  EFI_TPL           OldTpl;\r
+\r
+  MnpServiceData = (MNP_SERVICE_DATA *) Context;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
+\r
+    Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
+    NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+    if (!Instance->Configured || (Instance->ConfigData.ReceivedQueueTimeoutValue == 0)) {\r
+      //\r
+      // This instance is not configured or there is no receive time out,\r
+      // just skip to the next instance.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+    NET_LIST_FOR_EACH_SAFE (RxEntry, NextEntry, &Instance->RcvdPacketQueue) {\r
+\r
+      RxDataWrap = NET_LIST_USER_STRUCT (RxEntry, MNP_RXDATA_WRAP, WrapEntry);\r
+\r
+      if (RxDataWrap->TimeoutTick >= MNP_TIMEOUT_CHECK_INTERVAL) {\r
+\r
+        RxDataWrap->TimeoutTick -= MNP_TIMEOUT_CHECK_INTERVAL;\r
+      } else {\r
+        //\r
+        // Drop the timeout packet.\r
+        //\r
+        MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Received packet timeout.\n"));\r
+        MnpRecycleRxData (NULL, RxDataWrap);\r
+        Instance->RcvdPacketQueueSize--;\r
+      }\r
+    }\r
+\r
+    NET_RESTORE_TPL (OldTpl);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Poll to receive the packets from Snp. This function is either called by upperlayer\r
+  protocols/applications or the system poll timer notify mechanism.\r
+\r
+  @param  Event                 The event this notify function registered to.\r
+  @param  Context               Pointer to the context data registered to the\r
+                                event.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MnpSystemPoll (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+\r
+  MnpServiceData = (MNP_SERVICE_DATA *) Context;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  //\r
+  // Try to receive packets from Snp.\r
+  //\r
+  MnpReceivePacket (MnpServiceData);\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c
new file mode 100644 (file)
index 0000000..02c0065
--- /dev/null
@@ -0,0 +1,655 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  MnpMain.c\r
+\r
+Abstract:\r
+\r
+  Implementation of Managed Network Protocol public services.\r
+\r
+\r
+**/\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+#include "MnpImpl.h"\r
+\r
+\r
+/**\r
+  Get configuration data of this instance.\r
+\r
+  @param  This                   Pointer to the Managed Network Protocol.\r
+  @param  MnpConfigData          Pointer to strorage for MNP operational\r
+                                 parameters.\r
+  @param  SnpModeData            Pointer to strorage for SNP operational\r
+                                 parameters.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured The default values are returned in\r
+                                 MnpConfigData if it is not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpGetModeData (\r
+  IN  EFI_MANAGED_NETWORK_PROTOCOL     *This,\r
+  OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData OPTIONAL,\r
+  OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData OPTIONAL\r
+  )\r
+{\r
+  MNP_INSTANCE_DATA           *Instance;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_TPL                     OldTpl;\r
+  EFI_STATUS                  Status;\r
+\r
+  if (This == NULL) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (MnpConfigData != NULL) {\r
+    //\r
+    // Copy the instance configuration data.\r
+    //\r
+    *MnpConfigData = Instance->ConfigData;\r
+  }\r
+\r
+  if (SnpModeData != NULL) {\r
+    //\r
+    // Copy the underlayer Snp mode data.\r
+    //\r
+    Snp           = Instance->MnpServiceData->Snp;\r
+    *SnpModeData  = *(Snp->Mode);\r
+  }\r
+\r
+  if (!Instance->Configured) {\r
+    Status = EFI_NOT_STARTED;\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set or clear the operational parameters for the MNP child driver.\r
+\r
+  @param  This                   Pointer to the Managed Network Protocol.\r
+  @param  MnpConfigData          Pointer to the configuration data that will be\r
+                                 assigned to the MNP child driver instance. If\r
+                                 NULL, the MNP child driver instance is reset to\r
+                                 startup defaults and all pending transmit and\r
+                                 receive requests are flushed.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameter is invalid.\r
+  @retval EFI_OUT_OF_RESOURCES   Required system resources (usually memory) could\r
+                                 not be allocated.\r
+  @retval EFI_UNSUPPORTED        EnableReceiveTimestamps is TRUE, this\r
+                                 implementation doesn't support it.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval Other                  The MNP child driver instance has been reset to\r
+                                 startup defaults.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpConfigure (\r
+  IN EFI_MANAGED_NETWORK_PROTOCOL     *This,\r
+  IN EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData OPTIONAL\r
+  )\r
+{\r
+  MNP_INSTANCE_DATA  *Instance;\r
+  EFI_TPL            OldTpl;\r
+  EFI_STATUS         Status;\r
+\r
+  if ((This == NULL) ||\r
+    ((MnpConfigData != NULL) &&\r
+    (MnpConfigData->ProtocolTypeFilter > 0) &&\r
+    (MnpConfigData->ProtocolTypeFilter <= 1500))) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if ((MnpConfigData == NULL) && (!Instance->Configured)) {\r
+    //\r
+    // If the instance is not configured and a reset is requested, just return.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Configure the instance.\r
+  //\r
+  Status = MnpConfigureInstance (Instance, MnpConfigData);\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Translate a multicast IP address to a multicast hardware (MAC) address.\r
+\r
+  @param  This                   Pointer to the Managed Network Protocol.\r
+  @param  Ipv6Flag               Set to TRUE if IpAddress is an IPv6 multicast\r
+                                 address. Set to FALSE if IpAddress is an IPv4\r
+                                 multicast address.\r
+  @param  IpAddress              Pointer to the multicast IP address to convert.\r
+  @param  MacAddress             Pointer to the resulting multicast MAC address.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameter is invalid.\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured.\r
+  @retval EFI_UNSUPPORTED        Ipv6Flag is TRUE, this implementation doesn't\r
+                                 supported it.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval Other                  The address could not be converted.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpMcastIpToMac (\r
+  IN  EFI_MANAGED_NETWORK_PROTOCOL  *This,\r
+  IN  BOOLEAN                       Ipv6Flag,\r
+  IN  EFI_IP_ADDRESS                *IpAddress,\r
+  OUT EFI_MAC_ADDRESS               *MacAddress\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  MNP_INSTANCE_DATA           *Instance;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_TPL                     OldTpl;\r
+\r
+  if ((This == NULL) || (IpAddress == NULL) || (MacAddress == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Ipv6Flag) {\r
+    //\r
+    // Currently IPv6 isn't supported.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (!IP4_IS_MULTICAST (EFI_NTOHL (*IpAddress))) {\r
+    //\r
+    // The IPv4 address passed in is not a multicast address.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (!Instance->Configured) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Snp = Instance->MnpServiceData->Snp;\r
+  ASSERT (Snp != NULL);\r
+\r
+  if (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) {\r
+    //\r
+    // Translate the IPv4 address into a multicast MAC address if the NIC is an\r
+    // ethernet NIC.\r
+    //\r
+    MacAddress->Addr[0] = 0x01;\r
+    MacAddress->Addr[1] = 0x00;\r
+    MacAddress->Addr[2] = 0x5E;\r
+    MacAddress->Addr[3] = IpAddress->v4.Addr[1] & 0x7F;\r
+    MacAddress->Addr[4] = IpAddress->v4.Addr[2];\r
+    MacAddress->Addr[5] = IpAddress->v4.Addr[3];\r
+\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // Invoke Snp to translate the multicast IP address.\r
+    //\r
+    Status = Snp->MCastIpToMac (\r
+                    Snp,\r
+                    Ipv6Flag,\r
+                    IpAddress,\r
+                    MacAddress\r
+                    );\r
+  }\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Enable or disable receie filters for multicast address.\r
+\r
+  @param  This                   Pointer to the Managed Network Protocol.\r
+  @param  JoinFlag               Set to TRUE to join this multicast group. Set to\r
+                                 FALSE to leave this multicast group.\r
+  @param  MacAddress             Pointer to the multicast MAC group (address) to\r
+                                 join or leave.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameter is invalid\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured.\r
+  @retval EFI_ALREADY_STARTED    The supplied multicast group is already joined.\r
+  @retval EFI_NOT_FOUND          The supplied multicast group is not joined.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval Other                  The requested operation could not be completed.\r
+                                 The MNP multicast group settings are unchanged.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpGroups (\r
+  IN EFI_MANAGED_NETWORK_PROTOCOL  *This,\r
+  IN BOOLEAN                       JoinFlag,\r
+  IN EFI_MAC_ADDRESS               *MacAddress OPTIONAL\r
+  )\r
+{\r
+  MNP_INSTANCE_DATA       *Instance;\r
+  EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+  MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;\r
+  MNP_GROUP_ADDRESS       *GroupAddress;\r
+  NET_LIST_ENTRY          *ListEntry;\r
+  BOOLEAN                 AddressExist;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+\r
+  if (This == NULL || (JoinFlag && (MacAddress == NULL))) {\r
+    //\r
+    // This is NULL, or it's a join operation but MacAddress is NULL.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance  = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+  SnpMode   = Instance->MnpServiceData->Snp->Mode;\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (!Instance->Configured) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if ((!Instance->ConfigData.EnableMulticastReceive) ||\r
+    ((MacAddress != NULL) && !NET_MAC_IS_MULTICAST (MacAddress, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize))) {\r
+    //\r
+    // The instance isn't configured to do mulitcast receive. OR\r
+    // the passed in MacAddress is not a mutlticast mac address.\r
+    //\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status       = EFI_SUCCESS;\r
+  AddressExist = FALSE;\r
+  GroupCtrlBlk = NULL;\r
+\r
+  if (MacAddress != NULL) {\r
+    //\r
+    // Search the instance's GroupCtrlBlkList to find the specific address.\r
+    //\r
+    NET_LIST_FOR_EACH (ListEntry, &Instance->GroupCtrlBlkList) {\r
+\r
+      GroupCtrlBlk = NET_LIST_USER_STRUCT (\r
+                      ListEntry,\r
+                      MNP_GROUP_CONTROL_BLOCK,\r
+                      CtrlBlkEntry\r
+                      );\r
+      GroupAddress = GroupCtrlBlk->GroupAddress;\r
+      if (0 == NetCompareMem (\r
+                MacAddress,\r
+                &GroupAddress->Address,\r
+                SnpMode->HwAddressSize\r
+                )) {\r
+        //\r
+        // There is already the same multicast mac address configured.\r
+        //\r
+        AddressExist = TRUE;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (JoinFlag && AddressExist) {\r
+      //\r
+      // The multicast mac address to join already exists.\r
+      //\r
+      Status = EFI_ALREADY_STARTED;\r
+    }\r
+\r
+    if (!JoinFlag && !AddressExist) {\r
+      //\r
+      // The multicast mac address to leave doesn't exist in this instance.\r
+      //\r
+      Status = EFI_NOT_FOUND;\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  } else if (NetListIsEmpty (&Instance->GroupCtrlBlkList)) {\r
+    //\r
+    // The MacAddress is NULL and there is no configured multicast mac address,\r
+    // just return.\r
+    //\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // OK, it is time to take action.\r
+  //\r
+  Status = MnpGroupOp (Instance, JoinFlag, MacAddress, GroupCtrlBlk);\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Place an outgoing packet into the transmit queue.\r
+\r
+  @param  This                   Pointer to the Managed Network Protocol.\r
+  @param  Token                  Pointer to a token associated with the transmit\r
+                                 data descriptor.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameter is invalid\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured.\r
+  @retval EFI_ACCESS_DENIED      The transmit completion token is already in the\r
+                                 transmit queue.\r
+  @retval EFI_OUT_OF_RESOURCES   The transmit data could not be queued due to a\r
+                                 lack of system resources (usually memory).\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+                                 The MNP child driver instance has been reset to\r
+                                 startup defaults.\r
+  @retval EFI_NOT_READY          The transmit request could not be queued because\r
+                                 the transmit queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpTransmit (\r
+  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,\r
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  MNP_INSTANCE_DATA *Instance;\r
+  MNP_SERVICE_DATA  *MnpServiceData;\r
+  UINT8             *PktBuf;\r
+  UINT32            PktLen;\r
+  EFI_TPL           OldTpl;\r
+\r
+  if ((This == NULL) || (Token == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (!Instance->Configured) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (!MnpIsValidTxToken (Instance, Token)) {\r
+    //\r
+    // The Token is invalid.\r
+    //\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  MnpServiceData = Instance->MnpServiceData;\r
+  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+  //\r
+  // Build the tx packet\r
+  //\r
+  MnpBuildTxPacket (MnpServiceData, Token->Packet.TxData, &PktBuf, &PktLen);\r
+\r
+  //\r
+  //  OK, send the packet synchronously.\r
+  //\r
+  Status = MnpSyncSendPacket (MnpServiceData, PktBuf, PktLen, Token);\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Place an asynchronous receiving request into the receiving queue.\r
+\r
+  @param  This                   Pointer to the EFI_MANAGED_NETWORK_PROTOCOL\r
+                                 instance.\r
+  @param  Token                  Pointer to a token associated with the receive\r
+                                 data descriptor.\r
+\r
+  @retval EFI_SUCCESS            The receive completion token was cached.\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameter is invalid.\r
+  @retval EFI_OUT_OF_RESOURCES   The transmit data could not be queued due to a\r
+                                 lack of system resources (usually memory).\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+                                 The MNP child driver instance has been reset to\r
+                                 startup defaults.\r
+  @retval EFI_ACCESS_DENIED      The receive completion token was already in the\r
+                                 receive queue.\r
+  @retval EFI_NOT_READY          The receive request could not be queued because\r
+                                 the receive queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpReceive (\r
+  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,\r
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  MNP_INSTANCE_DATA  *Instance;\r
+  EFI_TPL            OldTpl;\r
+\r
+  if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (!Instance->Configured) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check whether this token(event) is already in the rx token queue.\r
+  //\r
+  Status = NetMapIterate (&Instance->RxTokenMap, MnpTokenExist, (VOID *) Token);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Insert the Token into the RxTokenMap.\r
+  //\r
+  Status = NetMapInsertTail (&Instance->RxTokenMap, (VOID *) Token, NULL);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Try to deliver any buffered packets.\r
+    //\r
+    Status = MnpInstanceDeliverPacket (Instance);\r
+  }\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Abort a pending transmit or receive request.\r
+\r
+  @param  This                   Pointer to the EFI_MANAGED_NETWORK_PROTOCOL\r
+                                 instance.\r
+  @param  Token                  Pointer to a token that has been issued by\r
+                                 EFI_MANAGED_NETWORK_PROTOCOL.Transmit() or\r
+                                 EFI_MANAGED_NETWORK_PROTOCOL.Receive(). If NULL,\r
+                                 all pending tokens are aborted.\r
+\r
+  @retval EFI_SUCCESS            The asynchronous I/O request was aborted and\r
+                                 Token->Event was signaled.\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+  @retval EFI_NOT_FOUND          The asynchronous I/O request was not found in the\r
+                                 transmit or receive queue. It has either completed\r
+                                 or was not issued by Transmit() and Receive().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpCancel (\r
+  IN EFI_MANAGED_NETWORK_PROTOCOL          *This,\r
+  IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  MNP_INSTANCE_DATA  *Instance;\r
+  EFI_TPL            OldTpl;\r
+\r
+  if (This == NULL) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (!Instance->Configured) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Iterate the RxTokenMap to cancel the specified Token.\r
+  //\r
+  Status = NetMapIterate (&Instance->RxTokenMap, MnpCancelTokens, (VOID *) Token);\r
+\r
+  if (Token != NULL) {\r
+\r
+    Status = (Status == EFI_ABORTED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+  }\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Poll the network interface to do transmit/receive work.\r
+\r
+  @param  This                   Pointer to the EFI_MANAGED_NETWORK_PROTOCOL\r
+                                 instance.\r
+\r
+  @retval EFI_SUCCESS            Incoming or outgoing data was processed.\r
+  @retval EFI_NOT_STARTED        This MNP child driver instance has not been\r
+                                 configured.\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+                                 The MNP child driver instance has been reset to\r
+                                 startup defaults.\r
+  @retval EFI_NOT_READY          No incoming or outgoing data was processed.\r
+  @retval EFI_TIMEOUT            Data was dropped out of the transmit and/or\r
+                                 receive queue.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpPoll (\r
+  IN EFI_MANAGED_NETWORK_PROTOCOL  *This\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  MNP_INSTANCE_DATA  *Instance;\r
+  EFI_TPL            OldTpl;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (!Instance->Configured) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Try to receive packets.\r
+  //\r
+  Status = MnpReceivePacket (Instance->MnpServiceData);\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c b/MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..6da17a3
--- /dev/null
@@ -0,0 +1,163 @@
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+\r
+#include "Snp.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gSimpleNetworkComponentName = {\r
+  SimpleNetworkComponentNameGetDriverName,\r
+  SimpleNetworkComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"Simple Network Protocol Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller\r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a\r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language\r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned\r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gSimpleNetworkComponentName.SupportedLanguages,\r
+          mSimpleNetworkDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by\r
+                       This is managing.  This handle specifies the controller\r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name\r
+                       of.  This is an optional parameter that may be NULL.  It\r
+                       will be NULL for device drivers.  It will also be NULL\r
+                       for a bus drivers that wish to retrieve the name of the\r
+                       bus controller.  It will not be NULL for a bus driver\r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language\r
+                       identifier.  This is the language of the controller name\r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The\r
+                       number of languages supported by a driver is up to the\r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by\r
+                       ControllerHandle and ChildHandle in the language specified\r
+                       by Language from the point of view of the driver specified\r
+                       by This.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the user readable name in the\r
+                            language specified by Language for the driver\r
+                            specified by This was returned in DriverName.\r
+    EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This is not currently managing\r
+                            the controller specified by ControllerHandle and\r
+                            ChildHandle.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf b/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf
new file mode 100644 (file)
index 0000000..34623da
--- /dev/null
@@ -0,0 +1,75 @@
+#/** @file\r
+# Component name for module SNP\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. 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
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = SnpDxe\r
+  FILE_GUID                      = A2f436EA-A127-4EF8-957C-8048606FF670\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = InitializeSnpNiiDriver\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  receive.c\r
+  snp.h\r
+  nvdata.c\r
+  get_status.c\r
+  start.c\r
+  snp.c\r
+  stop.c\r
+  statistics.c\r
+  reset.c\r
+  shutdown.c\r
+  mcast_ip_to_mac.c\r
+  transmit.c\r
+  WaitForPacket.c\r
+  receive_filters.c\r
+  initialize.c\r
+  ComponentName.c\r
+  callback.c\r
+  station_address.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  UefiLib\r
+  BaseLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  DebugLib\r
+\r
+\r
+[Protocols]\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSimpleNetworkProtocolGuid                 # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiNetworkInterfaceIdentifierProtocolGuid    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiNetworkInterfaceIdentifierProtocolGuid_31 # PROTOCOL ALWAYS_CONSUMED\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa b/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa
new file mode 100644 (file)
index 0000000..748b5c5
--- /dev/null
@@ -0,0 +1,90 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>SnpDxe</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>A2f436EA-A127-4EF8-957C-8048606FF670</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module SNP</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <License>All rights reserved. This program and the accompanying materials
+      are licensed and made available under the terms and conditions of the BSD License
+      which accompanies this distribution.  The full text of the license may be found at
+      http://opensource.org/licenses/bsd-license.php
+
+      THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+      WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>SnpDxe</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseMemoryLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>station_address.c</Filename>\r
+    <Filename>SNPEntry.c</Filename>\r
+    <Filename>callback.c</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>initialize.c</Filename>\r
+    <Filename>receive_filters.c</Filename>\r
+    <Filename>WaitForPacket.c</Filename>\r
+    <Filename>transmit.c</Filename>\r
+    <Filename>mcast_ip_to_mac.c</Filename>\r
+    <Filename>shutdown.c</Filename>\r
+    <Filename>reset.c</Filename>\r
+    <Filename>statistics.c</Filename>\r
+    <Filename>stop.c</Filename>\r
+    <Filename>snp.c</Filename>\r
+    <Filename>start.c</Filename>\r
+    <Filename>get_status.c</Filename>\r
+    <Filename>nvdata.c</Filename>\r
+    <Filename>snp.h</Filename>\r
+    <Filename>receive.c</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiNetworkInterfaceIdentifierProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>InitializeSnpNiiDriver</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c b/MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c
new file mode 100644 (file)
index 0000000..57d82ea
--- /dev/null
@@ -0,0 +1,97 @@
+/** @file\r
+Copyright (c) 2004, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  WaitForPacket.c\r
+\r
+Abstract:\r
+  Event handler to check for available packet.\r
+\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+\r
+\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SnpWaitForPacketNotify (\r
+  EFI_EVENT Event,\r
+  VOID      *SnpPtr\r
+  )\r
+{\r
+  PXE_DB_GET_STATUS PxeDbGetStatus;\r
+\r
+  //\r
+  // Do nothing if either parameter is a NULL pointer.\r
+  //\r
+  if (Event == NULL || SnpPtr == NULL) {\r
+    return ;\r
+  }\r
+  //\r
+  // Do nothing if the SNP interface is not initialized.\r
+  //\r
+  switch (((SNP_DRIVER *) SnpPtr)->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+  case EfiSimpleNetworkStarted:\r
+  default:\r
+    return ;\r
+  }\r
+  //\r
+  // Fill in CDB for UNDI GetStatus().\r
+  //\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.OpCode     = PXE_OPCODE_GET_STATUS;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.OpFlags    = 0;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.DBsize     = sizeof (UINT32) * 2;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.DBaddr     = (UINT64)(UINTN) (((SNP_DRIVER *) SnpPtr)->db);\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.IFnum      = ((SNP_DRIVER *) SnpPtr)->if_num;\r
+  ((SNP_DRIVER *) SnpPtr)->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Clear contents of DB buffer.\r
+  //\r
+  ZeroMem (((SNP_DRIVER *) SnpPtr)->db, sizeof (UINT32) * 2);\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  (*((SNP_DRIVER *) SnpPtr)->issue_undi32_command) ((UINT64)(UINTN) &((SNP_DRIVER *) SnpPtr)->cdb);\r
+\r
+  if (((SNP_DRIVER *) SnpPtr)->cdb.StatCode != EFI_SUCCESS) {\r
+    return ;\r
+  }\r
+  //\r
+  // We might have a packet.  Check the receive length and signal\r
+  // the event if the length is not zero.\r
+  //\r
+  CopyMem (\r
+    &PxeDbGetStatus,\r
+    ((SNP_DRIVER *) SnpPtr)->db,\r
+    sizeof (UINT32) * 2\r
+    );\r
+\r
+  if (PxeDbGetStatus.RxFrameLen != 0) {\r
+    gBS->SignalEvent (Event);\r
+  }\r
+}\r
+\r
+/* eof - WaitForPacket.c */\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/callback.c b/MdeModulePkg/Universal/Network/SnpDxe/callback.c
new file mode 100644 (file)
index 0000000..c246874
--- /dev/null
@@ -0,0 +1,611 @@
+/*++\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+ callback.c\r
+\r
+Abstract:\r
+ This file contains two sets of callback routines for undi3.0 and undi3.1.\r
+ the callback routines for Undi3.1 have an extra parameter UniqueId which\r
+ stores the interface context for the NIC that snp is trying to talk..\r
+\r
+--*/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+//\r
+// Global variables\r
+// these 2 global variables are used only for 3.0 undi. we could not place\r
+// them in the snp structure because we will not know which snp structure\r
+// in the callback context!\r
+//\r
+STATIC BOOLEAN              mInitializeLock = TRUE;\r
+STATIC EFI_LOCK             mLock;\r
+\r
+//\r
+// End Global variables\r
+//\r
+extern EFI_PCI_IO_PROTOCOL  *mPciIoFncs;\r
+\r
+VOID\r
+snp_undi32_callback_v2p_30 (\r
+  IN UINT64     CpuAddr,\r
+  IN OUT UINT64 DeviceAddrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine with a virtual or CPU address that SNP provided\r
+ to convert it to a physical or device address. Since EFI uses the identical\r
+ mapping, this routine returns the physical address same as the virtual address\r
+ for most of the addresses. an address above 4GB cannot generally be used as a\r
+ device address, it needs to be mapped to a lower physical address. This routine\r
+ does not call the map routine itself, but it assumes that the mapping was done\r
+ at the time of providing the address to UNDI. This routine just looks up the\r
+ address in a map table (which is the v2p structure chain)\r
+\r
+Arguments:\r
+ CpuAddr - virtual address of a buffer\r
+ DeviceAddrPtr - pointer to the physical address\r
+\r
+Returns:\r
+ void - The DeviceAddrPtr will contain 0 in case of any error\r
+\r
+--*/\r
+{\r
+  struct s_v2p  *v2p;\r
+  //\r
+  // Do nothing if virtual address is zero or physical pointer is NULL.\r
+  // No need to map if the virtual address is within 4GB limit since\r
+  // EFI uses identical mapping\r
+  //\r
+  if ((CpuAddr == 0) || (DeviceAddrPtr == 0)) {\r
+    DEBUG ((EFI_D_ERROR, "\nv2p: Null virtual address or physical pointer.\n"));\r
+    return ;\r
+  }\r
+\r
+  if (CpuAddr < FOUR_GIGABYTES) {\r
+    *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;\r
+    return ;\r
+  }\r
+  //\r
+  // SNP creates a vaddr tp paddr mapping at the time of calling undi with any\r
+  // big address, this callback routine just looks up in the v2p list and\r
+  // returns the physical address for any given virtual address.\r
+  //\r
+  if (find_v2p (&v2p, (VOID *) (UINTN) CpuAddr) != EFI_SUCCESS) {\r
+    *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;\r
+  } else {\r
+    *(UINT64 *) (UINTN) DeviceAddrPtr = v2p->paddr;\r
+  }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_block_30 (\r
+  IN UINT32 Enable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it wants to have exclusive access to a critical\r
+ section of the code/data\r
+\r
+Arguments:\r
+ Enable - non-zero indicates acquire\r
+          zero indicates release\r
+\r
+Returns:\r
+ void\r
+--*/\r
+{\r
+  //\r
+  // tcpip was calling snp at tpl_notify and if we acquire a lock that was\r
+  // created at a lower level (TPL_CALLBACK) it gives an assert!\r
+  //\r
+  if (mInitializeLock) {\r
+    EfiInitializeLock (&mLock, TPL_NOTIFY);\r
+    mInitializeLock = FALSE;\r
+  }\r
+\r
+  if (Enable != 0) {\r
+    EfiAcquireLock (&mLock);\r
+  } else {\r
+    EfiReleaseLock (&mLock);\r
+  }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_delay_30 (\r
+  IN UINT64 MicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine with the number of micro seconds when it wants to\r
+ pause.\r
+\r
+Arguments:\r
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10\r
+\r
+Returns:\r
+ void\r
+--*/\r
+{\r
+  if (MicroSeconds != 0) {\r
+    gBS->Stall ((UINTN) MicroSeconds);\r
+  }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_memio_30 (\r
+  IN UINT8      ReadOrWrite,\r
+  IN UINT8      NumBytes,\r
+  IN UINT64     Address,\r
+  IN OUT UINT64 BufferAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ This is the IO routine for UNDI. This is not currently being used by UNDI3.0\r
+ because Undi3.0 uses io/mem offsets relative to the beginning of the device\r
+ io/mem address and so it needs to use the PCI_IO_FUNCTION that abstracts the\r
+ start of the device's io/mem addresses. Since SNP cannot retrive the context\r
+ of the undi3.0 interface it cannot use the PCI_IO_FUNCTION that specific for\r
+ that NIC and uses one global IO functions structure, this does not work.\r
+ This however works fine for EFI1.0 Undis because they use absolute addresses\r
+ for io/mem access.\r
+\r
+Arguments:\r
+  ReadOrWrite - indicates read or write, IO or Memory\r
+  NumBytes    - number of bytes to read or write\r
+  Address     - IO or memory address to read from or write to\r
+  BufferAddr  - memory location to read into or that contains the bytes\r
+                to write\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+\r
+  switch (NumBytes) {\r
+  case 2:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
+    break;\r
+\r
+  case 4:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
+    break;\r
+\r
+  case 8:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
+    break;\r
+\r
+  default:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
+  }\r
+\r
+  switch (ReadOrWrite) {\r
+  case PXE_IO_READ:\r
+    mPciIoFncs->Io.Read (\r
+                    mPciIoFncs,\r
+                    Width,\r
+                    1,    // BAR 1, IO base address\r
+                    Address,\r
+                    1,    // count\r
+                    (VOID *) (UINTN) BufferAddr\r
+                    );\r
+    break;\r
+\r
+  case PXE_IO_WRITE:\r
+    mPciIoFncs->Io.Write (\r
+                    mPciIoFncs,\r
+                    Width,\r
+                    1,    // BAR 1, IO base address\r
+                    Address,\r
+                    1,    // count\r
+                    (VOID *) (UINTN) BufferAddr\r
+                    );\r
+    break;\r
+\r
+  case PXE_MEM_READ:\r
+    mPciIoFncs->Mem.Read (\r
+                      mPciIoFncs,\r
+                      Width,\r
+                      0,  // BAR 0, Memory base address\r
+                      Address,\r
+                      1,  // count\r
+                      (VOID *) (UINTN) BufferAddr\r
+                      );\r
+    break;\r
+\r
+  case PXE_MEM_WRITE:\r
+    mPciIoFncs->Mem.Write (\r
+                      mPciIoFncs,\r
+                      Width,\r
+                      0,  // BAR 0, Memory base address\r
+                      Address,\r
+                      1,  // count\r
+                      (VOID *) (UINTN) BufferAddr\r
+                      );\r
+    break;\r
+  }\r
+\r
+  return ;\r
+}\r
+//\r
+// New callbacks for 3.1:\r
+// there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses\r
+// the MemMap call to map the required address by itself!\r
+//\r
+VOID\r
+snp_undi32_callback_block (\r
+  IN UINT64 UniqueId,\r
+  IN UINT32 Enable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI3.1 at undi_start time.\r
+ UNDI call this routine when it wants to have exclusive access to a critical\r
+ section of the code/data\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+            Undi interface context (Undi does not read or write this variable)\r
+ Enable   - non-zero indicates acquire\r
+            zero indicates release\r
+\r
+Returns:\r
+ void\r
+\r
+--*/\r
+{\r
+  SNP_DRIVER  *snp;\r
+\r
+  snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
+  //\r
+  // tcpip was calling snp at tpl_notify and when we acquire a lock that was\r
+  // created at a lower level (TPL_CALLBACK) it gives an assert!\r
+  //\r
+  if (Enable != 0) {\r
+    EfiAcquireLock (&snp->lock);\r
+  } else {\r
+    EfiReleaseLock (&snp->lock);\r
+  }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_delay (\r
+  IN UINT64 UniqueId,\r
+  IN UINT64 MicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine with the number of micro seconds when it wants to\r
+ pause.\r
+\r
+Arguments:\r
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10\r
+\r
+Returns:\r
+ void\r
+--*/\r
+{\r
+  if (MicroSeconds != 0) {\r
+    gBS->Stall ((UINTN) MicroSeconds);\r
+  }\r
+}\r
+\r
+/*\r
+ *  IO routine for UNDI start CPB.\r
+ */\r
+VOID\r
+snp_undi32_callback_memio (\r
+  UINT64 UniqueId,\r
+  UINT8  ReadOrWrite,\r
+  UINT8  NumBytes,\r
+  UINT64 Address,\r
+  UINT64 BufferAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ This is the IO routine for UNDI3.1.\r
+\r
+Arguments:\r
+  ReadOrWrite - indicates read or write, IO or Memory\r
+  NumBytes    - number of bytes to read or write\r
+  Address     - IO or memory address to read from or write to\r
+  BufferAddr  - memory location to read into or that contains the bytes\r
+                to write\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  SNP_DRIVER                *snp;\r
+  EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+\r
+  snp   = (SNP_DRIVER *) (UINTN) UniqueId;\r
+\r
+  Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
+  switch (NumBytes) {\r
+  case 2:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
+    break;\r
+\r
+  case 4:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
+    break;\r
+\r
+  case 8:\r
+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
+    break;\r
+  }\r
+\r
+  switch (ReadOrWrite) {\r
+  case PXE_IO_READ:\r
+    snp->IoFncs->Io.Read (\r
+                      snp->IoFncs,\r
+                      Width,\r
+                      snp->IoBarIndex,      // BAR 1 (for 32bit regs), IO base address\r
+                      Address,\r
+                      1,                    // count\r
+                      (VOID *) (UINTN) BufferAddr\r
+                      );\r
+    break;\r
+\r
+  case PXE_IO_WRITE:\r
+    snp->IoFncs->Io.Write (\r
+                      snp->IoFncs,\r
+                      Width,\r
+                      snp->IoBarIndex,      // BAR 1 (for 32bit regs), IO base address\r
+                      Address,\r
+                      1,                    // count\r
+                      (VOID *) (UINTN) BufferAddr\r
+                      );\r
+    break;\r
+\r
+  case PXE_MEM_READ:\r
+    snp->IoFncs->Mem.Read (\r
+                      snp->IoFncs,\r
+                      Width,\r
+                      snp->MemoryBarIndex,  // BAR 0, Memory base address\r
+                      Address,\r
+                      1,                    // count\r
+                      (VOID *) (UINTN) BufferAddr\r
+                      );\r
+    break;\r
+\r
+  case PXE_MEM_WRITE:\r
+    snp->IoFncs->Mem.Write (\r
+                      snp->IoFncs,\r
+                      Width,\r
+                      snp->MemoryBarIndex,  // BAR 0, Memory base address\r
+                      Address,\r
+                      1,                    // count\r
+                      (VOID *) (UINTN) BufferAddr\r
+                      );\r
+    break;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_map (\r
+  IN UINT64     UniqueId,\r
+  IN UINT64     CpuAddr,\r
+  IN UINT32     NumBytes,\r
+  IN UINT32     Direction,\r
+  IN OUT UINT64 DeviceAddrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  This is a callback routine supplied to UNDI at undi_start time.\r
+  UNDI call this routine when it has to map a CPU address to a device\r
+  address.\r
+\r
+Arguments:\r
+  UniqueId      - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+                  Undi interface context (Undi does not read or write this variable)\r
+  CpuAddr       - Virtual address to be mapped!\r
+  NumBytes      - size of memory to be mapped\r
+  Direction     - direction of data flow for this memory's usage:\r
+                  cpu->device, device->cpu or both ways\r
+  DeviceAddrPtr - pointer to return the mapped device address\r
+\r
+Returns:\r
+  None\r
+\r
+--*/\r
+{\r
+  EFI_PHYSICAL_ADDRESS          *DevAddrPtr;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;\r
+  UINTN                         BuffSize;\r
+  SNP_DRIVER                    *snp;\r
+  UINTN                         Index;\r
+  EFI_STATUS                    Status;\r
+\r
+  BuffSize    = (UINTN) NumBytes;\r
+  snp         = (SNP_DRIVER *) (UINTN) UniqueId;\r
+  DevAddrPtr  = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;\r
+\r
+  if (CpuAddr == 0) {\r
+    *DevAddrPtr = 0;\r
+    return ;\r
+  }\r
+\r
+  switch (Direction) {\r
+  case TO_AND_FROM_DEVICE:\r
+    DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;\r
+    break;\r
+\r
+  case FROM_DEVICE:\r
+    DirectionFlag = EfiPciIoOperationBusMasterWrite;\r
+    break;\r
+\r
+  case TO_DEVICE:\r
+    DirectionFlag = EfiPciIoOperationBusMasterRead;\r
+    break;\r
+\r
+  default:\r
+    *DevAddrPtr = 0;\r
+    //\r
+    // any non zero indicates error!\r
+    //\r
+    return ;\r
+  }\r
+  //\r
+  // find an unused map_list entry\r
+  //\r
+  for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
+    if (snp->map_list[Index].virt == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index >= MAX_MAP_LENGTH) {\r
+    DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));\r
+    *DevAddrPtr = 0;\r
+    return ;\r
+  }\r
+\r
+  snp->map_list[Index].virt = (EFI_PHYSICAL_ADDRESS) CpuAddr;\r
+\r
+  Status = snp->IoFncs->Map (\r
+                          snp->IoFncs,\r
+                          DirectionFlag,\r
+                          (VOID *) (UINTN) CpuAddr,\r
+                          &BuffSize,\r
+                          DevAddrPtr,\r
+                          &(snp->map_list[Index].map_cookie)\r
+                          );\r
+  if (Status != EFI_SUCCESS) {\r
+    *DevAddrPtr               = 0;\r
+    snp->map_list[Index].virt = 0;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_unmap (\r
+  IN UINT64 UniqueId,\r
+  IN UINT64 CpuAddr,\r
+  IN UINT32 NumBytes,\r
+  IN UINT32 Direction,\r
+  IN UINT64 DeviceAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it wants to unmap an address that was previously\r
+ mapped using map callback\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+            Undi interface context (Undi does not read or write this variable)\r
+ CpuAddr  - Virtual address that was mapped!\r
+ NumBytes - size of memory mapped\r
+ Direction- direction of data flow for this memory's usage:\r
+            cpu->device, device->cpu or both ways\r
+ DeviceAddr - the mapped device address\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  SNP_DRIVER  *snp;\r
+  UINT16      Index;\r
+\r
+  snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
+\r
+  for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
+    if (snp->map_list[Index].virt == CpuAddr) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index >= MAX_MAP_LENGTH)\r
+  {\r
+    DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));\r
+    return ;\r
+  }\r
+\r
+  snp->IoFncs->Unmap (snp->IoFncs, snp->map_list[Index].map_cookie);\r
+  snp->map_list[Index].virt       = 0;\r
+  snp->map_list[Index].map_cookie = NULL;\r
+  return ;\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_sync (\r
+  UINT64 UniqueId,\r
+  UINT64 CpuAddr,\r
+  UINT32 NumBytes,\r
+  UINT32 Direction,\r
+  UINT64 DeviceAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it wants synchronize the virtual buffer contents\r
+ with the mapped buffer contents. The virtual and mapped buffers need not\r
+ correspond to the same physical memory (especially if the virtual address is\r
+ > 4GB). Depending on the direction for which the buffer is mapped, undi will\r
+ need to synchronize their contents whenever it writes to/reads from the buffer\r
+ using either the cpu address or the device address.\r
+\r
+ EFI does not provide a sync call, since virt=physical, we sould just do\r
+ the synchronization ourself here!\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+            Undi interface context (Undi does not read or write this variable)\r
+ CpuAddr  - Virtual address that was mapped!\r
+ NumBytes - size of memory mapped\r
+ Direction- direction of data flow for this memory's usage:\r
+            cpu->device, device->cpu or both ways\r
+ DeviceAddr - the mapped device address\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {\r
+    return ;\r
+\r
+  }\r
+\r
+  switch (Direction) {\r
+  case FROM_DEVICE:\r
+    CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);\r
+    break;\r
+\r
+  case TO_DEVICE:\r
+    CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);\r
+    break;\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/get_status.c b/MdeModulePkg/Universal/Network/SnpDxe/get_status.c
new file mode 100644 (file)
index 0000000..0c1cd8a
--- /dev/null
@@ -0,0 +1,195 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  get_status.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-03 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+STATIC\r
+/**\r
+  this routine calls undi to get the status of the interrupts, get the list of\r
+  transmit buffers that completed transmitting!\r
+\r
+  @param  snp                     pointer to snp driver structure\r
+  @param  InterruptStatusPtr      a non null pointer gets the interrupt status\r
+  @param  TransmitBufferListPtrs  a non null ointer gets the list of pointers of\r
+                                  previously  transmitted buffers whose\r
+                                  transmission was completed  asynchrnously.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_getstatus (\r
+  SNP_DRIVER *snp,\r
+  UINT32     *InterruptStatusPtr,\r
+  VOID       **TransmitBufferListPtr\r
+  )\r
+{\r
+  PXE_DB_GET_STATUS *db;\r
+  UINT16            InterruptFlags;\r
+  UINT64            TempData;\r
+\r
+  db                = snp->db;\r
+  snp->cdb.OpCode   = PXE_OPCODE_GET_STATUS;\r
+\r
+  snp->cdb.OpFlags  = 0;\r
+\r
+  if (TransmitBufferListPtr != NULL) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;\r
+  }\r
+\r
+  if (InterruptStatusPtr != NULL) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;\r
+  }\r
+\r
+  snp->cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;\r
+\r
+  //\r
+  // size DB for return of one buffer\r
+  //\r
+  snp->cdb.DBsize = (UINT16) (((UINT16) (sizeof (PXE_DB_GET_STATUS)) - (UINT16) (sizeof db->TxBuffer)) + (UINT16) (sizeof db->TxBuffer[0]));\r
+\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.get_status()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+    DEBUG (\r
+      (EFI_D_NET,\r
+      "\nsnp->undi.get_status()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatFlags)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // report the values back..\r
+  //\r
+  if (InterruptStatusPtr != NULL) {\r
+    InterruptFlags      = (UINT16) (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);\r
+\r
+    *InterruptStatusPtr = 0;\r
+\r
+    if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) {\r
+      *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
+    }\r
+\r
+    if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) {\r
+      *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
+    }\r
+\r
+    if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) {\r
+      *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;\r
+    }\r
+\r
+    if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) {\r
+      *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;\r
+    }\r
+\r
+  }\r
+\r
+  if (TransmitBufferListPtr != NULL) {\r
+    *TransmitBufferListPtr =\r
+      (\r
+        (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) ||\r
+        (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY)\r
+      ) ? 0 : (VOID *) (UINTN) db->TxBuffer[0];\r
+\r
+    TempData = (UINT64) (UINTN) (*TransmitBufferListPtr);\r
+    if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+      del_v2p ((VOID *) (UINTN) (db->TxBuffer[0]));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for getting the status\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_getstatus routine to actually get the undi status\r
+\r
+  @param  this                    context pointer\r
+  @param  InterruptStatusPtr      a non null pointer gets the interrupt status\r
+  @param  TransmitBufferListPtrs  a non null ointer gets the list of pointers of\r
+                                  previously  transmitted buffers whose\r
+                                  transmission was completed  asynchrnously.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_get_status (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+  OUT UINT32                     *InterruptStatusPtr OPTIONAL,\r
+  OUT VOID                       **TransmitBufferListPtr OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+  EFI_STATUS  Status;\r
+\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (InterruptStatusPtr == NULL && TransmitBufferListPtr == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (snp == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = pxe_getstatus (snp, InterruptStatusPtr, TransmitBufferListPtr);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/initialize.c b/MdeModulePkg/Universal/Network/SnpDxe/initialize.c
new file mode 100644 (file)
index 0000000..69154fc
--- /dev/null
@@ -0,0 +1,245 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  initialize.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-09 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+VOID\r
+EFIAPI\r
+SnpWaitForPacketNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *SnpPtr\r
+  );\r
+\r
+\r
+/**\r
+  this routine calls undi to initialize the interface.\r
+\r
+  @param  snp                   pointer to snp driver structure\r
+  @param  CableDetectFlag       Do/don't detect the cable (depending on what undi\r
+                                supports)\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_init (\r
+  SNP_DRIVER *snp,\r
+  UINT16     CableDetectFlag\r
+  )\r
+{\r
+  PXE_CPB_INITIALIZE  *cpb;\r
+  VOID                *addr;\r
+  EFI_STATUS          Status;\r
+\r
+  cpb = snp->cpb;\r
+  if (snp->tx_rx_bufsize != 0) {\r
+    Status = snp->IoFncs->AllocateBuffer (\r
+                            snp->IoFncs,\r
+                            AllocateAnyPages,\r
+                            EfiBootServicesData,\r
+                            SNP_MEM_PAGES (snp->tx_rx_bufsize),\r
+                            &addr,\r
+                            0\r
+                            );\r
+\r
+    if (Status != EFI_SUCCESS) {\r
+      DEBUG (\r
+        (EFI_D_ERROR,\r
+        "\nsnp->pxe_init()  AllocateBuffer  %xh (%r)\n",\r
+        Status,\r
+        Status)\r
+        );\r
+\r
+      return Status;\r
+    }\r
+\r
+    ASSERT (addr);\r
+\r
+    snp->tx_rx_buffer = addr;\r
+  }\r
+\r
+  cpb->MemoryAddr   = (UINT64)(UINTN) snp->tx_rx_buffer;\r
+\r
+  cpb->MemoryLength = snp->tx_rx_bufsize;\r
+\r
+  //\r
+  // let UNDI decide/detect these values\r
+  //\r
+  cpb->LinkSpeed      = 0;\r
+  cpb->TxBufCnt       = 0;\r
+  cpb->TxBufSize      = 0;\r
+  cpb->RxBufCnt       = 0;\r
+  cpb->RxBufSize      = 0;\r
+\r
+  cpb->DuplexMode         = PXE_DUPLEX_DEFAULT;\r
+\r
+  cpb->LoopBackMode       = LOOPBACK_NORMAL;\r
+\r
+  snp->cdb.OpCode     = PXE_OPCODE_INITIALIZE;\r
+  snp->cdb.OpFlags    = CableDetectFlag;\r
+\r
+  snp->cdb.CPBsize    = sizeof (PXE_CPB_INITIALIZE);\r
+  snp->cdb.DBsize     = sizeof (PXE_DB_INITIALIZE);\r
+\r
+  snp->cdb.CPBaddr    = (UINT64)(UINTN) snp->cpb;\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) snp->db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.initialize()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode == PXE_STATCODE_SUCCESS) {\r
+    snp->mode.State = EfiSimpleNetworkInitialized;\r
+\r
+    Status          = EFI_SUCCESS;\r
+  } else {\r
+    DEBUG (\r
+      (EFI_D_WARN,\r
+      "\nsnp->undi.initialize()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    if (snp->tx_rx_buffer != NULL) {\r
+      snp->IoFncs->FreeBuffer (\r
+                    snp->IoFncs,\r
+                    SNP_MEM_PAGES (snp->tx_rx_bufsize),\r
+                    (VOID *) snp->tx_rx_buffer\r
+                    );\r
+    }\r
+\r
+    snp->tx_rx_buffer = NULL;\r
+\r
+    Status            = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for initializing the interface\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_initialize routine to actually do the undi initialization\r
+\r
+  @param  this                  context pointer\r
+  @param  extra_rx_buffer_size  optional parameter, indicates extra space for\r
+                                rx_buffers\r
+  @param  extra_tx_buffer_size  optional parameter, indicates extra space for\r
+                                tx_buffers\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_initialize (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+  IN UINTN                       extra_rx_buffer_size OPTIONAL,\r
+  IN UINTN                       extra_tx_buffer_size OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  EfiStatus;\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+\r
+  //\r
+  //\r
+  //\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (snp == NULL) {\r
+    EfiStatus = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkStarted:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    EfiStatus = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    EfiStatus = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EfiStatus = gBS->CreateEvent (\r
+                    EVT_NOTIFY_WAIT,\r
+                    TPL_NOTIFY,\r
+                    &SnpWaitForPacketNotify,\r
+                    snp,\r
+                    &snp->snp.WaitForPacket\r
+                    );\r
+\r
+  if (EFI_ERROR (EfiStatus)) {\r
+    snp->snp.WaitForPacket = NULL;\r
+    EfiStatus = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  //\r
+  //\r
+  snp->mode.MCastFilterCount      = 0;\r
+  snp->mode.ReceiveFilterSetting  = 0;\r
+  ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);\r
+  CopyMem (\r
+    &snp->mode.CurrentAddress,\r
+    &snp->mode.PermanentAddress,\r
+    sizeof (EFI_MAC_ADDRESS)\r
+    );\r
+\r
+  //\r
+  // Compute tx/rx buffer sizes based on UNDI init info and parameters.\r
+  //\r
+  snp->tx_rx_bufsize = (UINT32) (snp->init_info.MemoryRequired + extra_rx_buffer_size + extra_tx_buffer_size);\r
+\r
+  if (snp->mode.MediaPresentSupported) {\r
+    if (pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {\r
+      snp->mode.MediaPresent = TRUE;\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  snp->mode.MediaPresent  = FALSE;\r
+\r
+  EfiStatus               = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
+\r
+  if (EFI_ERROR (EfiStatus)) {\r
+    gBS->CloseEvent (snp->snp.WaitForPacket);\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EfiStatus;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c b/MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c
new file mode 100644 (file)
index 0000000..91b5e02
--- /dev/null
@@ -0,0 +1,165 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  mcast_ip_to_mac.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-17 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+/**\r
+  this routine calls undi to convert an multicast IP address to a MAC address\r
+\r
+  @param  snp   pointer to snp driver structure\r
+  @param  IPv6  flag to indicate if this is an ipv6 address\r
+  @param  IP    multicast IP address\r
+  @param  MAC   pointer to hold the return MAC address\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_ip2mac (\r
+  IN SNP_DRIVER          *snp,\r
+  IN BOOLEAN             IPv6,\r
+  IN EFI_IP_ADDRESS      *IP,\r
+  IN OUT EFI_MAC_ADDRESS *MAC\r
+  )\r
+{\r
+  PXE_CPB_MCAST_IP_TO_MAC *cpb;\r
+  PXE_DB_MCAST_IP_TO_MAC  *db;\r
+\r
+  cpb                 = snp->cpb;\r
+  db                  = snp->db;\r
+  snp->cdb.OpCode     = PXE_OPCODE_MCAST_IP_TO_MAC;\r
+  snp->cdb.OpFlags    = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC);\r
+  snp->cdb.CPBsize    = sizeof (PXE_CPB_MCAST_IP_TO_MAC);\r
+  snp->cdb.DBsize     = sizeof (PXE_DB_MCAST_IP_TO_MAC);\r
+\r
+  snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  CopyMem (&cpb->IP, IP, sizeof (PXE_IP_ADDR));\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.mcast_ip_to_mac()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  switch (snp->cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    break;\r
+\r
+  case PXE_STATCODE_INVALID_CPB:\r
+    return EFI_INVALID_PARAMETER;\r
+\r
+  case PXE_STATCODE_UNSUPPORTED:\r
+    DEBUG (\r
+      (EFI_D_NET,\r
+      "\nsnp->undi.mcast_ip_to_mac()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+    return EFI_UNSUPPORTED;\r
+\r
+  default:\r
+    //\r
+    // UNDI command failed.  Return EFI_DEVICE_ERROR\r
+    // to caller.\r
+    //\r
+    DEBUG (\r
+      (EFI_D_NET,\r
+      "\nsnp->undi.mcast_ip_to_mac()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CopyMem (MAC, &db->MAC, sizeof (PXE_MAC_ADDR));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for converting a multicast IP address to\r
+  a MAC address.\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_ip2mac routine to actually do the conversion\r
+\r
+  @param  this  context pointer\r
+  @param  IPv6  flag to indicate if this is an ipv6 address\r
+  @param  IP    multicast IP address\r
+  @param  MAC   pointer to hold the return MAC address\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_mcast_ip_to_mac (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+  IN BOOLEAN                     IPv6,\r
+  IN EFI_IP_ADDRESS              *IP,\r
+  OUT EFI_MAC_ADDRESS            *MAC\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Get pointer to SNP driver instance for *this.\r
+  //\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IP == NULL || MAC == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = pxe_ip2mac (snp, IPv6, IP, MAC);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/nvdata.c b/MdeModulePkg/Universal/Network/SnpDxe/nvdata.c
new file mode 100644 (file)
index 0000000..531a4d6
--- /dev/null
@@ -0,0 +1,185 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  nvdata.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-03 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "snp.h"\r
+\r
+\r
+/**\r
+  This routine calls Undi to read the desired number of eeprom bytes.\r
+\r
+  @param  snp          pointer to the snp driver structure\r
+  @param  RegOffset    eeprom register value relative to the base address\r
+  @param  NumBytes     number of bytes to read\r
+  @param  BufferPtr    pointer where to read into\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_nvdata_read (\r
+  IN SNP_DRIVER *snp,\r
+  IN UINTN      RegOffset,\r
+  IN UINTN      NumBytes,\r
+  IN OUT VOID   *BufferPtr\r
+  )\r
+{\r
+  PXE_DB_NVDATA *db;\r
+\r
+  db                  = snp->db;\r
+  snp->cdb.OpCode     = PXE_OPCODE_NVDATA;\r
+\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NVDATA_READ;\r
+\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+\r
+  snp->cdb.DBsize     = sizeof (PXE_DB_NVDATA);\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata ()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  switch (snp->cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    break;\r
+\r
+  case PXE_STATCODE_UNSUPPORTED:\r
+    DEBUG (\r
+      (EFI_D_NET,\r
+      "\nsnp->undi.nvdata()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_UNSUPPORTED;\r
+\r
+  default:\r
+    DEBUG (\r
+      (EFI_D_NET,\r
+      "\nsnp->undi.nvdata()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CopyMem (BufferPtr, db->Data.Byte + RegOffset, NumBytes);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is an interface call provided by SNP.\r
+  It does the basic checking on the input parameters and retrieves snp structure\r
+  and then calls the read_nvdata() call which does the actual reading\r
+\r
+  @param  this         context pointer\r
+  @param  ReadOrWrite  true for reading and false for writing\r
+  @param  RegOffset    eeprom register relative to the base\r
+  @param  NumBytes     how many bytes to read\r
+  @param  BufferPtr    address of memory to read into\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_nvdata (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+  IN BOOLEAN                     ReadOrWrite,\r
+  IN UINTN                       RegOffset,\r
+  IN UINTN                       NumBytes,\r
+  IN OUT VOID                    *BufferPtr\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Get pointer to SNP driver instance for *this.\r
+  //\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  //\r
+  // Return error if the SNP is not initialized.\r
+  //\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Return error if non-volatile memory variables are not valid.\r
+  //\r
+  if (snp->mode.NvRamSize == 0 || snp->mode.NvRamAccessSize == 0) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Check for invalid parameter combinations.\r
+  //\r
+  if ((NumBytes == 0) ||\r
+      (BufferPtr == NULL) ||\r
+      (RegOffset >= snp->mode.NvRamSize) ||\r
+      (RegOffset + NumBytes > snp->mode.NvRamSize) ||\r
+      (NumBytes % snp->mode.NvRamAccessSize != 0) ||\r
+      (RegOffset % snp->mode.NvRamAccessSize != 0)\r
+      ) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // check the implementation flags of undi if we can write the nvdata!\r
+  //\r
+  if (!ReadOrWrite) {\r
+    Status = EFI_UNSUPPORTED;\r
+  } else {\r
+    Status = pxe_nvdata_read (snp, RegOffset, NumBytes, BufferPtr);\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/receive.c b/MdeModulePkg/Universal/Network/SnpDxe/receive.c
new file mode 100644 (file)
index 0000000..64ca256
--- /dev/null
@@ -0,0 +1,255 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+    receive.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+    2000-Feb-03 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+/**\r
+  this routine calls undi to receive a packet and fills in the data in the\r
+  input pointers!\r
+\r
+  @param  snp                 pointer to snp driver structure\r
+  @param  BufferPtr           pointer to the memory for the received data\r
+  @param  BuffSizePtr         is a pointer to the length of the buffer on entry and\r
+                              contains the length of the received data on return\r
+  @param  HeaderSizePtr       pointer to the header portion of the data received.\r
+  @param  SourceAddrPtr       optional parameter, is a pointer to contain the\r
+                              source ethernet address on return\r
+  @param  DestinationAddrPtr  optional parameter, is a pointer to contain the\r
+                              destination ethernet address on return\r
+  @param  ProtocolPtr         optional parameter, is a pointer to contain the\r
+                              protocol type from the ethernet header on return\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_receive (\r
+  SNP_DRIVER      *snp,\r
+  VOID            *BufferPtr,\r
+  UINTN           *BuffSizePtr,\r
+  UINTN           *HeaderSizePtr,\r
+  EFI_MAC_ADDRESS *SourceAddrPtr,\r
+  EFI_MAC_ADDRESS *DestinationAddrPtr,\r
+  UINT16          *ProtocolPtr\r
+  )\r
+{\r
+  PXE_CPB_RECEIVE *cpb;\r
+  PXE_DB_RECEIVE  *db;\r
+  UINTN           buf_size;\r
+  UINT64          TempData;\r
+\r
+  cpb       = snp->cpb;\r
+  db        = snp->db;\r
+  buf_size  = *BuffSizePtr;\r
+  //\r
+  // IMPORTANT NOTE:\r
+  // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB,\r
+  // DO NOT call the map function on the given buffer, instead use\r
+  // a global buffer. The reason is that UNDI3.0 has some unnecessary check of\r
+  // making sure that all the addresses (whether or not they will be given\r
+  // to the NIC ) supplied to it are below 4GB. It may or may not use\r
+  // the mapped address after all (like in case of CPB and DB)!\r
+  // Instead of using the global buffer whose address is allocated within the\r
+  // 2GB limit if I start mapping the given buffer we lose the data, here is\r
+  // why!!!\r
+  // if our address is > 4GB, the map call creates another buffer below 2GB and\r
+  // copies data to/from the original buffer to the mapped buffer either at\r
+  // map time or unmap time depending on the map direction.\r
+  // UNDI will not complain since we already mapped the buffer to be\r
+  // within the 2GB limit but will not use (I know undi) the mapped address\r
+  // since it does not give the user buffers to the NIC's receive unit,\r
+  // It just copies the received packet into the user buffer using the virtual\r
+  // (CPU) address rather than the mapped (device or physical) address.\r
+  // When the UNDI call returns, if we then unmap the buffer, we will lose\r
+  // the contents because unmap copies the contents of the mapped buffer into\r
+  // the original buffer (since the direction is FROM_DEVICE) !!!\r
+  //\r
+  // this is not a problem in Undi 3.1 because this undi uses it's map callback\r
+  // routine to map a cpu address to device address and it does it only if\r
+  // it is giving the address to the device and unmaps it before using the cpu\r
+  // address!\r
+  //\r
+  TempData = (UINT64) (UINTN) BufferPtr;\r
+  if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+    cpb->BufferAddr = (UINT64)(UINTN) snp->receive_buf;\r
+    cpb->BufferLen  = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+  } else {\r
+    cpb->BufferAddr = (UINT64)(UINTN) BufferPtr;\r
+    cpb->BufferLen  = (UINT32) *BuffSizePtr;\r
+  }\r
+\r
+  cpb->reserved       = 0;\r
+\r
+  snp->cdb.OpCode     = PXE_OPCODE_RECEIVE;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+\r
+  snp->cdb.CPBsize    = sizeof (PXE_CPB_RECEIVE);\r
+  snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
+\r
+  snp->cdb.DBsize     = sizeof (PXE_DB_RECEIVE);\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_INFO, "\nsnp->undi.receive ()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  switch (snp->cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    break;\r
+\r
+  case PXE_STATCODE_NO_DATA:\r
+    DEBUG (\r
+      (EFI_D_INFO,\r
+      "\nsnp->undi.receive ()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_NOT_READY;\r
+\r
+  default:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.receive()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  *BuffSizePtr = db->FrameLen;\r
+\r
+  if (HeaderSizePtr != NULL) {\r
+    *HeaderSizePtr = db->MediaHeaderLen;\r
+  }\r
+\r
+  if (SourceAddrPtr != NULL) {\r
+    CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize);\r
+  }\r
+\r
+  if (DestinationAddrPtr != NULL) {\r
+    CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize);\r
+  }\r
+\r
+  if (ProtocolPtr != NULL) {\r
+    *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /*  we need to do the byte swapping */\r
+  }\r
+\r
+  TempData = (UINT64) (UINTN) BufferPtr;\r
+  if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+    CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+  }\r
+\r
+  return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for receiving network data.\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_receive routine to actually do the receive!\r
+\r
+  @param  this                context pointer\r
+  @param  HeaderSizePtr       optional parameter and is a pointer to the header\r
+                              portion of the data received.\r
+  @param  BuffSizePtr         is a pointer to the length of the buffer on entry and\r
+                              contains the length of the received data on return\r
+  @param  BufferPtr           pointer to the memory for the received data\r
+  @param  SourceAddrPtr       optional parameter, is a pointer to contain the\r
+                              source ethernet address on return\r
+  @param  DestinationAddrPtr  optional parameter, is a pointer to contain the\r
+                              destination ethernet address on return\r
+  @param  ProtocolPtr         optional parameter, is a pointer to contain the\r
+                              protocol type from the ethernet header on return\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_receive (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+  OUT UINTN                      *HeaderSizePtr OPTIONAL,\r
+  IN OUT UINTN                   *BuffSizePtr,\r
+  OUT VOID                       *BufferPtr,\r
+  OUT EFI_MAC_ADDRESS            * SourceAddrPtr OPTIONAL,\r
+  OUT EFI_MAC_ADDRESS            * DestinationAddrPtr OPTIONAL,\r
+  OUT UINT16                     *ProtocolPtr OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+  EFI_STATUS  Status;\r
+\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (!snp->mode.ReceiveFilterSetting) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = pxe_receive (\r
+             snp,\r
+             BufferPtr,\r
+             BuffSizePtr,\r
+             HeaderSizePtr,\r
+             SourceAddrPtr,\r
+             DestinationAddrPtr,\r
+             ProtocolPtr\r
+             );\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c b/MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c
new file mode 100644 (file)
index 0000000..3886d20
--- /dev/null
@@ -0,0 +1,406 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  receive_filters.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-17 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "Snp.h"\r
+\r
+/**\r
+  this routine calls undi to enable the receive filters.\r
+\r
+  @param  snp                pointer to snp driver structure\r
+  @param  EnableFlags        bit mask for enabling the receive filters\r
+  @param  MCastAddressCount  multicast address count for a new multicast address\r
+                             list\r
+  @param  MCastAddressList   list of new multicast addresses\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_rcvfilter_enable (\r
+  SNP_DRIVER      *snp,\r
+  UINT32          EnableFlags,\r
+  UINTN           MCastAddressCount,\r
+  EFI_MAC_ADDRESS *MCastAddressList\r
+  )\r
+{\r
+  snp->cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;\r
+  }\r
+\r
+  if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;\r
+  }\r
+\r
+  if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;\r
+  }\r
+\r
+  if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;\r
+  }\r
+\r
+  if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;\r
+  }\r
+\r
+  if (MCastAddressCount != 0) {\r
+    snp->cdb.CPBsize  = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));\r
+    snp->cdb.CPBaddr  = (UINT64)(UINTN) snp->cpb;\r
+    CopyMem (snp->cpb, MCastAddressList, snp->cdb.CPBsize);\r
+  }\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+    //\r
+    // UNDI command failed.  Return UNDI status to caller.\r
+    //\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.receive_filters()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    switch (snp->cdb.StatCode) {\r
+    case PXE_STATCODE_INVALID_CDB:\r
+    case PXE_STATCODE_INVALID_CPB:\r
+    case PXE_STATCODE_INVALID_PARAMETER:\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    case PXE_STATCODE_UNSUPPORTED:\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  this routine calls undi to disable the receive filters.\r
+\r
+  @param  snp                pointer to snp driver structure\r
+  @param  DisableFlags       bit mask for disabling the receive filters\r
+  @param  ResetMCastList     boolean flag to reset/delete the multicast filter list\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_rcvfilter_disable (\r
+  SNP_DRIVER *snp,\r
+  UINT32     DisableFlags,\r
+  BOOLEAN    ResetMCastList\r
+  )\r
+{\r
+  snp->cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  snp->cdb.OpFlags    = (UINT16) (DisableFlags ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);\r
+\r
+  if (ResetMCastList) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;\r
+  }\r
+\r
+  if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;\r
+  }\r
+\r
+  if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;\r
+  }\r
+\r
+  if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;\r
+  }\r
+\r
+  if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;\r
+  }\r
+\r
+  if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+    snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;\r
+  }\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+    //\r
+    // UNDI command failed.  Return UNDI status to caller.\r
+    //\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.receive_filters()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  this routine calls undi to read the receive filters.\r
+\r
+  @param  snp                pointer to snp driver structure\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_rcvfilter_read (\r
+  SNP_DRIVER *snp\r
+  )\r
+{\r
+  snp->cdb.OpCode   = PXE_OPCODE_RECEIVE_FILTERS;\r
+  snp->cdb.OpFlags  = PXE_OPFLAGS_RECEIVE_FILTER_READ;\r
+  snp->cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize   = (UINT16) (snp->mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));\r
+  snp->cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;\r
+  if (snp->cdb.DBsize == 0) {\r
+    snp->cdb.DBaddr = (UINT64)(UINTN) NULL;\r
+  } else {\r
+    snp->cdb.DBaddr = (UINT64)(UINTN) snp->db;\r
+    ZeroMem (snp->db, snp->cdb.DBsize);\r
+  }\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+    //\r
+    // UNDI command failed.  Return UNDI status to caller.\r
+    //\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.receive_filters()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Convert UNDI32 StatFlags to EFI SNP filter flags.\r
+  //\r
+  snp->mode.ReceiveFilterSetting = 0;\r
+\r
+  if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {\r
+    snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+  }\r
+\r
+  if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {\r
+    snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+  }\r
+\r
+  if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {\r
+    snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+  }\r
+\r
+  if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {\r
+    snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+  }\r
+\r
+  if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {\r
+    snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+  }\r
+\r
+  CopyMem (snp->mode.MCastFilter, snp->db, snp->cdb.DBsize);\r
+\r
+  //\r
+  // Count number of active entries in multicast filter list.\r
+  //\r
+  {\r
+    EFI_MAC_ADDRESS ZeroMacAddr;\r
+\r
+    SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);\r
+\r
+    for (snp->mode.MCastFilterCount = 0;\r
+         snp->mode.MCastFilterCount < snp->mode.MaxMCastFilterCount;\r
+         snp->mode.MCastFilterCount++\r
+        ) {\r
+      if (CompareMem (\r
+            &snp->mode.MCastFilter[snp->mode.MCastFilterCount],\r
+            &ZeroMacAddr,\r
+            sizeof ZeroMacAddr\r
+            ) == 0) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for reading/enabling/disabling the\r
+  receive filters.\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  checks the parameter validity, calls one of the above routines to actually\r
+  do the work\r
+\r
+  @param  this               context pointer\r
+  @param  EnableFlags        bit mask for enabling the receive filters\r
+  @param  DisableFlags       bit mask for disabling the receive filters\r
+  @param  ResetMCastList     boolean flag to reset/delete the multicast filter list\r
+  @param  MCastAddressCount  multicast address count for a new multicast address\r
+                             list\r
+  @param  MCastAddressList   list of new multicast addresses\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_receive_filters (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+  IN UINT32                      EnableFlags,\r
+  IN UINT32                      DisableFlags,\r
+  IN BOOLEAN                     ResetMCastList,\r
+  IN UINTN                       MCastAddressCount OPTIONAL,\r
+  IN EFI_MAC_ADDRESS             * MCastAddressList OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_STATUS  Status;\r
+  EFI_TPL     OldTpl;\r
+\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // check if we are asked to enable or disable something that the UNDI\r
+  // does not even support!\r
+  //\r
+  if (((EnableFlags &~snp->mode.ReceiveFilterMask) != 0) ||\r
+    ((DisableFlags &~snp->mode.ReceiveFilterMask) != 0)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (ResetMCastList) {\r
+\r
+    DisableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & snp->mode.ReceiveFilterMask;\r
+    MCastAddressCount = 0;\r
+    MCastAddressList  = NULL;\r
+  } else {\r
+    if (MCastAddressCount != 0) {\r
+      if ((MCastAddressCount > snp->mode.MaxMCastFilterCount) ||\r
+        (MCastAddressList == NULL)) {\r
+\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (EnableFlags == 0 && DisableFlags == 0 && !ResetMCastList && MCastAddressCount == 0) {\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastAddressCount == 0) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if ((EnableFlags != 0) || (MCastAddressCount != 0)) {\r
+    Status = pxe_rcvfilter_enable (\r
+              snp,\r
+              EnableFlags,\r
+              MCastAddressCount,\r
+              MCastAddressList\r
+              );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  if ((DisableFlags != 0) || ResetMCastList) {\r
+    Status = pxe_rcvfilter_disable (snp, DisableFlags, ResetMCastList);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  Status = pxe_rcvfilter_read (snp);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/reset.c b/MdeModulePkg/Universal/Network/SnpDxe/reset.c
new file mode 100644 (file)
index 0000000..0a08032
--- /dev/null
@@ -0,0 +1,128 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  reset.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-09 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  This routine calls undi to reset the nic.\r
+\r
+  @param  snp                   pointer to the snp driver structure\r
+\r
+  @return EFI_SUCCESSFUL for a successful completion\r
+  @return other for failed calls\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_reset (\r
+  SNP_DRIVER *snp\r
+  )\r
+{\r
+  snp->cdb.OpCode     = PXE_OPCODE_RESET;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.reset()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    DEBUG (\r
+      (EFI_D_WARN,\r
+      "\nsnp->undi32.reset()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    //\r
+    // UNDI could not be reset. Return UNDI error.\r
+    //\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for resetting the NIC\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_reset routine to actually do the reset!\r
+\r
+  @param  this                  context pointer\r
+  @param  ExtendedVerification  not implemented\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_reset (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+  IN BOOLEAN                     ExtendedVerification\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Resolve Warning 4 unreferenced parameter problem\r
+  //\r
+  ExtendedVerification = 0;\r
+\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = pxe_reset (snp);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/shutdown.c b/MdeModulePkg/Universal/Network/SnpDxe/shutdown.c
new file mode 100644 (file)
index 0000000..8e0ae45
--- /dev/null
@@ -0,0 +1,148 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  shutdown.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-14 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  this routine calls undi to shut down the interface.\r
+\r
+  @param  snp   pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_shutdown (\r
+  IN SNP_DRIVER *snp\r
+  )\r
+{\r
+  snp->cdb.OpCode     = PXE_OPCODE_SHUTDOWN;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    //\r
+    // UNDI could not be shutdown. Return UNDI error.\r
+    //\r
+    DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown()  %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Free allocated memory.\r
+  //\r
+  if (snp->tx_rx_buffer != NULL) {\r
+    snp->IoFncs->FreeBuffer (\r
+                  snp->IoFncs,\r
+                  SNP_MEM_PAGES (snp->tx_rx_bufsize),\r
+                  (VOID *) snp->tx_rx_buffer\r
+                  );\r
+  }\r
+\r
+  snp->tx_rx_buffer   = NULL;\r
+  snp->tx_rx_bufsize  = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for shutting down the interface\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_shutdown routine to actually do the undi shutdown\r
+\r
+  @param  this  context pointer\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_shutdown (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_STATUS  Status;\r
+  EFI_TPL     OldTpl;\r
+\r
+  //\r
+  //\r
+  //\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  //\r
+  //\r
+  //\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  //\r
+  //\r
+  Status                          = pxe_shutdown (snp);\r
+\r
+  snp->mode.State                 = EfiSimpleNetworkStarted;\r
+  snp->mode.ReceiveFilterSetting  = 0;\r
+\r
+  snp->mode.MCastFilterCount      = 0;\r
+  snp->mode.ReceiveFilterSetting  = 0;\r
+  ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);\r
+  CopyMem (\r
+    &snp->mode.CurrentAddress,\r
+    &snp->mode.PermanentAddress,\r
+    sizeof (EFI_MAC_ADDRESS)\r
+    );\r
+\r
+  gBS->CloseEvent (snp->snp.WaitForPacket);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/snp.c b/MdeModulePkg/Universal/Network/SnpDxe/snp.c
new file mode 100644 (file)
index 0000000..460cdfd
--- /dev/null
@@ -0,0 +1,1269 @@
+/** @file\r
+Copyright (c) 2004 - 2005, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+    snp.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+EFI_STATUS\r
+pxe_start (\r
+  SNP_DRIVER *snp\r
+  );\r
+EFI_STATUS\r
+pxe_stop (\r
+  SNP_DRIVER *snp\r
+  );\r
+EFI_STATUS\r
+pxe_init (\r
+  SNP_DRIVER *snp,\r
+  UINT16     OpFlags\r
+  );\r
+EFI_STATUS\r
+pxe_shutdown (\r
+  SNP_DRIVER *snp\r
+  );\r
+EFI_STATUS\r
+pxe_get_stn_addr (\r
+  SNP_DRIVER *snp\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSnpNiiDriver (\r
+  IN EFI_HANDLE       image_handle,\r
+  IN EFI_SYSTEM_TABLE *system_table\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN EFI_HANDLE                     Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN EFI_HANDLE                     Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN  EFI_HANDLE                     Controller,\r
+  IN  UINTN                          NumberOfChildren,\r
+  IN  EFI_HANDLE                     *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// Simple Network Protocol Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {\r
+  SimpleNetworkDriverSupported,\r
+  SimpleNetworkDriverStart,\r
+  SimpleNetworkDriverStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+//  Module global variables needed to support undi 3.0 interface\r
+//\r
+EFI_PCI_IO_PROTOCOL         *mPciIoFncs;\r
+struct s_v2p                *_v2p = NULL; // undi3.0 map_list head\r
+// End Global variables\r
+//\r
+\r
+/**\r
+  This routine maps the given CPU address to a Device address. It creates a\r
+  an entry in the map list with the virtual and physical addresses and the\r
+  un map cookie.\r
+\r
+  @param  v2p                  pointer to return a map list node pointer.\r
+  @param  type                 the direction in which the data flows from the given\r
+                               virtual address device->cpu or cpu->device or both\r
+                               ways.\r
+  @param  vaddr                virtual address (or CPU address) to be mapped\r
+  @param  bsize                size of the buffer to be mapped.\r
+\r
+  @retval EFI_SUCEESS          routine has completed the mapping\r
+  @retval other                error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+add_v2p (\r
+  IN OUT struct s_v2p           **v2p,\r
+  EFI_PCI_IO_PROTOCOL_OPERATION type,\r
+  VOID                          *vaddr,\r
+  UINTN                         bsize\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *v2p = AllocatePool (sizeof (struct s_v2p));\r
+  if (*v2p != NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = mPciIoFncs->Map (\r
+                        mPciIoFncs,\r
+                        type,\r
+                        vaddr,\r
+                        &bsize,\r
+                        &(*v2p)->paddr,\r
+                        &(*v2p)->unmap\r
+                        );\r
+  if (Status != EFI_SUCCESS) {\r
+    FreePool (*v2p);\r
+    return Status;\r
+  }\r
+  (*v2p)->vaddr = vaddr;\r
+  (*v2p)->bsize = bsize;\r
+  (*v2p)->next  = _v2p;\r
+  _v2p          = *v2p;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This routine searches the linked list of mapped address nodes (for undi3.0\r
+  interface) to find the node that corresponds to the given virtual address and\r
+  returns a pointer to that node.\r
+\r
+  @param  v2p                  pointer to return a map list node pointer.\r
+  @param  vaddr                virtual address (or CPU address) to be searched in\r
+                               the map list\r
+\r
+  @retval EFI_SUCEESS          if a match found!\r
+  @retval Other                match not found\r
+\r
+**/\r
+EFI_STATUS\r
+find_v2p (\r
+  struct s_v2p **v2p,\r
+  VOID         *vaddr\r
+  )\r
+{\r
+  struct s_v2p  *v;\r
+\r
+  if (v2p == NULL || vaddr == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (v = _v2p; v != NULL; v = v->next) {\r
+    if (v->vaddr == vaddr) {\r
+      *v2p = v;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  This routine unmaps the given virtual address and frees the memory allocated\r
+  for the map list node corresponding to that address.\r
+\r
+  @param  vaddr                virtual address (or CPU address) to be unmapped\r
+\r
+  @retval EFI_SUCEESS          if successfully unmapped\r
+  @retval Other                as indicated by the error\r
+\r
+**/\r
+EFI_STATUS\r
+del_v2p (\r
+  VOID *vaddr\r
+  )\r
+{\r
+  struct s_v2p  *v;\r
+  struct s_v2p  *t;\r
+  EFI_STATUS    Status;\r
+\r
+  if (vaddr == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (_v2p == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Is our node at the head of the list??\r
+  //\r
+  if ((v = _v2p)->vaddr == vaddr) {\r
+    _v2p    = _v2p->next;\r
+\r
+    Status  = mPciIoFncs->Unmap (mPciIoFncs, v->unmap);\r
+\r
+    FreePool (v);\r
+\r
+    if (Status) {\r
+      DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  for (; v->next != NULL; v = t) {\r
+    if ((t = v->next)->vaddr == vaddr) {\r
+      v->next = t->next;\r
+      Status  = mPciIoFncs->Unmap (mPciIoFncs, t->unmap);\r
+      FreePool (t);\r
+\r
+      if (Status) {\r
+        DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));\r
+      }\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+issue_hwundi_command (\r
+  UINT64 cdb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  DEBUG ((EFI_D_ERROR, "\nissue_hwundi_command() - This should not be called!"));\r
+\r
+  if (cdb == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+\r
+  }\r
+  //\r
+  //  %%TBD - For now, nothing is done.\r
+  //\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Compute 8-bit checksum of a buffer.\r
+\r
+  @param  ptr                  Pointer to buffer.\r
+  @param  len                  Length of buffer in bytes.\r
+\r
+  @return 8-bit checksum of all bytes in buffer.\r
+  @return If ptr is NULL or len is zero, zero is returned.\r
+\r
+**/\r
+STATIC\r
+UINT8\r
+calc_8bit_cksum (\r
+  VOID  *ptr,\r
+  UINTN len\r
+  )\r
+{\r
+  UINT8 *bptr;\r
+  UINT8 cksum;\r
+\r
+  bptr  = ptr;\r
+  cksum = 0;\r
+\r
+  if (ptr == NULL || len == 0) {\r
+    return 0;\r
+  }\r
+\r
+  while (len--) {\r
+    cksum = (UINT8) (cksum +*bptr++);\r
+  }\r
+\r
+  return cksum;\r
+}\r
+\r
+\r
+/**\r
+  Test to see if this driver supports Controller. Any Controller\r
+  that contains a Nii protocol can be supported.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test.\r
+  @param  RemainingDevicePath  Not used.\r
+\r
+  @retval EFI_SUCCESS          This driver supports this device.\r
+  @retval EFI_ALREADY_STARTED  This driver is already running on this device.\r
+  @retval other                This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN EFI_HANDLE                     Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r
+  PXE_UNDI                                  *pxe;\r
+  BOOLEAN                                   IsUndi31;\r
+\r
+  IsUndi31 = FALSE;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+                  (VOID **) &NiiProtocol,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (Status == EFI_ALREADY_STARTED)\r
+  {\r
+    DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %x\n", Controller));\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status))\r
+  {\r
+    DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %x\n", Controller));\r
+    IsUndi31 = TRUE;\r
+  } else {\r
+    //\r
+    // try the older 3.0 driver\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+                    (VOID **) &NiiProtocol,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "Support(): UNDI3.0 found on handle %x\n", Controller));\r
+  }\r
+  //\r
+  // check the version, we don't want to connect to the undi16\r
+  //\r
+  if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r
+  //\r
+  if (NiiProtocol->ID & 0x0F) {\r
+    DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);\r
+\r
+  //\r
+  //  Verify !PXE revisions.\r
+  //\r
+  if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
+    DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  if (pxe->hw.Rev < PXE_ROMID_REV) {\r
+    DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
+\r
+    DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+\r
+  } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
+    DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Do S/W UNDI specific checks.\r
+  //\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
+    if (pxe->sw.EntryPoint < pxe->sw.Len) {\r
+      DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
+      Status = EFI_UNSUPPORTED;\r
+      goto Done;\r
+    }\r
+\r
+    if (pxe->sw.BusCnt == 0) {\r
+      DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
+      Status = EFI_UNSUPPORTED;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  DEBUG ((EFI_D_INFO, "Support(): supported on %x\n", Controller));\r
+\r
+Done:\r
+  if (IsUndi31) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+\r
+  } else {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  called for any handle that we said "supported" in the above call!\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to start\r
+  @param  RemainingDevicePath  Not used.\r
+\r
+  @retval EFI_SUCCESS          This driver supports this device.\r
+  @retval other                This driver failed to start this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN EFI_HANDLE                     Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
+  EFI_DEVICE_PATH_PROTOCOL                  *NiiDevicePath;\r
+  EFI_STATUS                                Status;\r
+  PXE_UNDI                                  *pxe;\r
+  SNP_DRIVER                                *snp;\r
+  VOID                                      *addr;\r
+  VOID                                      *addrUnmap;\r
+  EFI_PHYSICAL_ADDRESS                      paddr;\r
+  EFI_HANDLE                                Handle;\r
+  UINTN                                     Size;\r
+  BOOLEAN                                   UndiNew;\r
+  PXE_PCI_CONFIG_INFO                       ConfigInfo;\r
+  PCI_TYPE00                                *ConfigHeader;\r
+  UINT32                                    *TempBar;\r
+  UINT8                                     BarIndex;\r
+  PXE_STATFLAGS                             InitStatFlags;\r
+\r
+  DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier()  "));\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &NiiDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &NiiDevicePath,\r
+                  &Handle\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &mPciIoFncs,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the NII interface. look for 3.1 undi first, if it is not there\r
+  // then look for 3.0, validate the interface.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+                  (VOID **) &Nii,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiDevicePathProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+    return Status;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // probably not a 3.1 UNDI\r
+    //\r
+    UndiNew = TRUE;\r
+    DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r
+\r
+  } else {\r
+    UndiNew = FALSE;\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+                    (VOID **) &Nii,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->CloseProtocol (\r
+            Controller,\r
+            &gEfiDevicePathProtocolGuid,\r
+            This->DriverBindingHandle,\r
+            Controller\r
+            );\r
+\r
+      return Status;\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "Start(): UNDI3.0 found\n"));\r
+  }\r
+\r
+  pxe = (PXE_UNDI *) (UINTN) (Nii->ID);\r
+\r
+  if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {\r
+    DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
+    goto NiiError;\r
+  }\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
+    //\r
+    //  We can get any packets.\r
+    //\r
+  } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
+    //\r
+    //  We need to be able to get broadcast packets for DHCP.\r
+    //  If we do not have promiscuous support, we must at least have\r
+    //  broadcast support or we cannot do DHCP!\r
+    //\r
+  } else {\r
+    DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
+    goto NiiError;\r
+  }\r
+  //\r
+  // OK, we like this UNDI, and we know snp is not already there on this handle\r
+  // Allocate and initialize a new simple network protocol structure.\r
+  //\r
+  Status = mPciIoFncs->AllocateBuffer (\r
+                        mPciIoFncs,\r
+                        AllocateAnyPages,\r
+                        EfiBootServicesData,\r
+                        SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
+                        &addr,\r
+                        0\r
+                        );\r
+\r
+  if (Status != EFI_SUCCESS) {\r
+    DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
+    goto NiiError;\r
+  }\r
+\r
+  snp = (SNP_DRIVER *) (UINTN) addr;\r
+\r
+  if (!UndiNew) {\r
+    Size = SNP_MEM_PAGES (sizeof (SNP_DRIVER));\r
+\r
+    Status = mPciIoFncs->Map (\r
+                          mPciIoFncs,\r
+                          EfiPciIoOperationBusMasterCommonBuffer,\r
+                          addr,\r
+                          &Size,\r
+                          &paddr,\r
+                          &addrUnmap\r
+                          );\r
+\r
+    ASSERT (paddr);\r
+\r
+    DEBUG ((EFI_D_NET, "\nSNP_DRIVER @ %Xh, sizeof(SNP_DRIVER) == %d", addr, sizeof (SNP_DRIVER)));\r
+    snp                 = (SNP_DRIVER *) (UINTN) paddr;\r
+    snp->SnpDriverUnmap = addrUnmap;\r
+  }\r
+\r
+  ZeroMem (snp, sizeof (SNP_DRIVER));\r
+\r
+  snp->IoFncs     = mPciIoFncs;\r
+  snp->IsOldUndi  = (BOOLEAN) (!UndiNew);\r
+\r
+  snp->Signature  = SNP_DRIVER_SIGNATURE;\r
+\r
+  EfiInitializeLock (&snp->lock, TPL_NOTIFY);\r
+\r
+  snp->snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
+  snp->snp.Start          = snp_undi32_start;\r
+  snp->snp.Stop           = snp_undi32_stop;\r
+  snp->snp.Initialize     = snp_undi32_initialize;\r
+  snp->snp.Reset          = snp_undi32_reset;\r
+  snp->snp.Shutdown       = snp_undi32_shutdown;\r
+  snp->snp.ReceiveFilters = snp_undi32_receive_filters;\r
+  snp->snp.StationAddress = snp_undi32_station_address;\r
+  snp->snp.Statistics     = snp_undi32_statistics;\r
+  snp->snp.MCastIpToMac   = snp_undi32_mcast_ip_to_mac;\r
+  snp->snp.NvData         = snp_undi32_nvdata;\r
+  snp->snp.GetStatus      = snp_undi32_get_status;\r
+  snp->snp.Transmit       = snp_undi32_transmit;\r
+  snp->snp.Receive        = snp_undi32_receive;\r
+  snp->snp.WaitForPacket  = NULL;\r
+\r
+  snp->snp.Mode           = &snp->mode;\r
+\r
+  snp->tx_rx_bufsize      = 0;\r
+  snp->tx_rx_buffer       = NULL;\r
+\r
+  snp->if_num             = Nii->IfNum;\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
+    snp->is_swundi            = FALSE;\r
+    snp->issue_undi32_command = &issue_hwundi_command;\r
+  } else {\r
+    snp->is_swundi = TRUE;\r
+\r
+    if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
+      snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;\r
+    } else {\r
+      snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);\r
+    }\r
+  }\r
+  //\r
+  // Allocate a global CPB and DB buffer for this UNDI interface.\r
+  // we do this because:\r
+  //\r
+  // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
+  // within 2GB limit, create them here and map them so that when undi calls\r
+  // v2p callback to check if the physical address is < 2gb, we will pass.\r
+  //\r
+  // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
+  // simpler if we use the same cpb, db variables for both old and new undi\r
+  // interfaces from all the SNP interface calls (we don't map the buffers\r
+  // for the newer undi interfaces though)\r
+  // .\r
+  // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
+  // interface as EFI does not multi-task and so SNP will not be re-entered!\r
+  //\r
+  Status = mPciIoFncs->AllocateBuffer (\r
+                        mPciIoFncs,\r
+                        AllocateAnyPages,\r
+                        EfiBootServicesData,\r
+                        SNP_MEM_PAGES (4096),\r
+                        &addr,\r
+                        0\r
+                        );\r
+\r
+  if (Status != EFI_SUCCESS) {\r
+    DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
+    goto Error_DeleteSNP;\r
+  }\r
+\r
+  if (snp->IsOldUndi) {\r
+    Size = SNP_MEM_PAGES (4096);\r
+\r
+    Status = mPciIoFncs->Map (\r
+                          mPciIoFncs,\r
+                          EfiPciIoOperationBusMasterCommonBuffer,\r
+                          addr,\r
+                          &Size,\r
+                          &paddr,\r
+                          &snp->CpbUnmap\r
+                          );\r
+\r
+    ASSERT (paddr);\r
+\r
+    snp->cpb  = (VOID *) (UINTN) paddr;\r
+    snp->db   = (VOID *) ((UINTN) paddr + 2048);\r
+  } else {\r
+    snp->cpb  = (VOID *) (UINTN) addr;\r
+    snp->db   = (VOID *) ((UINTN) addr + 2048);\r
+  }\r
+  //\r
+  // pxe_start call is going to give the callback functions to UNDI, these callback\r
+  // functions use the BarIndex values from the snp structure, so these must be initialized\r
+  // with default values before doing a pxe_start. The correct values can be obtained after\r
+  // getting the config information from UNDI\r
+  //\r
+  snp->MemoryBarIndex = 0;\r
+  snp->IoBarIndex     = 1;\r
+\r
+  //\r
+  // we need the undi init information many times in this snp code, just get it\r
+  // once here and store it in the snp driver structure. to get Init Info\r
+  // from UNDI we have to start undi first.\r
+  //\r
+  Status = pxe_start (snp);\r
+\r
+  if (Status != EFI_SUCCESS) {\r
+    goto Error_DeleteCPBDB;\r
+  }\r
+\r
+  snp->cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_DBADDR_NOT_USED;\r
+\r
+  snp->cdb.DBsize     = sizeof snp->init_info;\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) &snp->init_info;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  //\r
+  // Save the INIT Stat Code...\r
+  //\r
+  InitStatFlags = snp->cdb.StatFlags;\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    DEBUG ((EFI_D_NET, "\nsnp->undi.init_info()  %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
+    pxe_stop (snp);\r
+    goto Error_DeleteCPBDB;\r
+  }\r
+\r
+  snp->cdb.OpCode     = PXE_OPCODE_GET_CONFIG_INFO;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_DBADDR_NOT_USED;\r
+\r
+  snp->cdb.DBsize     = sizeof ConfigInfo;\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) &ConfigInfo;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    DEBUG ((EFI_D_NET, "\nsnp->undi.config_info()  %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
+    pxe_stop (snp);\r
+    goto Error_DeleteCPBDB;\r
+  }\r
+  //\r
+  // Find the correct BAR to do IO.\r
+  //\r
+  //\r
+  // Enumerate through the PCI BARs for the device to determine which one is\r
+  // the IO BAR.  Save the index of the BAR into the adapter info structure.\r
+  // for  regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
+  //\r
+  ConfigHeader  = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r
+  TempBar       = (UINT32 *) &ConfigHeader->Device.Bar[0];\r
+  for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r
+    if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r
+      //\r
+      // This is a 64-bit memory bar, skip this and the\r
+      // next bar as well.\r
+      //\r
+      TempBar++;\r
+    }\r
+\r
+    if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r
+      snp->IoBarIndex = BarIndex;\r
+      break;\r
+    }\r
+\r
+    TempBar++;\r
+  }\r
+\r
+  //\r
+  // We allocate 2 more global buffers for undi 3.0 interface. We use these\r
+  // buffers to pass to undi when the user buffers are beyond 4GB.\r
+  // UNDI 3.0 wants all the addresses passed to it to be\r
+  // within 2GB limit, create them here and map them so that when undi calls\r
+  // v2p callback to check if the physical address is < 2gb, we will pass.\r
+  //\r
+  // For 3.1 and later UNDIs, we do not do this because undi is\r
+  // going to call the map() callback if and only if it wants to use the\r
+  // device address for any address it receives.\r
+  //\r
+  if (snp->IsOldUndi) {\r
+    //\r
+    // buffer for receive\r
+    //\r
+    Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+    Status = mPciIoFncs->AllocateBuffer (\r
+                          mPciIoFncs,\r
+                          AllocateAnyPages,\r
+                          EfiBootServicesData,\r
+                          Size,\r
+                          &addr,\r
+                          0\r
+                          );\r
+\r
+    if (Status != EFI_SUCCESS) {\r
+      DEBUG ((EFI_D_ERROR, "\nCould not allocate receive buffer.\n"));\r
+      goto Error_DeleteCPBDB;\r
+    }\r
+\r
+    Status = mPciIoFncs->Map (\r
+                          mPciIoFncs,\r
+                          EfiPciIoOperationBusMasterCommonBuffer,\r
+                          addr,\r
+                          &Size,\r
+                          &paddr,\r
+                          &snp->ReceiveBufUnmap\r
+                          );\r
+\r
+    ASSERT (paddr);\r
+\r
+    snp->receive_buf = (UINT8 *) (UINTN) paddr;\r
+\r
+    //\r
+    // buffer for fill_header\r
+    //\r
+    Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);\r
+    Status = mPciIoFncs->AllocateBuffer (\r
+                          mPciIoFncs,\r
+                          AllocateAnyPages,\r
+                          EfiBootServicesData,\r
+                          Size,\r
+                          &addr,\r
+                          0\r
+                          );\r
+\r
+    if (Status != EFI_SUCCESS) {\r
+      DEBUG ((EFI_D_ERROR, "\nCould not allocate fill_header buffer.\n"));\r
+      goto Error_DeleteRCVBuf;\r
+    }\r
+\r
+    Status = mPciIoFncs->Map (\r
+                          mPciIoFncs,\r
+                          EfiPciIoOperationBusMasterCommonBuffer,\r
+                          addr,\r
+                          &Size,\r
+                          &paddr,\r
+                          &snp->FillHdrBufUnmap\r
+                          );\r
+\r
+    ASSERT (paddr);\r
+    snp->fill_hdr_buf = (UINT8 *) (UINTN) paddr;\r
+  }\r
+  //\r
+  //  Initialize simple network protocol mode structure\r
+  //\r
+  snp->mode.State               = EfiSimpleNetworkStopped;\r
+  snp->mode.HwAddressSize       = snp->init_info.HWaddrLen;\r
+  snp->mode.MediaHeaderSize     = snp->init_info.MediaHeaderLen;\r
+  snp->mode.MaxPacketSize       = snp->init_info.FrameDataLen;\r
+  snp->mode.NvRamAccessSize     = snp->init_info.NvWidth;\r
+  snp->mode.NvRamSize           = snp->init_info.NvCount * snp->mode.NvRamAccessSize;\r
+  snp->mode.IfType              = snp->init_info.IFtype;\r
+  snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;\r
+  snp->mode.MCastFilterCount    = 0;\r
+\r
+  switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
+  case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
+    snp->mode.MediaPresentSupported = TRUE;\r
+    break;\r
+\r
+  case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
+  default:\r
+    snp->mode.MediaPresentSupported = FALSE;\r
+  }\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
+    snp->mode.MacAddressChangeable = TRUE;\r
+  } else {\r
+    snp->mode.MacAddressChangeable = FALSE;\r
+  }\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
+    snp->mode.MultipleTxSupported = TRUE;\r
+  } else {\r
+    snp->mode.MultipleTxSupported = FALSE;\r
+  }\r
+\r
+  snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
+    snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+\r
+  }\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
+    snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+\r
+  }\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
+    snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+\r
+  }\r
+\r
+  if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
+    snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+\r
+  }\r
+\r
+  if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {\r
+    snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+\r
+  }\r
+\r
+  snp->mode.ReceiveFilterSetting = 0;\r
+\r
+  //\r
+  //  need to get the station address to save in the mode structure. we need to\r
+  // initialize the UNDI first for this.\r
+  //\r
+  snp->tx_rx_bufsize  = snp->init_info.MemoryRequired;\r
+  Status              = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
+\r
+  if (Status) {\r
+    pxe_stop (snp);\r
+    goto Error_DeleteHdrBuf;\r
+  }\r
+\r
+  Status = pxe_get_stn_addr (snp);\r
+\r
+  if (Status != EFI_SUCCESS) {\r
+    DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr()  failed.\n"));\r
+    pxe_shutdown (snp);\r
+    pxe_stop (snp);\r
+    goto Error_DeleteHdrBuf;\r
+  }\r
+\r
+  snp->mode.MediaPresent = FALSE;\r
+\r
+  //\r
+  // We should not leave UNDI started and initialized here. this DriverStart()\r
+  // routine must only find and attach the SNP interface to UNDI layer that it\r
+  // finds on the given handle!\r
+  // The UNDI layer will be started when upper layers call snp->start.\r
+  // How ever, this DriverStart() must fill up the snp mode structure which\r
+  // contains the MAC address of the NIC. For this reason we started and\r
+  // initialized UNDI here, now we are done, do a shutdown and stop of the\r
+  // UNDI interface!\r
+  //\r
+  pxe_shutdown (snp);\r
+  pxe_stop (snp);\r
+\r
+  //\r
+  //  add SNP to the undi handle\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &(snp->snp)\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+Error_DeleteHdrBuf:\r
+  if (snp->IsOldUndi) {\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          snp->FillHdrBufUnmap\r
+                          );\r
+    Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);\r
+    mPciIoFncs->FreeBuffer (\r
+                  mPciIoFncs,\r
+                  Size,\r
+                  snp->fill_hdr_buf\r
+                  );\r
+  }\r
+\r
+Error_DeleteRCVBuf:\r
+  if (snp->IsOldUndi) {\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          snp->ReceiveBufUnmap\r
+                          );\r
+    Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+    mPciIoFncs->FreeBuffer (\r
+                  mPciIoFncs,\r
+                  Size,\r
+                  snp->receive_buf\r
+                  );\r
+\r
+  }\r
+\r
+Error_DeleteCPBDB:\r
+  if (snp->IsOldUndi) {\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          snp->CpbUnmap\r
+                          );\r
+  }\r
+\r
+  Status = mPciIoFncs->FreeBuffer (\r
+                        mPciIoFncs,\r
+                        SNP_MEM_PAGES (4096),\r
+                        snp->cpb\r
+                        );\r
+\r
+Error_DeleteSNP:\r
+  if (snp->IsOldUndi) {\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          snp->SnpDriverUnmap\r
+                          );\r
+  }\r
+\r
+  mPciIoFncs->FreeBuffer (\r
+                mPciIoFncs,\r
+                SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
+                snp\r
+                );\r
+NiiError:\r
+  if (!UndiNew) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  } else {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiDevicePathProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN  EFI_HANDLE                     Controller,\r
+  IN  UINTN                          NumberOfChildren,\r
+  IN  EFI_HANDLE                     *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
+  SNP_DRIVER                  *Snp;\r
+\r
+  //\r
+  // Get our context back.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  (VOID **) &SnpProtocol,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  &Snp->snp\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!Snp->IsOldUndi) {\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+  } else {\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+  }\r
+\r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+\r
+  pxe_shutdown (Snp);\r
+  pxe_stop (Snp);\r
+\r
+  if (Snp->IsOldUndi) {\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          Snp->FillHdrBufUnmap\r
+                          );\r
+\r
+    mPciIoFncs->FreeBuffer (\r
+                  mPciIoFncs,\r
+                  SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen),\r
+                  Snp->fill_hdr_buf\r
+                  );\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          Snp->ReceiveBufUnmap\r
+                          );\r
+\r
+    mPciIoFncs->FreeBuffer (\r
+                  mPciIoFncs,\r
+                  SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen + Snp->init_info.FrameDataLen),\r
+                  Snp->receive_buf\r
+                  );\r
+\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          Snp->CpbUnmap\r
+                          );\r
+    Status = mPciIoFncs->Unmap (\r
+                          mPciIoFncs,\r
+                          Snp->SnpDriverUnmap\r
+                          );\r
+  }\r
+\r
+  mPciIoFncs->FreeBuffer (\r
+                mPciIoFncs,\r
+                SNP_MEM_PAGES (4096),\r
+                Snp->cpb\r
+                );\r
+\r
+  mPciIoFncs->FreeBuffer (\r
+                mPciIoFncs,\r
+                SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
+                Snp\r
+                );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Install all the driver protocol\r
+\r
+  @param  entry                EFI_IMAGE_ENTRY_POINT)\r
+\r
+  @retval EFI_SUCEESS          Initialization routine has found UNDI hardware,\r
+                               loaded it's ROM, and installed a notify event for\r
+                               the Network Indentifier Interface Protocol\r
+                               successfully.\r
+  @retval Other                Return value from HandleProtocol for\r
+                               DeviceIoProtocol or LoadedImageProtocol\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSnpNiiDriver (\r
+  IN EFI_HANDLE       ImageHandle,\r
+  IN EFI_SYSTEM_TABLE *SystemTable\r
+  )\r
+{\r
+  return EfiLibInstallAllDriverProtocols (\r
+          ImageHandle,\r
+          SystemTable,\r
+          &mSimpleNetworkDriverBinding,\r
+          NULL,\r
+          COMPONENT_NAME,\r
+          NULL,\r
+          NULL\r
+          );\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/snp.h b/MdeModulePkg/Universal/Network/SnpDxe/snp.h
new file mode 100644 (file)
index 0000000..624a44c
--- /dev/null
@@ -0,0 +1,454 @@
+/** @file
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+    snp.h
+
+Abstract:
+
+Revision history:
+
+
+**/
+#ifndef _SNP_H
+#define _SNP_H
+
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SimpleNetwork.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/NetworkInterfaceIdentifier.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#define FOUR_GIGABYTES  (UINT64) 0x100000000ULL
+
+//
+// Driver Consumed Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_DEFINITION (DevicePath)
+//@MT:#include EFI_PROTOCOL_DEFINITION (PciIo)
+//@MT:#include EFI_PROTOCOL_DEFINITION (EfiNetworkInterfaceIdentifier)
+
+//
+// Driver Produced Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_DEFINITION (DriverBinding)
+//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName)
+//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName2)
+//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleNetwork)
+
+#define SNP_DRIVER_SIGNATURE  EFI_SIGNATURE_32 ('s', 'n', 'd', 's')
+#define MAX_MAP_LENGTH        100
+
+#define PCI_BAR_IO_MASK       0x00000003
+#define PCI_BAR_IO_MODE       0x00000001
+
+#define PCI_BAR_MEM_MASK      0x0000000F
+#define PCI_BAR_MEM_MODE      0x00000000
+#define PCI_BAR_MEM_64BIT     0x00000004
+
+typedef struct {
+  UINT32                      Signature;
+  EFI_LOCK                    lock;
+
+  EFI_SIMPLE_NETWORK_PROTOCOL snp;
+  EFI_SIMPLE_NETWORK_MODE     mode;
+
+  EFI_HANDLE                  device_handle;
+  EFI_DEVICE_PATH_PROTOCOL    *device_path;
+
+  //
+  //  Local instance data needed by SNP driver
+  //
+  //  Pointer to S/W UNDI API entry point
+  //  This will be NULL for H/W UNDI
+  //
+  EFI_STATUS (*issue_undi32_command) (UINT64 cdb);
+
+  BOOLEAN               is_swundi;
+
+  //
+  // undi interface number, if one undi manages more nics
+  //
+  PXE_IFNUM             if_num;
+
+  //
+  //  Allocated tx/rx buffer that was passed to UNDI Initialize.
+  //
+  UINT32                tx_rx_bufsize;
+  VOID                  *tx_rx_buffer;
+  //
+  // mappable buffers for receive and fill header for undi3.0
+  // these will be used if the user buffers are above 4GB limit (instead of
+  // mapping the user buffers)
+  //
+  UINT8                 *receive_buf;
+  VOID                  *ReceiveBufUnmap;
+  UINT8                 *fill_hdr_buf;
+  VOID                  *FillHdrBufUnmap;
+
+  EFI_PCI_IO_PROTOCOL   *IoFncs;
+  UINT8                 IoBarIndex;
+  UINT8                 MemoryBarIndex;
+  BOOLEAN               IsOldUndi;  // true for EFI1.0 UNDI (3.0) drivers
+  //
+  // Buffers for command descriptor block, command parameter block
+  // and data block.
+  //
+  PXE_CDB               cdb;
+  VOID                  *cpb;
+  VOID                  *CpbUnmap;
+  VOID                  *db;
+
+  //
+  // UNDI structure, we need to remember the init info for a long time!
+  //
+  PXE_DB_GET_INIT_INFO  init_info;
+
+  VOID                  *SnpDriverUnmap;
+  //
+  // when ever we map an address, we must remember it's address and the un-map
+  // cookie so that we can unmap later
+  //
+  struct s_map_list {
+    EFI_PHYSICAL_ADDRESS  virt;
+    VOID                  *map_cookie;
+  } map_list[MAX_MAP_LENGTH];
+}
+SNP_DRIVER;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, snp, SNP_DRIVER_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL   gSimpleNetworkComponentName;
+
+//
+//  Virtual to physical mapping for all UNDI 3.0s.
+//
+extern struct                       s_v2p {
+  struct s_v2p          *next;
+  VOID                  *vaddr;
+  UINTN                 bsize;
+  EFI_PHYSICAL_ADDRESS  paddr;
+  VOID                  *unmap;
+}
+*_v2p;
+
+EFI_STATUS
+add_v2p (
+  struct s_v2p                  **v2p,
+  EFI_PCI_IO_PROTOCOL_OPERATION type,
+  VOID                          *vaddr,
+  UINTN                         bsize
+  )
+;
+
+EFI_STATUS
+find_v2p (
+  struct s_v2p **v2p,
+  VOID         *vaddr
+  )
+;
+
+EFI_STATUS
+del_v2p (
+  VOID *vaddr
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_block_30 (
+  IN UINT32 Enable
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_delay_30 (
+  IN UINT64 MicroSeconds
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_memio_30 (
+  IN UINT8      ReadOrWrite,
+  IN UINT8      NumBytes,
+  IN UINT64     MemOrPortAddress,
+  IN OUT UINT64 BufferPtr
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_v2p_30 (
+  IN UINT64     CpuAddr,
+  IN OUT UINT64 DeviceAddrPtr
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_block (
+  IN UINT64 UniqueId,
+  IN UINT32 Enable
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_delay (
+  IN UINT64 UniqueId,
+  IN UINT64 MicroSeconds
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_memio (
+  IN UINT64     UniqueId,
+  IN UINT8      ReadOrWrite,
+  IN UINT8      NumBytes,
+  IN UINT64     MemOrPortAddr,
+  IN OUT UINT64 BufferPtr
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_map (
+  IN UINT64     UniqueId,
+  IN UINT64     CpuAddr,
+  IN UINT32     NumBytes,
+  IN UINT32     Direction,
+  IN OUT UINT64 DeviceAddrPtr
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_unmap (
+  IN UINT64             UniqueId,
+  IN UINT64             CpuAddr,
+  IN UINT32             NumBytes,
+  IN UINT32             Direction,
+  IN UINT64 DeviceAddr  // not a pointer to device address
+  )
+;
+
+extern
+VOID
+snp_undi32_callback_sync (
+  IN UINT64             UniqueId,
+  IN UINT64             CpuAddr,
+  IN UINT32             NumBytes,
+  IN UINT32             Direction,
+  IN UINT64 DeviceAddr  // not a pointer to device address
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_start (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_stop (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_initialize (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+  IN UINTN                       extra_rx_buffer_size OPTIONAL,
+  IN UINTN                       extra_tx_buffer_size OPTIONAL
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_reset (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  *this,
+  IN BOOLEAN                      ExtendedVerification
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_shutdown (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive_filters (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+  IN UINT32                      enable,
+  IN UINT32                      disable,
+  IN BOOLEAN                     reset_mcast_filter,
+  IN UINTN                       mcast_filter_count OPTIONAL,
+  IN EFI_MAC_ADDRESS             * mcast_filter OPTIONAL
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_station_address (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+  IN BOOLEAN                     reset,
+  IN EFI_MAC_ADDRESS             *new OPTIONAL
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_statistics (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL  * this,
+  IN BOOLEAN                      reset,
+  IN OUT UINTN                    *statistics_size OPTIONAL,
+  IN OUT EFI_NETWORK_STATISTICS   * statistics_table OPTIONAL
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_mcast_ip_to_mac (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+  IN BOOLEAN                     IPv6,
+  IN EFI_IP_ADDRESS              *IP,
+  OUT EFI_MAC_ADDRESS            *MAC
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_nvdata (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+  IN BOOLEAN                     read_write,
+  IN UINTN                       offset,
+  IN UINTN                       buffer_size,
+  IN OUT VOID                    *buffer
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_get_status (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+  OUT UINT32                     *interrupt_status OPTIONAL,
+  OUT VOID                       **tx_buffer OPTIONAL
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_transmit (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+  IN UINTN                       header_size,
+  IN UINTN                       buffer_size,
+  IN VOID                        *buffer,
+  IN EFI_MAC_ADDRESS             * src_addr OPTIONAL,
+  IN EFI_MAC_ADDRESS             * dest_addr OPTIONAL,
+  IN UINT16                      *protocol OPTIONAL
+  )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+  OUT UINTN                      *header_size OPTIONAL,
+  IN OUT UINTN                   *buffer_size,
+  OUT VOID                       *buffer,
+  OUT EFI_MAC_ADDRESS            * src_addr OPTIONAL,
+  OUT EFI_MAC_ADDRESS            * dest_addr OPTIONAL,
+  OUT UINT16                     *protocol OPTIONAL
+  )
+;
+
+typedef
+EFI_STATUS
+(*issue_undi32_command) (
+  UINT64 cdb
+  );
+typedef
+VOID
+(*ptr) (
+  VOID
+  );
+
+
+/**
+  Install all the driver protocol
+
+  @param  ImageHandle  Driver image handle
+  @param  SystemTable  System services table
+
+  @retval EFI_SUCEESS  Initialization routine has found UNDI hardware, loaded it's
+                       ROM, and installed a notify event for the Network
+                       Indentifier Interface Protocol successfully.
+  @retval Other        Return value from HandleProtocol for DeviceIoProtocol or
+                       LoadedImageProtocol
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+;
+
+#ifdef EFI_SIZE_REDUCTION_APPLIED
+  #define COMPONENT_NAME_CODE(code)
+  #define COMPONENT_NAME            NULL
+#else
+  #define COMPONENT_NAME_CODE(code) code
+  #define COMPONENT_NAME            &gSimpleNetworkComponentName
+#endif
+
+#define SNP_MEM_PAGES(x)  (((x) - 1) / 4096 + 1)
+
+
+#endif /*  _SNP_H  */
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/start.c b/MdeModulePkg/Universal/Network/SnpDxe/start.c
new file mode 100644 (file)
index 0000000..0a43f8e
--- /dev/null
@@ -0,0 +1,191 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  start.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-07 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  this routine calls undi to start the interface and changes the snp state!\r
+\r
+  @param  snp                    pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_start (\r
+  SNP_DRIVER *snp\r
+  )\r
+{\r
+  PXE_CPB_START_30     *cpb;\r
+  PXE_CPB_START_31  *cpb_31;\r
+\r
+  cpb     = snp->cpb;\r
+  cpb_31  = snp->cpb;\r
+  //\r
+  // Initialize UNDI Start CDB for H/W UNDI\r
+  //\r
+  snp->cdb.OpCode     = PXE_OPCODE_START;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Make changes to H/W UNDI Start CDB if this is\r
+  // a S/W UNDI.\r
+  //\r
+  if (snp->is_swundi) {\r
+    if (snp->IsOldUndi) {\r
+      snp->cdb.CPBsize  = sizeof (PXE_CPB_START_30);\r
+      snp->cdb.CPBaddr  = (UINT64)(UINTN) cpb;\r
+\r
+      cpb->Delay        = (UINT64)(UINTN) &snp_undi32_callback_delay_30;\r
+      cpb->Block        = (UINT64)(UINTN) &snp_undi32_callback_block_30;\r
+\r
+      //\r
+      // Virtual == Physical.  This can be set to zero.\r
+      //\r
+      cpb->Virt2Phys  = (UINT64)(UINTN) &snp_undi32_callback_v2p_30;\r
+      cpb->Mem_IO     = (UINT64)(UINTN) &snp_undi32_callback_memio_30;\r
+    } else {\r
+      snp->cdb.CPBsize  = sizeof (PXE_CPB_START_31);\r
+      snp->cdb.CPBaddr  = (UINT64)(UINTN) cpb_31;\r
+\r
+      cpb_31->Delay     = (UINT64)(UINTN) &snp_undi32_callback_delay;\r
+      cpb_31->Block     = (UINT64)(UINTN) &snp_undi32_callback_block;\r
+\r
+      //\r
+      // Virtual == Physical.  This can be set to zero.\r
+      //\r
+      cpb_31->Virt2Phys = (UINT64)(UINTN) 0;\r
+      cpb_31->Mem_IO    = (UINT64)(UINTN) &snp_undi32_callback_memio;\r
+\r
+      cpb_31->Map_Mem   = (UINT64)(UINTN) &snp_undi32_callback_map;\r
+      cpb_31->UnMap_Mem = (UINT64)(UINTN) &snp_undi32_callback_unmap;\r
+      cpb_31->Sync_Mem  = (UINT64)(UINTN) &snp_undi32_callback_sync;\r
+\r
+      cpb_31->Unique_ID = (UINT64)(UINTN) snp;\r
+    }\r
+  }\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.start()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    //\r
+    // UNDI could not be started. Return UNDI error.\r
+    //\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.start()  %xh:%xh\n",\r
+      snp->cdb.StatCode,\r
+      snp->cdb.StatFlags)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Set simple network state to Started and return success.\r
+  //\r
+  snp->mode.State = EfiSimpleNetworkStarted;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for starting the interface\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_start routine to actually do start undi interface\r
+\r
+  @param  This                   context pointer\r
+\r
+  @retval EFI_INVALID_PARAMETER  "This" is Null\r
+  @retval      No                SNP driver can be extracted from "This"\r
+  @retval EFI_ALREADY_STARTED    The state of SNP is EfiSimpleNetworkStarted or\r
+                                 EfiSimpleNetworkInitialized\r
+  @retval EFI_DEVICE_ERROR       The state of SNP is other than\r
+                                 EfiSimpleNetworkStarted,\r
+                                 EfiSimpleNetworkInitialized, and\r
+                                 EfiSimpleNetworkStopped\r
+  @retval EFI_SUCCESS            UNDI interface is succesfully started\r
+  @retval Other                  Error occurs while calling pxe_start function.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_start (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *This\r
+  )\r
+{\r
+  SNP_DRIVER  *Snp;\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  EFI_TPL     OldTpl;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  switch (Snp->mode.State) {\r
+  case EfiSimpleNetworkStopped:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStarted:\r
+  case EfiSimpleNetworkInitialized:\r
+    Status = EFI_ALREADY_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = pxe_start (Snp);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // clear the map_list in SNP structure\r
+  //\r
+  for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
+    Snp->map_list[Index].virt       = 0;\r
+    Snp->map_list[Index].map_cookie = 0;\r
+  }\r
+\r
+  Snp->mode.MCastFilterCount = 0;\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/station_address.c b/MdeModulePkg/Universal/Network/SnpDxe/station_address.c
new file mode 100644 (file)
index 0000000..b6e0728
--- /dev/null
@@ -0,0 +1,237 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  station_address.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-17 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  this routine calls undi to read the MAC address of the NIC and updates the\r
+  mode structure with the address.\r
+\r
+  @param  snp         pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_get_stn_addr (\r
+  SNP_DRIVER *snp\r
+  )\r
+{\r
+  PXE_DB_STATION_ADDRESS  *db;\r
+\r
+  db                  = snp->db;\r
+  snp->cdb.OpCode     = PXE_OPCODE_STATION_ADDRESS;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_STATION_ADDRESS_READ;\r
+\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+\r
+  snp->cdb.DBsize     = sizeof (PXE_DB_STATION_ADDRESS);\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.station_addr()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Set new station address in SNP->Mode structure and return success.\r
+  //\r
+  CopyMem (\r
+    &(snp->mode.CurrentAddress),\r
+    &db->StationAddr,\r
+    snp->mode.HwAddressSize\r
+    );\r
+\r
+  CopyMem (\r
+    &snp->mode.BroadcastAddress,\r
+    &db->BroadcastAddr,\r
+    snp->mode.HwAddressSize\r
+    );\r
+\r
+  CopyMem (\r
+    &snp->mode.PermanentAddress,\r
+    &db->PermanentAddr,\r
+    snp->mode.HwAddressSize\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  this routine calls undi to set a new MAC address for the NIC,\r
+\r
+  @param  snp         pointer to snp driver structure\r
+  @param  NewMacAddr  pointer to a mac address to be set for the nic, if this is\r
+                      NULL then this routine resets the mac address to the NIC's\r
+                      original address.\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_set_stn_addr (\r
+  SNP_DRIVER      *snp,\r
+  EFI_MAC_ADDRESS *NewMacAddr\r
+  )\r
+{\r
+  PXE_CPB_STATION_ADDRESS *cpb;\r
+  PXE_DB_STATION_ADDRESS  *db;\r
+\r
+  cpb             = snp->cpb;\r
+  db              = snp->db;\r
+  snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;\r
+\r
+  if (NewMacAddr == NULL) {\r
+    snp->cdb.OpFlags  = PXE_OPFLAGS_STATION_ADDRESS_RESET;\r
+    snp->cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;\r
+    snp->cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;\r
+  } else {\r
+    snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;\r
+    //\r
+    // even though the OPFLAGS are set to READ, supplying a new address\r
+    // in the CPB will make undi change the mac address to the new one.\r
+    //\r
+    CopyMem (&cpb->StationAddr, NewMacAddr, snp->mode.HwAddressSize);\r
+\r
+    snp->cdb.CPBsize  = sizeof (PXE_CPB_STATION_ADDRESS);\r
+    snp->cdb.CPBaddr  = (UINT64)(UINTN) cpb;\r
+  }\r
+\r
+  snp->cdb.DBsize     = sizeof (PXE_DB_STATION_ADDRESS);\r
+  snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.station_addr()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    //\r
+    // UNDI command failed.  Return UNDI status to caller.\r
+    //\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // read the changed address and save it in SNP->Mode structure\r
+  //\r
+  pxe_get_stn_addr (snp);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for changing the NIC's mac address.\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the above routines to actually do the work\r
+\r
+  @param  this        context pointer\r
+  @param  NewMacAddr  pointer to a mac address to be set for the nic, if this is\r
+                      NULL then this routine resets the mac address to the NIC's\r
+                      original address.\r
+  @param  ResetFlag   If true, the mac address will change to NIC's original\r
+                      address\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_station_address (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+  IN BOOLEAN                     ResetFlag,\r
+  IN EFI_MAC_ADDRESS             * NewMacAddr OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_STATUS  Status;\r
+  EFI_TPL     OldTpl;\r
+\r
+  //\r
+  // Check for invalid parameter combinations.\r
+  //\r
+  if ((this == NULL) ||\r
+    (!ResetFlag && (NewMacAddr == NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  //\r
+  // Return error if the SNP is not initialized.\r
+  //\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (ResetFlag) {\r
+    Status = pxe_set_stn_addr (snp, NULL);\r
+  } else {\r
+    Status = pxe_set_stn_addr (snp, NewMacAddr);\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/statistics.c b/MdeModulePkg/Universal/Network/SnpDxe/statistics.c
new file mode 100644 (file)
index 0000000..19f2823
--- /dev/null
@@ -0,0 +1,201 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  statistics.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-17 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for getting the NIC's statistics.\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_ routine to actually do the\r
+\r
+  @param  this              context pointer\r
+  @param  ResetFlag         true to reset the NIC's statistics counters to zero.\r
+  @param  StatTableSizePtr  pointer to the statistics table size\r
+  @param  StatTablePtr      pointer to the statistics table\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_statistics (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+  IN BOOLEAN                     ResetFlag,\r
+  IN OUT UINTN                   *StatTableSizePtr OPTIONAL,\r
+  IN OUT EFI_NETWORK_STATISTICS  * StatTablePtr OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER        *snp;\r
+  PXE_DB_STATISTICS *db;\r
+  UINT64            *stp;\r
+  UINT64            mask;\r
+  UINTN             size;\r
+  UINTN             n;\r
+  EFI_TPL           OldTpl;\r
+  EFI_STATUS        Status;\r
+\r
+  //\r
+  // Get pointer to SNP driver instance for *this.\r
+  //\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  //\r
+  // Return error if the SNP is not initialized.\r
+  //\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // if we are not resetting the counters, we have to have a valid stat table\r
+  // with >0 size. if no reset, no table and no size, return success.\r
+  //\r
+  if (!ResetFlag && StatTableSizePtr == NULL) {\r
+    Status = StatTablePtr ? EFI_INVALID_PARAMETER : EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Initialize UNDI Statistics CDB\r
+  //\r
+  snp->cdb.OpCode     = PXE_OPCODE_STATISTICS;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  if (ResetFlag) {\r
+    snp->cdb.OpFlags  = PXE_OPFLAGS_STATISTICS_RESET;\r
+    snp->cdb.DBsize   = PXE_DBSIZE_NOT_USED;\r
+    snp->cdb.DBaddr   = PXE_DBADDR_NOT_USED;\r
+    db                = snp->db;\r
+  } else {\r
+    snp->cdb.OpFlags                = PXE_OPFLAGS_STATISTICS_READ;\r
+    snp->cdb.DBsize                 = sizeof (PXE_DB_STATISTICS);\r
+    snp->cdb.DBaddr                 = (UINT64)(UINTN) (db = snp->db);\r
+  }\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.statistics()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  switch (snp->cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    break;\r
+\r
+  case PXE_STATCODE_UNSUPPORTED:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.statistics()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.statistics()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (ResetFlag) {\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (StatTablePtr == NULL) {\r
+    *StatTableSizePtr = sizeof (EFI_NETWORK_STATISTICS);\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Convert the UNDI statistics information to SNP statistics\r
+  // information.\r
+  //\r
+  ZeroMem (StatTablePtr, *StatTableSizePtr);\r
+  stp   = (UINT64 *) StatTablePtr;\r
+  size  = 0;\r
+\r
+  for (n = 0, mask = 1; n < 64; n++, mask = LShiftU64 (mask, 1), stp++) {\r
+    //\r
+    // There must be room for a full UINT64.  Partial\r
+    // numbers will not be stored.\r
+    //\r
+    if ((n + 1) * sizeof (UINT64) > *StatTableSizePtr) {\r
+      break;\r
+    }\r
+\r
+    if (db->Supported & mask) {\r
+      *stp  = db->Data[n];\r
+      size  = n + 1;\r
+    } else {\r
+      SetMem (stp, sizeof (UINT64), 0xFF);\r
+    }\r
+  }\r
+  //\r
+  // Compute size up to last supported statistic.\r
+  //\r
+  while (++n < 64) {\r
+    if (db->Supported & (mask = LShiftU64 (mask, 1))) {\r
+      size = n;\r
+    }\r
+  }\r
+\r
+  size *= sizeof (UINT64);\r
+\r
+  if (*StatTableSizePtr >= size) {\r
+    *StatTableSizePtr = size;\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    *StatTableSizePtr = size;\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/stop.c b/MdeModulePkg/Universal/Network/SnpDxe/stop.c
new file mode 100644 (file)
index 0000000..6372523
--- /dev/null
@@ -0,0 +1,118 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+  stop.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-09 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  this routine calls undi to stop the interface and changes the snp state\r
+\r
+  @param  snp   pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_stop (\r
+  SNP_DRIVER *snp\r
+  )\r
+{\r
+  snp->cdb.OpCode     = PXE_OPCODE_STOP;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
+  snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.stop()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+  if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+    DEBUG (\r
+      (EFI_D_WARN,\r
+      "\nsnp->undi.stop()  %xh:%xh\n",\r
+      snp->cdb.StatCode,\r
+      snp->cdb.StatFlags)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Set simple network state to Started and return success.\r
+  //\r
+  snp->mode.State = EfiSimpleNetworkStopped;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This is the SNP interface routine for stopping the interface.\r
+  This routine basically retrieves snp structure, checks the SNP state and\r
+  calls the pxe_stop routine to actually stop the undi interface\r
+\r
+  @param  this  context pointer\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_stop (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *this\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_TPL     OldTpl;\r
+  EFI_STATUS  Status;\r
+\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkStarted:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = pxe_stop (snp);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/transmit.c b/MdeModulePkg/Universal/Network/SnpDxe/transmit.c
new file mode 100644 (file)
index 0000000..d113ede
--- /dev/null
@@ -0,0 +1,399 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module name:\r
+\r
+    transmit.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+  2000-Feb-03 M(f)J   Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  This routine calls undi to create the meadia header for the given data buffer.\r
+\r
+  @param  snp                 pointer to SNP driver structure\r
+  @param  MacHeaderPtr        address where the media header will be filled in.\r
+  @param  MacHeaderSize       size of the memory at MacHeaderPtr\r
+  @param  BufferPtr           data buffer pointer\r
+  @param  BufferLength        Size of data in the BufferPtr\r
+  @param  DestinationAddrPtr  address of the destination mac address buffer\r
+  @param  SourceAddrPtr       address of the source mac address buffer\r
+  @param  ProtocolPtr         address of the protocol type\r
+\r
+  @retval EFI_SUCCESS         if successfully completed the undi call\r
+  @retval Other               error return from undi call.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_fillheader (\r
+  SNP_DRIVER      *snp,\r
+  VOID            *MacHeaderPtr,\r
+  UINTN           MacHeaderSize,\r
+  VOID            *BufferPtr,\r
+  UINTN           BufferLength,\r
+  EFI_MAC_ADDRESS *DestinationAddrPtr,\r
+  EFI_MAC_ADDRESS *SourceAddrPtr,\r
+  UINT16          *ProtocolPtr\r
+  )\r
+{\r
+  PXE_CPB_FILL_HEADER_FRAGMENTED  *cpb;\r
+  EFI_STATUS                      Status;\r
+  struct s_v2p                    *pkt_v2p;\r
+  UINT64                          TempData;\r
+\r
+  cpb = snp->cpb;\r
+  if (SourceAddrPtr) {\r
+    CopyMem (\r
+      (VOID *) cpb->SrcAddr,\r
+      (VOID *) SourceAddrPtr,\r
+      snp->mode.HwAddressSize\r
+      );\r
+  } else {\r
+    CopyMem (\r
+      (VOID *) cpb->SrcAddr,\r
+      (VOID *) &(snp->mode.CurrentAddress),\r
+      snp->mode.HwAddressSize\r
+      );\r
+  }\r
+\r
+  CopyMem (\r
+    (VOID *) cpb->DestAddr,\r
+    (VOID *) DestinationAddrPtr,\r
+    snp->mode.HwAddressSize\r
+    );\r
+\r
+  //\r
+  // we need to do the byte swapping\r
+  //\r
+  cpb->Protocol             = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);\r
+\r
+  cpb->PacketLen            = (UINT32) (BufferLength);\r
+  cpb->MediaHeaderLen       = (UINT16) MacHeaderSize;\r
+\r
+  cpb->FragCnt              = 2;\r
+  cpb->reserved             = 0;\r
+\r
+  cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;\r
+  cpb->FragDesc[0].FragLen  = (UINT32) MacHeaderSize;\r
+  cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr;\r
+  cpb->FragDesc[1].FragLen  = (UINT32) BufferLength;\r
+\r
+  cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;\r
+\r
+  if (snp->IsOldUndi) {\r
+    TempData = (UINT64) (UINTN) MacHeaderPtr;\r
+    if (TempData >= FOUR_GIGABYTES) {\r
+      cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) snp->fill_hdr_buf;\r
+      cpb->FragDesc[0].FragLen  = (UINT32) snp->init_info.MediaHeaderLen;\r
+    }\r
+\r
+    TempData = (UINT64) (UINTN) (BufferPtr);\r
+    if (TempData >= FOUR_GIGABYTES) {\r
+      //\r
+      // Let the device just read this buffer\r
+      //\r
+      Status = add_v2p (\r
+                &pkt_v2p,\r
+                EfiPciIoOperationBusMasterRead,\r
+                BufferPtr,\r
+                BufferLength\r
+                );\r
+      if (Status != EFI_SUCCESS) {\r
+        return Status;\r
+      }\r
+      //\r
+      // give the virtual address to UNDI and it will call back on Virt2Phys\r
+      // to get the mapped address, if it needs it\r
+      //\r
+      cpb->FragDesc[1].FragLen = (UINT32) pkt_v2p->bsize;\r
+    }\r
+  }\r
+\r
+  snp->cdb.OpCode     = PXE_OPCODE_FILL_HEADER;\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;\r
+\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+\r
+  snp->cdb.CPBsize    = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);\r
+  snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header()  "));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
+\r
+  if (snp->IsOldUndi) {\r
+    TempData = (UINT64) (UINTN) (BufferPtr);\r
+    if (TempData >= FOUR_GIGABYTES) {\r
+      del_v2p (BufferPtr);\r
+    }\r
+    //\r
+    // if we used the global buffer for header, copy the contents\r
+    //\r
+    TempData = (UINT64) (UINTN) MacHeaderPtr;\r
+    if (TempData >= FOUR_GIGABYTES) {\r
+      CopyMem (\r
+        MacHeaderPtr,\r
+        snp->fill_hdr_buf,\r
+        snp->init_info.MediaHeaderLen\r
+        );\r
+    }\r
+  }\r
+\r
+  switch (snp->cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    return EFI_SUCCESS;\r
+\r
+  case PXE_STATCODE_INVALID_PARAMETER:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.fill_header()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+\r
+  default:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nsnp->undi.fill_header()  %xh:%xh\n",\r
+      snp->cdb.StatFlags,\r
+      snp->cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This routine calls undi to transmit the given data buffer\r
+\r
+  @param  snp                 pointer to SNP driver structure\r
+  @param  BufferPtr           data buffer pointer\r
+  @param  BufferLength        Size of data in the BufferPtr\r
+\r
+  @retval EFI_SUCCESS         if successfully completed the undi call\r
+  @retval Other               error return from undi call.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_transmit (\r
+  SNP_DRIVER *snp,\r
+  VOID       *BufferPtr,\r
+  UINTN      BufferLength\r
+  )\r
+{\r
+  PXE_CPB_TRANSMIT  *cpb;\r
+  EFI_STATUS        Status;\r
+  struct s_v2p      *v2p;\r
+  UINT64            TempData;\r
+\r
+  cpb             = snp->cpb;\r
+  cpb->FrameAddr  = (UINT64) (UINTN) BufferPtr;\r
+  cpb->DataLen    = (UINT32) BufferLength;\r
+  \r
+  TempData = (UINT64) (UINTN) BufferPtr;\r
+  if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+    //\r
+    // we need to create a mapping now and give it to the undi when it calls\r
+    // the Virt2Phys on this address.\r
+    // this is a transmit, just map it for the device to READ\r
+    //\r
+    Status = add_v2p (\r
+              &v2p,\r
+              EfiPciIoOperationBusMasterRead,\r
+              BufferPtr,\r
+              BufferLength\r
+              );\r
+    if (Status != EFI_SUCCESS) {\r
+      return Status;\r
+    }\r
+\r
+    cpb->DataLen = (UINT32) v2p->bsize;\r
+  }\r
+\r
+  cpb->MediaheaderLen = 0;\r
+  cpb->reserved       = 0;\r
+\r
+  snp->cdb.OpFlags    = PXE_OPFLAGS_TRANSMIT_WHOLE;\r
+\r
+  snp->cdb.CPBsize    = sizeof (PXE_CPB_TRANSMIT);\r
+  snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
+\r
+  snp->cdb.OpCode     = PXE_OPCODE_TRANSMIT;\r
+  snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+\r
+  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  snp->cdb.IFnum      = snp->if_num;\r
+  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nsnp->undi.transmit()  "));\r
+  DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode  == %x", snp->cdb.OpCode));\r
+  DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));\r
+  DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr  == %X", snp->cdb.DBaddr));\r
+  DEBUG ((EFI_D_NET, "\ncpb->FrameAddr   == %X\n", cpb->FrameAddr));\r
+\r
+  (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
+\r
+  DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit()  "));\r
+  DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));\r
+\r
+  //\r
+  // we will unmap the buffers in get_status call, not here\r
+  //\r
+  switch (snp->cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    return EFI_SUCCESS;\r
+\r
+  case PXE_STATCODE_QUEUE_FULL:\r
+  case PXE_STATCODE_BUSY:\r
+    Status = EFI_NOT_READY;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  DEBUG (\r
+    (EFI_D_ERROR,\r
+    "\nsnp->undi.transmit()  %xh:%xh\n",\r
+    snp->cdb.StatFlags,\r
+    snp->cdb.StatCode)\r
+    );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This is the snp interface routine for transmitting a packet. this routine\r
+  basically retrieves the snp structure, checks the snp state and calls\r
+  pxe_fill_header and pxe_transmit calls to complete the transmission.\r
+\r
+  @param  this                pointer to SNP driver context\r
+  @param  MacHeaderSize       size of the memory at MacHeaderPtr\r
+  @param  BufferLength        Size of data in the BufferPtr\r
+  @param  BufferPtr           data buffer pointer\r
+  @param  SourceAddrPtr       address of the source mac address buffer\r
+  @param  DestinationAddrPtr  address of the destination mac address buffer\r
+  @param  ProtocolPtr         address of the protocol type\r
+\r
+  @retval EFI_SUCCESS         if successfully completed the undi call\r
+  @retval Other               error return from undi call.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_transmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+  IN UINTN                       MacHeaderSize,\r
+  IN UINTN                       BufferLength,\r
+  IN VOID                        *BufferPtr,\r
+  IN EFI_MAC_ADDRESS             * SourceAddrPtr OPTIONAL,\r
+  IN EFI_MAC_ADDRESS             * DestinationAddrPtr OPTIONAL,\r
+  IN UINT16                      *ProtocolPtr OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER  *snp;\r
+  EFI_STATUS  Status;\r
+  EFI_TPL     OldTpl;\r
+\r
+  if (this == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (snp == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  switch (snp->mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (BufferPtr == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (BufferLength < snp->mode.MediaHeaderSize) {\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // if the MacHeaderSize is non-zero, we need to fill up the header and for that\r
+  // we need the destination address and the protocol\r
+  //\r
+  if (MacHeaderSize != 0) {\r
+    if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = pxe_fillheader (\r
+              snp,\r
+              BufferPtr,\r
+              MacHeaderSize,\r
+              (UINT8 *) BufferPtr + MacHeaderSize,\r
+              BufferLength - MacHeaderSize,\r
+              DestinationAddrPtr,\r
+              SourceAddrPtr,\r
+              ProtocolPtr\r
+              );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  Status = pxe_transmit (snp, BufferPtr, BufferLength);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/ComponentName.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/ComponentName.c
new file mode 100644 (file)
index 0000000..477af22
--- /dev/null
@@ -0,0 +1,169 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle  OPTIONAL,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gTcp4ComponentName = {\r
+  TcpComponentNameGetDriverName,\r
+  TcpComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mTcpDriverNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"Tcp Network Service Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+Arguments:\r
+\r
+  This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  Language   - A pointer to a three character ISO 639-2 language identifier.\r
+               This is the language of the driver name that that the caller\r
+               is requesting, and it must match one of the languages\r
+               specified in SupportedLanguages.  The number of languages\r
+               supported by a driver is up to the driver writer.\r
+  DriverName - A pointer to the Unicode string to return.  This Unicode\r
+               string is the name of the driver specified by This in the\r
+               language specified by Language.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES            - The Unicode string for the Driver specified by\r
+                          This and the language specified by Language was\r
+                          returned in DriverName.\r
+  EFI_INVALID_PARAMETER - Language is NULL.\r
+  EFI_INVALID_PARAMETER - DriverName is NULL.\r
+  EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                          language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gTcp4ComponentName.SupportedLanguages,\r
+          mTcpDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle  OPTIONAL,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **ControllerName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+Arguments:\r
+\r
+  This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  ControllerHandle - The handle of a controller that the driver specified by\r
+                     This is managing.  This handle specifies the controller\r
+                     whose name is to be returned.\r
+  ChildHandle      - The handle of the child controller to retrieve the name\r
+                     of.  This is an optional parameter that may be NULL.\r
+                     It will be NULL for device drivers.  It will also be\r
+                     NULL for a bus drivers that wish to retrieve the name of\r
+                     the bus controller.  It will not be NULL for a bus\r
+                     driver that wishes to retrieve the name of a child\r
+                     controller.\r
+  Language         - A pointer to a three character ISO 639-2 language\r
+                     identifier.  This is the language of the controller\r
+                     name that that the caller is requesting, and it must\r
+                     match one of the languages specified in supported\r
+                     languages. The number of languages supported by a driver\r
+                     is up to the driver writer.\r
+  ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                     string is the name of the controller specified by\r
+                     ControllerHandle and ChildHandle in the language\r
+                     specified by Language from the point of view of the\r
+                     driver specified by This.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Unicode string for the user readable name in\r
+                          the language specified by Language for the driver\r
+                          specified by This was returned in DriverName.\r
+  EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+  EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid\r
+                          EFI_HANDLE.\r
+  EFI_INVALID_PARAMETER - Language is NULL.\r
+  EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+  EFI_UNSUPPORTED       - The driver specified by This is not currently\r
+                          managing the controller specified by\r
+                          ControllerHandle and ChildHandle.\r
+  EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                          language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.c
new file mode 100644 (file)
index 0000000..1f81fc3
--- /dev/null
@@ -0,0 +1,1269 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  SockImpl.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "SockImpl.h"\r
+\r
+STATIC\r
+UINT32\r
+SockTcpDataToRcv (\r
+  IN  SOCK_BUFFER   *SockBuffer,\r
+  OUT BOOLEAN       *IsOOB,\r
+  IN  UINT32        BufLen\r
+  );\r
+\r
+STATIC\r
+VOID\r
+SockProcessSndToken (\r
+  IN SOCKET *Sock\r
+  );\r
+\r
+VOID\r
+SockFreeFoo (\r
+  IN EFI_EVENT Event\r
+  )\r
+{\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Get the length of the data that can be retrieved from the socket\r
+  receive buffer.\r
+\r
+  @param  SockBuffer            Pointer to the socket receive buffer.\r
+  @param  IsUrg                 Pointer to a BOOLEAN variable. If TRUE the data is\r
+                                OOB.\r
+  @param  BufLen                The maximum length of the data buffer to store the\r
+                                received data in socket layer.\r
+\r
+  @return The length of the data can be retreived.\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+SockTcpDataToRcv (\r
+  IN  SOCK_BUFFER    *SockBuffer,\r
+  OUT BOOLEAN        *IsUrg,\r
+  IN  UINT32         BufLen\r
+  )\r
+{\r
+  NET_BUF       *RcvBufEntry;\r
+  UINT32        DataLen;\r
+  TCP_RSV_DATA  *TcpRsvData;\r
+  BOOLEAN       Urg;\r
+\r
+  ASSERT (SockBuffer && IsUrg && (BufLen > 0));\r
+\r
+  RcvBufEntry = SockBufFirst (SockBuffer);\r
+  ASSERT (RcvBufEntry);\r
+\r
+  TcpRsvData  = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
+\r
+  *IsUrg      = ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
+\r
+  if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
+\r
+    DataLen = NET_MIN (TcpRsvData->UrgLen, BufLen);\r
+\r
+    if (DataLen < TcpRsvData->UrgLen) {\r
+      TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;\r
+    } else {\r
+      TcpRsvData->UrgLen = 0;\r
+    }\r
+\r
+    return DataLen;\r
+\r
+  }\r
+\r
+  DataLen     = RcvBufEntry->TotalSize;\r
+\r
+  RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
+\r
+  while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {\r
+\r
+    TcpRsvData  = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
+\r
+    Urg         = ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
+\r
+    if (*IsUrg != Urg) {\r
+      break;\r
+    }\r
+\r
+    if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
+\r
+      if (TcpRsvData->UrgLen + DataLen < BufLen) {\r
+        TcpRsvData->UrgLen = 0;\r
+      } else {\r
+        TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);\r
+      }\r
+\r
+      return NET_MIN (TcpRsvData->UrgLen + DataLen, BufLen);\r
+\r
+    }\r
+\r
+    DataLen += RcvBufEntry->TotalSize;\r
+\r
+    RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
+  }\r
+\r
+  DataLen = NET_MIN (BufLen, DataLen);\r
+  return DataLen;\r
+}\r
+\r
+\r
+/**\r
+  Copy data from socket buffer to application provided receive buffer.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  TcpRxData             Pointer to the application provided receive buffer.\r
+  @param  RcvdBytes             The maximum length of the data can be copied.\r
+  @param  IsOOB                 If TURE the data is OOB, else the data is normal.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockSetTcpRxData (\r
+  IN SOCKET     *Sock,\r
+  IN VOID       *TcpRxData,\r
+  IN UINT32     RcvdBytes,\r
+  IN BOOLEAN    IsOOB\r
+  )\r
+{\r
+  UINT32                  Index;\r
+  UINT32                  CopyBytes;\r
+  UINT32                  OffSet;\r
+  EFI_TCP4_RECEIVE_DATA   *RxData;\r
+  EFI_TCP4_FRAGMENT_DATA  *Fragment;\r
+\r
+  RxData  = (EFI_TCP4_RECEIVE_DATA *) TcpRxData;\r
+\r
+  OffSet  = 0;\r
+\r
+  ASSERT (RxData->DataLength >= RcvdBytes);\r
+\r
+  RxData->DataLength  = RcvdBytes;\r
+  RxData->UrgentFlag  = IsOOB;\r
+\r
+  for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {\r
+\r
+    Fragment  = &RxData->FragmentTable[Index];\r
+    CopyBytes = NET_MIN (Fragment->FragmentLength, RcvdBytes);\r
+\r
+    NetbufQueCopy (\r
+      Sock->RcvBuffer.DataQueue,\r
+      OffSet,\r
+      CopyBytes,\r
+      Fragment->FragmentBuffer\r
+      );\r
+\r
+    Fragment->FragmentLength = CopyBytes;\r
+    RcvdBytes -= CopyBytes;\r
+    OffSet += CopyBytes;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Get received data from the socket layer to the receive token.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  RcvToken              Pointer to the application provided receive token.\r
+\r
+  @return The length of data received in this token.\r
+\r
+**/\r
+UINT32\r
+SockProcessRcvToken (\r
+  IN SOCKET        *Sock,\r
+  IN SOCK_IO_TOKEN *RcvToken\r
+  )\r
+{\r
+  UINT32                 TokenRcvdBytes;\r
+  EFI_TCP4_RECEIVE_DATA  *RxData;\r
+  BOOLEAN                IsUrg;\r
+\r
+  ASSERT (Sock);\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  RxData = RcvToken->Packet.RxData;\r
+\r
+  TokenRcvdBytes = SockTcpDataToRcv (\r
+                      &Sock->RcvBuffer,\r
+                      &IsUrg,\r
+                      RxData->DataLength\r
+                      );\r
+\r
+  //\r
+  // Copy data from RcvBuffer of socket to user\r
+  // provided RxData and set the fields in TCP RxData\r
+  //\r
+  SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);\r
+\r
+  SOCK_TRIM_RCV_BUFF (Sock, TokenRcvdBytes);\r
+  SIGNAL_TOKEN (&(RcvToken->Token), EFI_SUCCESS);\r
+\r
+  return TokenRcvdBytes;\r
+}\r
+\r
+\r
+/**\r
+  Process the TCP send data, buffer the tcp txdata and append\r
+  the buffer to socket send buffer,then try to send it.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  TcpTxData             Pointer to the tcp txdata.\r
+\r
+  @retval EFI_SUCCESS           The operation is completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed due to resource limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockProcessTcpSndData (\r
+  IN SOCKET   *Sock,\r
+  IN VOID     *TcpTxData\r
+  )\r
+{\r
+  NET_BUF                 *SndData;\r
+  EFI_STATUS              Status;\r
+  EFI_TCP4_TRANSMIT_DATA  *TxData;\r
+\r
+  TxData = (EFI_TCP4_TRANSMIT_DATA *) TcpTxData;\r
+\r
+  //\r
+  // transform this TxData into a NET_BUFFER\r
+  // and insert it into Sock->SndBuffer\r
+  //\r
+  SndData = NetbufFromExt (\r
+              (NET_FRAGMENT *) TxData->FragmentTable,\r
+              TxData->FragmentCount,\r
+              0,\r
+              0,\r
+              SockFreeFoo,\r
+              NULL\r
+              );\r
+\r
+  if (NULL == SndData) {\r
+    SOCK_DEBUG_ERROR (("SockKProcessSndData: Failed to"\r
+      " call NetBufferFromExt\n"));\r
+\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetbufQueAppend (Sock->SndBuffer.DataQueue, SndData);\r
+\r
+  //\r
+  // notify the low layer protocol to handle this send token\r
+  //\r
+  if (TxData->Urgent) {\r
+    Status = Sock->ProtoHandler (Sock, SOCK_SNDURG, NULL);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  if (TxData->Push) {\r
+    Status = Sock->ProtoHandler (Sock, SOCK_SNDPUSH, NULL);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // low layer protocol should really handle the sending\r
+  // process when catching SOCK_SND request\r
+  //\r
+  Status = Sock->ProtoHandler (Sock, SOCK_SND, NULL);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Flush the tokens in the specific token list.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  PendingTokenList      Pointer to the token list to be flushed.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockFlushPendingToken (\r
+  IN SOCKET         *Sock,\r
+  IN NET_LIST_ENTRY *PendingTokenList\r
+  )\r
+{\r
+  SOCK_TOKEN            *SockToken;\r
+  SOCK_COMPLETION_TOKEN *Token;\r
+\r
+  ASSERT (Sock && PendingTokenList);\r
+\r
+  while (!NetListIsEmpty (PendingTokenList)) {\r
+    SockToken = NET_LIST_HEAD (\r
+                  PendingTokenList,\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    Token = SockToken->Token;\r
+    SIGNAL_TOKEN (Token, Sock->SockError);\r
+\r
+    NetListRemoveEntry (&(SockToken->TokenList));\r
+    NetFreePool (SockToken);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Wake up the connection token while the connection is\r
+  successfully established, then try to process any\r
+  pending send token.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockWakeConnToken (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  ASSERT (Sock->ConnectionToken != NULL);\r
+\r
+  SIGNAL_TOKEN (Sock->ConnectionToken, EFI_SUCCESS);\r
+  Sock->ConnectionToken = NULL;\r
+\r
+  //\r
+  // check to see if some pending send token existed?\r
+  //\r
+  SockProcessSndToken (Sock);\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Wake up the listen token while the connection is\r
+  established successfully.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockWakeListenToken (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  SOCKET                *Parent;\r
+  SOCK_TOKEN            *SockToken;\r
+  EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
+\r
+  Parent = Sock->Parent;\r
+\r
+  ASSERT (Parent && SOCK_IS_LISTENING (Parent) && SOCK_IS_CONNECTED (Sock));\r
+\r
+  if (!NetListIsEmpty (&Parent->ListenTokenList)) {\r
+    SockToken = NET_LIST_HEAD (\r
+                  &Parent->ListenTokenList,\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    ListenToken = (EFI_TCP4_LISTEN_TOKEN *) SockToken->Token;\r
+    ListenToken->NewChildHandle = Sock->SockHandle;\r
+\r
+    SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
+\r
+    NetListRemoveEntry (&SockToken->TokenList);\r
+    NetFreePool (SockToken);\r
+\r
+    NetListRemoveEntry (&Sock->ConnectionList);\r
+\r
+    Parent->ConnCnt--;\r
+    SOCK_DEBUG_WARN (("SockWakeListenToken: accept a socket,"\r
+      "now conncnt is %d", Parent->ConnCnt));\r
+\r
+    Sock->Parent = NULL;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Wake up the receive token while some data is received.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockWakeRcvToken (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  UINT32        RcvdBytes;\r
+  UINT32        TokenRcvdBytes;\r
+  SOCK_TOKEN    *SockToken;\r
+  SOCK_IO_TOKEN *RcvToken;\r
+\r
+  ASSERT (Sock->RcvBuffer.DataQueue);\r
+\r
+  RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;\r
+\r
+  ASSERT (RcvdBytes > 0);\r
+\r
+  while (RcvdBytes > 0 && !NetListIsEmpty (&Sock->RcvTokenList)) {\r
+\r
+    SockToken = NET_LIST_HEAD (\r
+                  &Sock->RcvTokenList,\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    RcvToken        = (SOCK_IO_TOKEN *) SockToken->Token;\r
+    TokenRcvdBytes  = SockProcessRcvToken (Sock, RcvToken);\r
+\r
+    if (0 == TokenRcvdBytes) {\r
+      return ;\r
+    }\r
+\r
+    NetListRemoveEntry (&(SockToken->TokenList));\r
+    NetFreePool (SockToken);\r
+    RcvdBytes -= TokenRcvdBytes;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Process the send token.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockProcessSndToken (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  UINT32                  FreeSpace;\r
+  SOCK_TOKEN              *SockToken;\r
+  UINT32                  DataLen;\r
+  SOCK_IO_TOKEN           *SndToken;\r
+  EFI_TCP4_TRANSMIT_DATA  *TxData;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Sock && (SOCK_STREAM == Sock->Type));\r
+\r
+  FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
+\r
+  //\r
+  // to determine if process a send token using\r
+  // socket layer flow control policy\r
+  //\r
+  while ((FreeSpace >= Sock->SndBuffer.LowWater) &&\r
+         !NetListIsEmpty (&Sock->SndTokenList)) {\r
+\r
+    SockToken = NET_LIST_HEAD (\r
+                  &(Sock->SndTokenList),\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    //\r
+    // process this token\r
+    //\r
+    NetListRemoveEntry (&(SockToken->TokenList));\r
+    NetListInsertTail (\r
+      &(Sock->ProcessingSndTokenList),\r
+      &(SockToken->TokenList)\r
+      );\r
+\r
+    //\r
+    // Proceess it in the light of  SockType\r
+    //\r
+    SndToken  = (SOCK_IO_TOKEN *) SockToken->Token;\r
+    TxData    = SndToken->Packet.TxData;\r
+\r
+    DataLen = TxData->DataLength;\r
+    Status  = SockProcessTcpSndData (Sock, TxData);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto OnError;\r
+    }\r
+\r
+    if (DataLen >= FreeSpace) {\r
+      FreeSpace = 0;\r
+\r
+    } else {\r
+      FreeSpace -= DataLen;\r
+\r
+    }\r
+  }\r
+\r
+  return ;\r
+\r
+OnError:\r
+\r
+  NetListRemoveEntry (&SockToken->TokenList);\r
+  SIGNAL_TOKEN (SockToken->Token, Status);\r
+  NetFreePool (SockToken);\r
+}\r
+\r
+\r
+/**\r
+  Create a socket with initial data SockInitData.\r
+\r
+  @param  SockInitData          Pointer to the initial data of the socket.\r
+\r
+  @return Pointer to the newly created socket.\r
+\r
+**/\r
+SOCKET *\r
+SockCreate (\r
+  IN SOCK_INIT_DATA *SockInitData\r
+  )\r
+{\r
+  SOCKET      *Sock;\r
+  SOCKET      *Parent;\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (SockInitData && SockInitData->ProtoHandler);\r
+  ASSERT (SockInitData->Type == SOCK_STREAM);\r
+\r
+  Parent = SockInitData->Parent;\r
+\r
+  if (Parent && (Parent->ConnCnt == Parent->BackLog)) {\r
+    SOCK_DEBUG_ERROR (\r
+      ("SockCreate: Socket parent has "\r
+      "reached its connection limit with %d ConnCnt and %d BackLog\n",\r
+      Parent->ConnCnt,\r
+      Parent->BackLog)\r
+      );\r
+\r
+    return NULL;\r
+  }\r
+\r
+  Sock = NetAllocateZeroPool (sizeof (SOCKET));\r
+  if (NULL == Sock) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockCreate: No resource to create a new socket\n"));\r
+    return NULL;\r
+  }\r
+\r
+  NetListInit (&Sock->ConnectionList);\r
+  NetListInit (&Sock->ListenTokenList);\r
+  NetListInit (&Sock->RcvTokenList);\r
+  NetListInit (&Sock->SndTokenList);\r
+  NetListInit (&Sock->ProcessingSndTokenList);\r
+\r
+  NET_LOCK_INIT (&(Sock->Lock));\r
+\r
+  Sock->SndBuffer.DataQueue = NetbufQueAlloc ();\r
+  if (NULL == Sock->SndBuffer.DataQueue) {\r
+    SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate"\r
+      " SndBuffer for new socket\n"));\r
+\r
+    goto OnError;\r
+  }\r
+\r
+  Sock->RcvBuffer.DataQueue = NetbufQueAlloc ();\r
+  if (NULL == Sock->RcvBuffer.DataQueue) {\r
+    SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate "\r
+      "RcvBuffer for new socket\n"));\r
+\r
+    goto OnError;\r
+  }\r
+\r
+  Sock->Signature           = SOCK_SIGNATURE;\r
+\r
+  Sock->Parent              = Parent;\r
+  Sock->BackLog             = SockInitData->BackLog;\r
+  Sock->ProtoHandler        = SockInitData->ProtoHandler;\r
+  Sock->SndBuffer.HighWater = SockInitData->SndBufferSize;\r
+  Sock->RcvBuffer.HighWater = SockInitData->RcvBufferSize;\r
+  Sock->Type                = SockInitData->Type;\r
+  Sock->DriverBinding       = SockInitData->DriverBinding;\r
+  Sock->State               = SockInitData->State;\r
+\r
+  Sock->SockError           = EFI_ABORTED;\r
+  Sock->SndBuffer.LowWater  = SOCK_BUFF_LOW_WATER;\r
+  Sock->RcvBuffer.LowWater  = SOCK_BUFF_LOW_WATER;\r
+\r
+  //\r
+  // Install protocol on Sock->SockHandle\r
+  //\r
+  NetCopyMem (\r
+    &(Sock->NetProtocol.TcpProtocol),\r
+    SockInitData->Protocol,\r
+    sizeof (EFI_TCP4_PROTOCOL)\r
+    );\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Sock->SockHandle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  &(Sock->NetProtocol.TcpProtocol),\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    SOCK_DEBUG_ERROR (("SockCreate: Install TCP protocol in "\r
+      "socket failed with %r\n", Status));\r
+\r
+    goto OnError;\r
+  }\r
+\r
+  if (Parent != NULL) {\r
+    ASSERT (Parent->BackLog > 0);\r
+    ASSERT (SOCK_IS_LISTENING (Parent));\r
+\r
+    //\r
+    // need to add it into Parent->ConnectionList\r
+    // if the Parent->ConnCnt < Parent->BackLog\r
+    //\r
+    Parent->ConnCnt++;\r
+\r
+    SOCK_DEBUG_WARN (("SockCreate: Create a new socket and"\r
+      "add to parent, now conncnt is %d\n", Parent->ConnCnt));\r
+\r
+    NetListInsertTail (&Parent->ConnectionList, &Sock->ConnectionList);\r
+  }\r
+\r
+  return Sock;\r
+\r
+OnError:\r
+  if (NULL != Sock) {\r
+\r
+    if (NULL != Sock->SndBuffer.DataQueue) {\r
+      NetbufQueFree (Sock->SndBuffer.DataQueue);\r
+    }\r
+\r
+    if (NULL != Sock->RcvBuffer.DataQueue) {\r
+      NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
+    }\r
+\r
+    NetFreePool (Sock);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Destroy a socket.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockDestroy (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  VOID        *SockProtocol;\r
+  EFI_GUID    *ProtocolGuid;\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  //\r
+  // Flush the completion token buffered\r
+  // by sock and rcv, snd buffer\r
+  //\r
+  if (!SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+    SockConnFlush (Sock);\r
+    SockSetState (Sock, SO_CLOSED);\r
+    Sock->ConfigureState = SO_UNCONFIGURED;\r
+\r
+  }\r
+  //\r
+  // Destory the RcvBuffer Queue and SendBuffer Queue\r
+  //\r
+  NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
+  NetbufQueFree (Sock->SndBuffer.DataQueue);\r
+\r
+  //\r
+  // Remove it from parent connection list if needed\r
+  //\r
+  if (Sock->Parent) {\r
+\r
+    NetListRemoveEntry (&(Sock->ConnectionList));\r
+    (Sock->Parent->ConnCnt)--;\r
+\r
+    SOCK_DEBUG_WARN (("SockDestory: Delete a unaccepted socket from parent"\r
+      "now conncnt is %d\n", Sock->Parent->ConnCnt));\r
+\r
+    Sock->Parent = NULL;\r
+  }\r
+\r
+  //\r
+  // Set the protocol guid and driver binding handle\r
+  // in the light of Sock->SockType\r
+  //\r
+  ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+\r
+  //\r
+  // Retrieve the protocol installed on this sock\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Sock->SockHandle,\r
+                  ProtocolGuid,\r
+                  &SockProtocol,\r
+                  Sock->DriverBinding,\r
+                  Sock->SockHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockDestroy: Open protocol installed "\r
+      "on socket failed with %r\n", Status));\r
+\r
+    goto FreeSock;\r
+  }\r
+\r
+  //\r
+  // Uninstall the protocol installed on this sock\r
+  // in the light of Sock->SockType\r
+  //\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+        Sock->SockHandle,\r
+        ProtocolGuid,\r
+        SockProtocol,\r
+        NULL\r
+        );\r
+\r
+FreeSock:\r
+  NetFreePool (Sock);\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Flush the socket.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockConnFlush (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  SOCKET  *Child;\r
+\r
+  ASSERT (Sock);\r
+\r
+  //\r
+  // Clear the flag in this socket\r
+  //\r
+  Sock->Flag = 0;\r
+\r
+  //\r
+  // Flush the SndBuffer and RcvBuffer of Sock\r
+  //\r
+  NetbufQueFlush (Sock->SndBuffer.DataQueue);\r
+  NetbufQueFlush (Sock->RcvBuffer.DataQueue);\r
+\r
+  //\r
+  // Signal the pending token\r
+  //\r
+  if (Sock->ConnectionToken != NULL) {\r
+    SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);\r
+    Sock->ConnectionToken = NULL;\r
+  }\r
+\r
+  if (Sock->CloseToken != NULL) {\r
+    SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);\r
+    Sock->CloseToken = NULL;\r
+  }\r
+\r
+  SockFlushPendingToken (Sock, &(Sock->ListenTokenList));\r
+  SockFlushPendingToken (Sock, &(Sock->RcvTokenList));\r
+  SockFlushPendingToken (Sock, &(Sock->SndTokenList));\r
+  SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));\r
+\r
+  //\r
+  // Destroy the pending connection, if it is a listening socket\r
+  //\r
+  if (SOCK_IS_LISTENING (Sock)) {\r
+    while (!NetListIsEmpty (&Sock->ConnectionList)) {\r
+      Child = NET_LIST_HEAD (\r
+                &Sock->ConnectionList,\r
+                SOCKET,\r
+                ConnectionList\r
+                );\r
+\r
+      SockDestroyChild (Child);\r
+    }\r
+\r
+    Sock->ConnCnt = 0;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Set the state of the socket.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  State                 The new state to be set.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockSetState (\r
+  IN SOCKET     *Sock,\r
+  IN SOCK_STATE State\r
+  )\r
+{\r
+  Sock->State = State;\r
+}\r
+\r
+\r
+/**\r
+  Clone a new socket including its associated protocol control block.\r
+\r
+  @param  Sock                  Pointer to the socket to be cloned.\r
+\r
+  @retval *                     Pointer to the newly cloned socket. If NULL, error\r
+                                condition occurred.\r
+\r
+**/\r
+SOCKET *\r
+SockClone (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  SOCKET          *ClonedSock;\r
+  SOCK_INIT_DATA  InitData;\r
+\r
+  InitData.BackLog        = Sock->BackLog;\r
+  InitData.Parent         = Sock;\r
+  InitData.State          = Sock->State;\r
+  InitData.ProtoHandler   = Sock->ProtoHandler;\r
+  InitData.Type           = Sock->Type;\r
+  InitData.RcvBufferSize  = Sock->RcvBuffer.HighWater;\r
+  InitData.SndBufferSize  = Sock->SndBuffer.HighWater;\r
+  InitData.DriverBinding  = Sock->DriverBinding;\r
+  InitData.Protocol       = &(Sock->NetProtocol);\r
+\r
+  ClonedSock              = SockCreate (&InitData);\r
+\r
+  if (NULL == ClonedSock) {\r
+    SOCK_DEBUG_ERROR (("SockClone: no resource to create a cloned sock\n"));\r
+    return NULL;\r
+  }\r
+\r
+  NetCopyMem (\r
+    ClonedSock->ProtoReserved,\r
+    Sock->ProtoReserved,\r
+    PROTO_RESERVED_LEN\r
+    );\r
+\r
+  SockSetState (ClonedSock, SO_CONNECTING);\r
+  ClonedSock->ConfigureState = Sock->ConfigureState;\r
+\r
+  return ClonedSock;\r
+}\r
+\r
+\r
+/**\r
+  Called by the low layer protocol to indicate the socket\r
+  a connection is established. This function just changes\r
+  the socket's state to SO_CONNECTED and signals the token\r
+  used for connection establishment.\r
+\r
+  @param  Sock                  Pointer to the socket associated with the\r
+                                established connection.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockConnEstablished (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+\r
+  ASSERT (SO_CONNECTING == Sock->State);\r
+\r
+  SockSetState (Sock, SO_CONNECTED);\r
+\r
+  if (NULL == Sock->Parent) {\r
+    SockWakeConnToken (Sock);\r
+  } else {\r
+    SockWakeListenToken (Sock);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Called by the low layer protocol to indicate the connection\r
+  is closed. This function flushes the socket, sets the state\r
+  to SO_CLOSED and signals the close token.\r
+\r
+  @param  Sock                  Pointer to the socket associated with the closed\r
+                                connection.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockConnClosed (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  if (Sock->CloseToken) {\r
+    SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);\r
+    Sock->CloseToken = NULL;\r
+  }\r
+\r
+  SockConnFlush (Sock);\r
+  SockSetState (Sock, SO_CLOSED);\r
+\r
+  if (Sock->Parent != NULL) {\r
+    SockDestroyChild (Sock);\r
+  }\r
+\r
+}\r
+\r
+\r
+/**\r
+  Called by low layer protocol to indicate that some\r
+  data is sent or processed. This function trims the\r
+  sent data in the socket send buffer, signals the\r
+  data token if proper\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  Count                 The length of the data processed or sent, in bytes.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockDataSent (\r
+  IN SOCKET     *Sock,\r
+  IN UINT32     Count\r
+  )\r
+{\r
+  SOCK_TOKEN            *SockToken;\r
+  SOCK_COMPLETION_TOKEN *SndToken;\r
+\r
+  ASSERT (!NetListIsEmpty (&Sock->ProcessingSndTokenList));\r
+  ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);\r
+\r
+  NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);\r
+\r
+  //\r
+  // To check if we can signal some snd token in this socket\r
+  //\r
+  while (Count > 0) {\r
+    SockToken = NET_LIST_HEAD (\r
+                  &(Sock->ProcessingSndTokenList),\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    SndToken = SockToken->Token;\r
+\r
+    if (SockToken->RemainDataLen <= Count) {\r
+\r
+      NetListRemoveEntry (&(SockToken->TokenList));\r
+      SIGNAL_TOKEN (SndToken, EFI_SUCCESS);\r
+      Count -= SockToken->RemainDataLen;\r
+      NetFreePool (SockToken);\r
+    } else {\r
+\r
+      SockToken->RemainDataLen -= Count;\r
+      Count = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // to judge if we can process some send token in\r
+  // Sock->SndTokenList, if so process those send token\r
+  //\r
+  SockProcessSndToken (Sock);\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Called by the low layer protocol to copy some data in socket send\r
+  buffer starting from the specific offset to a buffer provided by\r
+  the caller.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  Offset                The start point of the data to be copied.\r
+  @param  Len                   The length of the data to be copied.\r
+  @param  Dest                  Pointer to the destination to copy the data.\r
+\r
+  @return The data size copied.\r
+\r
+**/\r
+UINT32\r
+SockGetDataToSend (\r
+  IN SOCKET      *Sock,\r
+  IN UINT32      Offset,\r
+  IN UINT32      Len,\r
+  IN UINT8       *Dest\r
+  )\r
+{\r
+  ASSERT (Sock && SOCK_STREAM == Sock->Type);\r
+\r
+  return NetbufQueCopy (\r
+          Sock->SndBuffer.DataQueue,\r
+          Offset,\r
+          Len,\r
+          Dest\r
+          );\r
+}\r
+\r
+\r
+/**\r
+  Called by the low layer protocol to deliver received data\r
+  to socket layer. This function will append the data to the\r
+  socket receive buffer, set ther urgent data length and then\r
+  check if any receive token can be signaled.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  NetBuffer             Pointer to the buffer that contains the received\r
+                                data.\r
+  @param  UrgLen                The length of the urgent data in the received data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockDataRcvd (\r
+  IN SOCKET    *Sock,\r
+  IN NET_BUF   *NetBuffer,\r
+  IN UINT32    UrgLen\r
+  )\r
+{\r
+  ASSERT (Sock && Sock->RcvBuffer.DataQueue &&\r
+    UrgLen <= NetBuffer->TotalSize);\r
+\r
+  NET_GET_REF (NetBuffer);\r
+\r
+  ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;\r
+\r
+  NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);\r
+\r
+  SockWakeRcvToken (Sock);\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Get the length of the free space of the specific socket buffer.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  Which                 Flag to indicate which socket buffer to check,\r
+                                either send buffer or receive buffer.\r
+\r
+  @return The length of the free space, in bytes.\r
+\r
+**/\r
+UINT32\r
+SockGetFreeSpace (\r
+  IN SOCKET  *Sock,\r
+  IN UINT32  Which\r
+  )\r
+{\r
+  UINT32      BufferCC;\r
+  SOCK_BUFFER *SockBuffer;\r
+\r
+  ASSERT (Sock && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));\r
+\r
+  if (SOCK_SND_BUF == Which) {\r
+    SockBuffer = &(Sock->SndBuffer);\r
+  } else {\r
+    SockBuffer = &(Sock->RcvBuffer);\r
+  }\r
+\r
+  BufferCC = (SockBuffer->DataQueue)->BufSize;\r
+\r
+  if (BufferCC >= SockBuffer->HighWater) {\r
+\r
+    return 0;\r
+  }\r
+\r
+  return SockBuffer->HighWater - BufferCC;\r
+}\r
+\r
+\r
+/**\r
+  Signal the receive token with the specific error or\r
+  set socket error code after error is received.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+  @param  Error                 The error code received.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockRcvdErr (\r
+  IN SOCKET       *Sock,\r
+  IN EFI_STATUS   Error\r
+  )\r
+{\r
+  SOCK_TOKEN  *SockToken;\r
+\r
+  if (!NetListIsEmpty (&Sock->RcvTokenList)) {\r
+\r
+    SockToken = NET_LIST_HEAD (\r
+                  &Sock->RcvTokenList,\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    NetListRemoveEntry (&SockToken->TokenList);\r
+\r
+    SIGNAL_TOKEN (SockToken->Token, Error);\r
+\r
+    NetFreePool (SockToken);\r
+  } else {\r
+\r
+    SOCK_ERROR (Sock, Error);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Called by the low layer protocol to indicate that there\r
+  will be no more data from the communication peer. This\r
+  function set the socket's state to SO_NO_MORE_DATA and\r
+  signal all queued IO tokens with the error status\r
+  EFI_CONNECTION_FIN.\r
+\r
+  @param  Sock                  Pointer to the socket.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+SockNoMoreData (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  EFI_STATUS  Err;\r
+\r
+  SOCK_NO_MORE_DATA (Sock);\r
+\r
+  if (!NetListIsEmpty (&Sock->RcvTokenList)) {\r
+\r
+    ASSERT (0 == GET_RCV_DATASIZE (Sock));\r
+\r
+    Err = Sock->SockError;\r
+\r
+    SOCK_ERROR (Sock, EFI_CONNECTION_FIN);\r
+\r
+    SockFlushPendingToken (Sock, &Sock->RcvTokenList);\r
+\r
+    SOCK_ERROR (Sock, Err);\r
+\r
+  }\r
+\r
+}\r
+\r
+\r
+/**\r
+  Get the first buffer block in the specific socket buffer.\r
+\r
+  @param  Sockbuf               Pointer to the socket buffer.\r
+\r
+  @return Pointer to the first buffer in the queue. NULL if the queue is empty.\r
+\r
+**/\r
+NET_BUF *\r
+SockBufFirst (\r
+  IN SOCK_BUFFER *Sockbuf\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *NetbufList;\r
+\r
+  NetbufList = &(Sockbuf->DataQueue->BufList);\r
+\r
+  if (NetListIsEmpty (NetbufList)) {\r
+    return NULL;\r
+  }\r
+\r
+  return NET_LIST_HEAD (NetbufList, NET_BUF, List);\r
+}\r
+\r
+\r
+/**\r
+  Get the next buffer block in the specific socket buffer.\r
+\r
+  @param  Sockbuf               Pointer to the socket buffer.\r
+  @param  SockEntry             Pointer to the buffer block prior to the required\r
+                                one.\r
+\r
+  @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is the tail or head entry.\r
+\r
+**/\r
+NET_BUF *\r
+SockBufNext (\r
+  IN SOCK_BUFFER *Sockbuf,\r
+  IN NET_BUF     *SockEntry\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *NetbufList;\r
+\r
+  NetbufList = &(Sockbuf->DataQueue->BufList);\r
+\r
+  if ((SockEntry->List.ForwardLink == NetbufList) ||\r
+      (SockEntry->List.BackLink == &SockEntry->List) ||\r
+      (SockEntry->List.ForwardLink == &SockEntry->List)\r
+      ) {\r
+\r
+    return NULL;\r
+  }\r
+\r
+  return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.h
new file mode 100644 (file)
index 0000000..69a1ac6
--- /dev/null
@@ -0,0 +1,84 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  SockImpl.h
+
+Abstract:
+
+
+**/
+
+#ifndef _SOCK_IMPL_H_
+#define _SOCK_IMPL_H_
+
+#include "Socket.h"
+
+#define SOCK_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR("Sock", PrintArg)
+#define SOCK_DEBUG_WARN(PrintArg)  NET_DEBUG_WARNING("Sock", PrintArg)
+#define SOCK_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE("Sock", PrintArg)
+
+#define SOCK_TRIM_RCV_BUFF(Sock, Len) \
+  (NetbufQueTrim ((Sock)->RcvBuffer.DataQueue, (Len)))
+
+#define SIGNAL_TOKEN(Token, TokenStatus) \
+  do { \
+    (Token)->Status = (TokenStatus); \
+    gBS->SignalEvent ((Token)->Event); \
+  } while (0)
+
+#define SOCK_HEADER_SPACE (60 + 60 + 72)
+
+//
+// Supporting function for both SockImpl and SockInterface
+//
+VOID
+SockFreeFoo (
+  IN EFI_EVENT Event
+  );
+
+EFI_STATUS
+SockProcessTcpSndData (
+  IN SOCKET *Sock,
+  IN VOID   *TcpTxData
+  );
+
+VOID
+SockSetTcpRxData (
+  IN SOCKET         *Sock,
+  IN VOID           *TcpRxData,
+  IN UINT32         RcvdBytes,
+  IN BOOLEAN        IsOOB
+  );
+
+UINT32
+SockProcessRcvToken (
+  IN SOCKET        *Sock,
+  IN SOCK_IO_TOKEN *RcvToken
+  );
+
+VOID
+SockConnFlush (
+  IN SOCKET *Sock
+  );
+
+SOCKET  *
+SockCreate (
+  IN SOCK_INIT_DATA *SockInitData
+  );
+
+VOID
+SockDestroy (
+  IN SOCKET *Sock
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/SockInterface.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/SockInterface.c
new file mode 100644 (file)
index 0000000..0b71996
--- /dev/null
@@ -0,0 +1,980 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  SockInterface.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "SockImpl.h"\r
+\r
+\r
+/**\r
+  Check whether the Event is in the List.\r
+\r
+  @param  List                 Pointer to the token list to be searched.\r
+  @param  Event                The event to be checked.\r
+\r
+  @retval BOOLEAN              If TRUE, the specific Event exists in the List. If\r
+                               FALSE, the specific Event is not in the List.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SockTokenExistedInList (\r
+  IN NET_LIST_ENTRY *List,\r
+  IN EFI_EVENT      Event\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *ListEntry;\r
+  SOCK_TOKEN      *SockToken;\r
+\r
+  NET_LIST_FOR_EACH (ListEntry, List) {\r
+    SockToken = NET_LIST_USER_STRUCT (\r
+                  ListEntry,\r
+                  SOCK_TOKEN,\r
+                  TokenList\r
+                  );\r
+\r
+    if (Event == SockToken->Token->Event) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Call SockTokenExistedInList() to check whether the Event is\r
+  in the related socket's lists.\r
+\r
+  @param  Sock                 Pointer to the instance's socket.\r
+  @param  Event                The event to be checked.\r
+\r
+  @return The specific Event exists in one of socket's lists or not.\r
+\r
+**/\r
+BOOLEAN\r
+SockTokenExisted (\r
+  IN SOCKET    *Sock,\r
+  IN EFI_EVENT Event\r
+  )\r
+{\r
+\r
+  if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||\r
+      SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||\r
+      SockTokenExistedInList (&Sock->RcvTokenList, Event) ||\r
+      SockTokenExistedInList (&Sock->ListenTokenList, Event)\r
+        ) {\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  if ((Sock->ConnectionToken != NULL) &&\r
+      (Sock->ConnectionToken->Event == Event)) {\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Buffer a token into the specific list of socket Sock.\r
+\r
+  @param  Sock                 Pointer to the instance's socket.\r
+  @param  List                 Pointer to the list to store the token.\r
+  @param  Token                Pointer to the token to be buffered.\r
+  @param  DataLen              The data length of the buffer contained in Token.\r
+\r
+  @return Pointer to the token that wraps Token. If NULL, error condition occurred.\r
+\r
+**/\r
+SOCK_TOKEN *\r
+SockBufferToken (\r
+  IN SOCKET         *Sock,\r
+  IN NET_LIST_ENTRY *List,\r
+  IN VOID           *Token,\r
+  IN UINT32         DataLen\r
+  )\r
+{\r
+  SOCK_TOKEN  *SockToken;\r
+\r
+  SockToken = NetAllocatePool (sizeof (SOCK_TOKEN));\r
+  if (NULL == SockToken) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockBufferIOToken: No Memory "\r
+      "to allocate SockToken\n"));\r
+\r
+    return NULL;\r
+  }\r
+\r
+  SockToken->Sock           = Sock;\r
+  SockToken->Token          = (SOCK_COMPLETION_TOKEN *) Token;\r
+  SockToken->RemainDataLen  = DataLen;\r
+  NetListInsertTail (List, &SockToken->TokenList);\r
+\r
+  return SockToken;\r
+}\r
+\r
+\r
+/**\r
+  Destory the socket Sock and its associated protocol control block.\r
+\r
+  @param  Sock                 The socket to be destroyed.\r
+\r
+  @retval EFI_SUCCESS          The socket Sock is destroyed successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.\r
+\r
+**/\r
+EFI_STATUS\r
+SockDestroyChild (\r
+  IN   SOCKET *Sock\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (Sock && Sock->ProtoHandler);\r
+\r
+  if (Sock->IsDestroyed) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Sock->IsDestroyed = TRUE;\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockDestroyChild: Get the lock to "\r
+      "access socket failed with %r\n", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // force protocol layer to detach the PCB\r
+  //\r
+  Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockDestroyChild: Protocol detach socket"\r
+      " failed with %r\n", Status));\r
+\r
+    Sock->IsDestroyed = FALSE;\r
+  } else if (SOCK_IS_CONFIGURED (Sock)) {\r
+\r
+    SockConnFlush (Sock);\r
+    SockSetState (Sock, SO_CLOSED);\r
+\r
+    Sock->ConfigureState = SO_UNCONFIGURED;\r
+  }\r
+\r
+  NET_UNLOCK (&(Sock->Lock));\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SockDestroy (Sock);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Create a socket and its associated protocol control block\r
+  with the intial data SockInitData and protocol specific\r
+  data ProtoData.\r
+\r
+  @param  SockInitData         Inital data to setting the socket.\r
+  @param  ProtoData            Pointer to the protocol specific data.\r
+  @param  Len                  Length of the protocol specific data.\r
+\r
+  @return Pointer to the newly created socket. If NULL, error condition occured.\r
+\r
+**/\r
+SOCKET *\r
+SockCreateChild (\r
+  IN SOCK_INIT_DATA *SockInitData,\r
+  IN VOID           *ProtoData,\r
+  IN UINT32         Len\r
+  )\r
+{\r
+  SOCKET      *Sock;\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (ProtoData && (Len <= PROTO_RESERVED_LEN));\r
+\r
+  //\r
+  // create a new socket\r
+  //\r
+  Sock = SockCreate (SockInitData);\r
+  if (NULL == Sock) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockCreateChild: No resource to "\r
+      "create a new socket\n"));\r
+\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Open the\r
+  //\r
+\r
+  //\r
+  // copy the protodata into socket\r
+  //\r
+  NetCopyMem (Sock->ProtoReserved, ProtoData, Len);\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockCreateChild: Get the lock to "\r
+      "access socket failed with %r\n", Status));\r
+\r
+    SockDestroy (Sock);\r
+    return NULL;\r
+  }\r
+  //\r
+  // inform the protocol layer to attach the socket\r
+  // with a new protocol control block\r
+  //\r
+  Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockCreateChild: Protocol failed to"\r
+      " attach a socket with %r\n", Status));\r
+\r
+    SockDestroy (Sock);\r
+    Sock = NULL;\r
+  }\r
+\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Sock;\r
+}\r
+\r
+\r
+/**\r
+  Configure the specific socket Sock using configuration data\r
+  ConfigData.\r
+\r
+  @param  Sock                 Pointer to the socket to be configured.\r
+  @param  ConfigData           Pointer to the configuration data.\r
+\r
+  @retval EFI_SUCCESS          The socket is configured successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket or the\r
+                               socket is already configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockConfigure (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *ConfigData\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockConfigure: Get the access for "\r
+      "socket failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_CONFIGURED (Sock)) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto OnExit;\r
+  }\r
+\r
+  ASSERT (Sock->State == SO_CLOSED);\r
+\r
+  Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);\r
+\r
+OnExit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Initiate a connection establishment process.\r
+\r
+  @param  Sock                 Pointer to the socket to initiate the initate the\r
+                               connection.\r
+  @param  Token                Pointer to the token used for the connection\r
+                               operation.\r
+\r
+  @retval EFI_SUCCESS          The connection is initialized successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the\r
+                               socket is closed, or the socket is not configured to\r
+                               be an active one, or the token is already in one of\r
+                               this socket's lists.\r
+  @retval EFI_NO_MAPPING       The IP address configuration operation is not\r
+                               finished.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockConnect (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *Token\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   Event;\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockConnect: Get the access for "\r
+      "socket failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_NO_MAPPING (Sock)) {\r
+    Status = EFI_NO_MAPPING;\r
+    goto OnExit;\r
+  }\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto OnExit;\r
+  }\r
+\r
+  if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto OnExit;\r
+  }\r
+\r
+  Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+  if (SockTokenExisted (Sock, Event)) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto OnExit;\r
+  }\r
+\r
+  Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;\r
+  SockSetState (Sock, SO_CONNECTING);\r
+  Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);\r
+\r
+OnExit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Issue a listen token to get an existed connected network instance\r
+  or wait for a connection if there is none.\r
+\r
+  @param  Sock                 Pointer to the socket to accept connections.\r
+  @param  Token                The token to accept a connection.\r
+\r
+  @retval EFI_SUCCESS          Either a connection is accpeted or the Token is\r
+                               buffered for further acception.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the\r
+                               socket is closed, or the socket is not configured to\r
+                               be a passive one, or the token is already in one of\r
+                               this socket's lists.\r
+  @retval EFI_NO_MAPPING       The IP address configuration operation is not\r
+                               finished.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+  @retval EFI_OUT_OF_RESOURCE  Failed to buffer the Token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockAccept (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *Token\r
+  )\r
+{\r
+  EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
+  NET_LIST_ENTRY        *ListEntry;\r
+  EFI_STATUS            Status;\r
+  SOCKET                *Socket;\r
+  EFI_EVENT             Event;\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockAccept: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_NO_MAPPING (Sock)) {\r
+    Status = EFI_NO_MAPPING;\r
+    goto Exit;\r
+  }\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto Exit;\r
+  }\r
+\r
+  if (!SOCK_IS_LISTENING (Sock)) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+  if (SockTokenExisted (Sock, Event)) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;\r
+\r
+  //\r
+  // Check if a connection has already in this Sock->ConnectionList\r
+  //\r
+  NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {\r
+\r
+    Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);\r
+\r
+    if (SOCK_IS_CONNECTED (Socket)) {\r
+      ListenToken->NewChildHandle = Socket->SockHandle;\r
+      SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
+\r
+      NetListRemoveEntry (ListEntry);\r
+\r
+      ASSERT (Socket->Parent);\r
+\r
+      Socket->Parent->ConnCnt--;\r
+\r
+      SOCK_DEBUG_WARN (("SockAccept: Accept a socket,"\r
+        "now conncount is %d", Socket->Parent->ConnCnt)\r
+        );\r
+      Socket->Parent = NULL;\r
+\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Buffer this token for latter incoming connection request\r
+  //\r
+  if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Issue a token with data to the socket to send out.\r
+\r
+  @param  Sock                 Pointer to the socket to process the token with\r
+                               data.\r
+  @param  Token                The token with data that needs to send out.\r
+\r
+  @retval EFI_SUCCESS          The token is processed successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the\r
+                               socket is closed, or the socket is not in a\r
+                               synchronized state , or the token is already in one\r
+                               of this socket's lists.\r
+  @retval EFI_NO_MAPPING       The IP address configuration operation is not\r
+                               finished.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+  @retval EFI_OUT_OF_RESOURCE  Failed to buffer the token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockSend (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *Token\r
+  )\r
+{\r
+  SOCK_IO_TOKEN           *SndToken;\r
+  EFI_EVENT               Event;\r
+  UINT32                  FreeSpace;\r
+  EFI_TCP4_TRANSMIT_DATA  *TxData;\r
+  EFI_STATUS              Status;\r
+  SOCK_TOKEN              *SockToken;\r
+  UINT32                  DataLen;\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockSend: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_NO_MAPPING (Sock)) {\r
+    Status = EFI_NO_MAPPING;\r
+    goto Exit;\r
+  }\r
+\r
+  SndToken  = (SOCK_IO_TOKEN *) Token;\r
+  TxData    = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto Exit;\r
+  }\r
+\r
+  if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // check if a token is already in the token buffer\r
+  //\r
+  Event = SndToken->Token.Event;\r
+\r
+  if (SockTokenExisted (Sock, Event)) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  DataLen = TxData->DataLength;\r
+\r
+  //\r
+  // process this sending token now or buffer it only?\r
+  //\r
+  FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
+\r
+  if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {\r
+\r
+    SockToken = SockBufferToken (\r
+                  Sock,\r
+                  &Sock->SndTokenList,\r
+                  SndToken,\r
+                  DataLen\r
+                  );\r
+\r
+    if (NULL == SockToken) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+\r
+    SockToken = SockBufferToken (\r
+                  Sock,\r
+                  &Sock->ProcessingSndTokenList,\r
+                  SndToken,\r
+                  DataLen\r
+                  );\r
+\r
+    if (NULL == SockToken) {\r
+      SOCK_DEBUG_ERROR (("SockSend: Failed to buffer IO token into"\r
+        " socket processing SndToken List\n", Status));\r
+\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Exit;\r
+    }\r
+\r
+    Status = SockProcessTcpSndData (Sock, TxData);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      SOCK_DEBUG_ERROR (("SockSend: Failed to process "\r
+        "Snd Data\n", Status));\r
+\r
+      NetListRemoveEntry (&(SockToken->TokenList));\r
+      NetFreePool (SockToken);\r
+    }\r
+  }\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Issue a token to get data from the socket.\r
+\r
+  @param  Sock                 Pointer to the socket to get data from.\r
+  @param  Token                The token to store the received data from the\r
+                               socket.\r
+\r
+  @retval EFI_SUCCESS          The token is processed successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the\r
+                               socket is closed, or the socket is not in a\r
+                               synchronized state , or the token is already in one\r
+                               of this socket's lists.\r
+  @retval EFI_NO_MAPPING       The IP address configuration operation is not\r
+                               finished.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+  @retval EFI_CONNECTION_FIN   The connection is closed and there is no more data.\r
+  @retval EFI_OUT_OF_RESOURCE  Failed to buffer the token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockRcv (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *Token\r
+  )\r
+{\r
+  SOCK_IO_TOKEN *RcvToken;\r
+  UINT32        RcvdBytes;\r
+  EFI_STATUS    Status;\r
+  EFI_EVENT     Event;\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockRcv: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_NO_MAPPING (Sock)) {\r
+\r
+    Status = EFI_NO_MAPPING;\r
+    goto Exit;\r
+  }\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+    Status = EFI_NOT_STARTED;\r
+    goto Exit;\r
+  }\r
+\r
+  if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  RcvToken = (SOCK_IO_TOKEN *) Token;\r
+\r
+  //\r
+  // check if a token is already in the token buffer of this socket\r
+  //\r
+  Event = RcvToken->Token.Event;\r
+  if (SockTokenExisted (Sock, Event)) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  RcvToken  = (SOCK_IO_TOKEN *) Token;\r
+  RcvdBytes = GET_RCV_DATASIZE (Sock);\r
+\r
+  //\r
+  // check whether an error has happened before\r
+  //\r
+  if (EFI_ABORTED != Sock->SockError) {\r
+\r
+    SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);\r
+    Sock->SockError = EFI_ABORTED;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // check whether can not receive and there is no any\r
+  // data buffered in Sock->RcvBuffer\r
+  //\r
+  if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {\r
+\r
+    Status = EFI_CONNECTION_FIN;\r
+    goto Exit;\r
+  }\r
+\r
+  if (RcvdBytes != 0) {\r
+    Status = SockProcessRcvToken (Sock, RcvToken);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);\r
+  } else {\r
+\r
+    if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reset the socket and its associated protocol control block.\r
+\r
+  @param  Sock                 Pointer to the socket to be flushed.\r
+\r
+  @retval EFI_SUCCESS          The socket is flushed successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.\r
+\r
+**/\r
+EFI_STATUS\r
+SockFlush (\r
+  IN SOCKET *Sock\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockFlush: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (!SOCK_IS_CONFIGURED (Sock)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockFlush: Protocol failed handling"\r
+      " SOCK_FLUSH with %r", Status));\r
+\r
+    goto Exit;\r
+  }\r
+\r
+  SOCK_ERROR (Sock, EFI_ABORTED);\r
+  SockConnFlush (Sock);\r
+  SockSetState (Sock, SO_CLOSED);\r
+\r
+  Sock->ConfigureState = SO_UNCONFIGURED;\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close or abort the socket associated connection.\r
+\r
+  @param  Sock                 Pointer to the socket of the connection to close or\r
+                               abort.\r
+  @param  Token                The token for close operation.\r
+  @param  OnAbort              TRUE for aborting the connection, FALSE to close it.\r
+\r
+  @retval EFI_SUCCESS          The close or abort operation is initialized\r
+                               successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the\r
+                               socket is closed, or the socket is not in a\r
+                               synchronized state , or the token is already in one\r
+                               of this socket's lists.\r
+  @retval EFI_NO_MAPPING       The IP address configuration operation is not\r
+                               finished.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockClose (\r
+  IN SOCKET  *Sock,\r
+  IN VOID    *Token,\r
+  IN BOOLEAN OnAbort\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   Event;\r
+\r
+  ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+    SOCK_DEBUG_ERROR (("SockClose: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_NO_MAPPING (Sock)) {\r
+    Status = EFI_NO_MAPPING;\r
+    goto Exit;\r
+  }\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto Exit;\r
+  }\r
+\r
+  if (SOCK_IS_DISCONNECTING (Sock)) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+  if (SockTokenExisted (Sock, Event)) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Exit;\r
+  }\r
+\r
+  Sock->CloseToken = Token;\r
+  SockSetState (Sock, SO_DISCONNECTING);\r
+\r
+  if (OnAbort) {\r
+    Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);\r
+  } else {\r
+    Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);\r
+  }\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the mode data of the low layer protocol.\r
+\r
+  @param  Sock                 Pointer to the socket to get mode data from.\r
+  @param  Mode                 Pointer to the data to store the low layer mode\r
+                               information.\r
+\r
+  @retval EFI_SUCCESS          The mode data is got successfully.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockGetMode (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *Mode\r
+  )\r
+{\r
+  return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);\r
+}\r
+\r
+\r
+/**\r
+  Configure the low level protocol to join a multicast group for\r
+  this socket's connection.\r
+\r
+  @param  Sock                 Pointer to the socket of the connection to join the\r
+                               specific multicast group.\r
+  @param  GroupInfo            Pointer to the multicast group info.\r
+\r
+  @retval EFI_SUCCESS          The configuration is done successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockGroup (\r
+  IN SOCKET *Sock,\r
+  IN VOID   *GroupInfo\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    SOCK_DEBUG_ERROR (("SockGroup: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto Exit;\r
+  }\r
+\r
+  Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Add or remove route information in IP route table associated\r
+  with this socket.\r
+\r
+  @param  Sock                 Pointer to the socket associated with the IP route\r
+                               table to operate on.\r
+  @param  RouteInfo            Pointer to the route information to be processed.\r
+\r
+  @retval EFI_SUCCESS          The route table is updated successfully.\r
+  @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.\r
+  @retval EFI_NO_MAPPING       The IP address configuration operation is  not\r
+                               finished.\r
+  @retval EFI_NOT_STARTED      The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockRoute (\r
+  IN SOCKET    *Sock,\r
+  IN VOID      *RouteInfo\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = NET_TRYLOCK (&(Sock->Lock));\r
+  if (EFI_ERROR (Status)) {\r
+    SOCK_DEBUG_ERROR (("SockRoute: Get the access for socket"\r
+      " failed with %r", Status));\r
+\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (SOCK_IS_NO_MAPPING (Sock)) {\r
+    Status = EFI_NO_MAPPING;\r
+    goto Exit;\r
+  }\r
+\r
+  if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto Exit;\r
+  }\r
+\r
+  Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);\r
+\r
+Exit:\r
+  NET_UNLOCK (&(Sock->Lock));\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Socket.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/Socket.h
new file mode 100644 (file)
index 0000000..f397854
--- /dev/null
@@ -0,0 +1,518 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Socket.h
+
+Abstract:
+
+
+**/
+
+#ifndef _SOCKET_H_
+#define _SOCKET_H_
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IP4.h>\r
+#include <Protocol/Tcp4.h>
+#include <Protocol/Udp4.h>\r
+
+#include <Library/NetLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#define SOCK_SND_BUF        0
+#define SOCK_RCV_BUF        1
+
+#define SOCK_BUFF_LOW_WATER 2 * 1024
+#define SOCK_RCV_BUFF_SIZE  8 * 1024
+#define SOCK_SND_BUFF_SIZE  8 * 1024
+#define SOCK_BACKLOG        5
+
+#define PROTO_RESERVED_LEN  20
+
+#define SO_NO_MORE_DATA     0x0001
+
+//
+//
+//
+// When a socket is created it enters into SO_UNCONFIGURED,
+// no actions can be taken on this socket, only after calling
+// SockConfigure. The state transition diagram of socket is
+// as following:
+//
+// SO_UNCONFIGURED --- SO_CONFIGURED --- SO_CONNECTING
+//  ^      |                                    |
+//  |      --->  SO_LISTENING                   |
+//  |                                           |
+//  |------------------SO_DISCONNECTING<-- SO_CONNECTED
+//
+// A passive socket can only go into SO_LISTENING and
+// SO_UNCONFIGURED state. SO_XXXING state is a middle state
+// when a socket is undergoing a protocol procedure such
+// as requesting a TCP connection.
+//
+//
+//
+typedef enum {
+  SO_CLOSED       = 0,
+  SO_LISTENING,
+  SO_CONNECTING,
+  SO_CONNECTED,
+  SO_DISCONNECTING
+} SOCK_STATE;
+
+typedef enum {
+  SO_UNCONFIGURED       = 0,
+  SO_CONFIGURED_ACTIVE,
+  SO_CONFIGURED_PASSIVE,
+  SO_NO_MAPPING
+} SOCK_CONFIGURE_STATE;
+
+#define SOCK_NO_MORE_DATA(Sock)     ((Sock)->Flag |= SO_NO_MORE_DATA)
+
+#define SOCK_IS_UNCONFIGURED(Sock)  ((Sock)->ConfigureState == SO_UNCONFIGURED)
+
+#define SOCK_IS_CONFIGURED(Sock) \
+    (((Sock)->ConfigureState == SO_CONFIGURED_ACTIVE) || \
+    ((Sock)->ConfigureState == SO_CONFIGURED_PASSIVE))
+
+#define SOCK_IS_CONFIGURED_ACTIVE(Sock) \
+  ((Sock)->ConfigureState == SO_CONFIGURED_ACTIVE)
+
+#define SOCK_IS_CONNECTED_PASSIVE(Sock) \
+  ((Sock)->ConfigureState == SO_CONFIGURED_PASSIVE)
+
+#define SOCK_IS_NO_MAPPING(Sock) \
+  ((Sock)->ConfigureState == SO_NO_MAPPING)
+
+#define SOCK_IS_CLOSED(Sock)         ((Sock)->State == SO_CLOSED)
+
+#define SOCK_IS_LISTENING(Sock)      ((Sock)->State == SO_LISTENING)
+
+#define SOCK_IS_CONNECTING(Sock)     ((Sock)->State == SO_CONNECTING)
+
+#define SOCK_IS_CONNECTED(Sock)      ((Sock)->State == SO_CONNECTED)
+
+#define SOCK_IS_DISCONNECTING(Sock)  ((Sock)->State == SO_DISCONNECTING)
+
+#define SOCK_IS_NO_MORE_DATA(Sock)   (0 != ((Sock)->Flag & SO_NO_MORE_DATA))
+
+#define SOCK_SIGNATURE           EFI_SIGNATURE_32 ('S', 'O', 'C', 'K')
+
+#define SOCK_FROM_THIS(a)        CR ((a), SOCKET, NetProtocol, SOCK_SIGNATURE)
+
+#define SET_RCV_BUFFSIZE(Sock, Size)  ((Sock)->RcvBuffer.HighWater = (Size))
+
+#define GET_RCV_BUFFSIZE(Sock)        ((Sock)->RcvBuffer.HighWater)
+
+#define GET_RCV_DATASIZE(Sock)        (((Sock)->RcvBuffer.DataQueue)->BufSize)
+
+#define SET_SND_BUFFSIZE(Sock, Size)  ((Sock)->SndBuffer.HighWater = (Size))
+
+#define GET_SND_BUFFSIZE(Sock)        ((Sock)->SndBuffer.HighWater)
+
+#define GET_SND_DATASIZE(Sock)        (((Sock)->SndBuffer.DataQueue)->BufSize)
+
+#define SET_BACKLOG(Sock, Value)      ((Sock)->BackLog = (Value))
+
+#define GET_BACKLOG(Sock)             ((Sock)->BackLog)
+
+#define SOCK_ERROR(Sock, Error)       ((Sock)->SockError = (Error))
+
+#define SND_BUF_HDR_LEN(Sock) \
+  ((SockBufFirst (&((Sock)->SndBuffer)))->TotalSize)
+
+#define RCV_BUF_HDR_LEN(Sock) \
+  ((SockBufFirst (&((Sock)->RcvBuffer)))->TotalSize)
+
+#define SOCK_FROM_TOKEN(Token)        (((SOCK_TOKEN *) (Token))->Sock)
+
+#define PROTO_TOKEN_FORM_SOCK(SockToken, Type) \
+  ((Type *) (((SOCK_TOKEN *) (SockToken))->Token))
+
+typedef struct _SOCKET SOCKET;
+
+typedef struct _SOCK_COMPLETION_TOKEN {
+  EFI_EVENT   Event;
+  EFI_STATUS  Status;
+} SOCK_COMPLETION_TOKEN;
+
+typedef struct _SOCK_IO_TOKEN {
+  SOCK_COMPLETION_TOKEN Token;
+  union {
+    VOID  *RxData;
+    VOID  *TxData;
+  } Packet;
+} SOCK_IO_TOKEN;
+
+//
+// the request issued from socket layer to protocol layer
+//
+typedef enum {
+  SOCK_ATTACH,    // attach current socket to a new PCB
+  SOCK_DETACH,    // detach current socket from the PCB
+  SOCK_CONFIGURE, // configure attached PCB
+  SOCK_FLUSH,     // flush attached PCB
+  SOCK_SND,       // need protocol to send something
+  SOCK_SNDPUSH,   // need protocol to send pushed data
+  SOCK_SNDURG,    // need protocol to send urgent data
+  SOCK_CONSUMED,  // application has retrieved data from socket
+  SOCK_CONNECT,   // need to connect to a peer
+  SOCK_CLOSE,     // need to close the protocol process
+  SOCK_ABORT,     // need to reset the protocol process
+  SOCK_POLL,      // need to poll to the protocol layer
+  SOCK_ROUTE,     // need to add a route information
+  SOCK_MODE,      // need to get the mode data of the protocol
+  SOCK_GROUP      // need to join a mcast group
+} SOCK_REQUEST;
+
+//
+// the socket type
+//
+typedef enum {
+  SOCK_DGRAM, // this socket providing datagram service
+  SOCK_STREAM // this socket providing stream service
+} SOCK_TYPE;
+
+//
+// the handler of protocol for request from socket
+//
+typedef
+EFI_STATUS
+(*SOCK_PROTO_HANDLER) (
+  IN SOCKET       * Socket,  // the socket issuing the request to protocol
+  IN SOCK_REQUEST Request,   // the request issued by socket
+  IN VOID *RequestData       // the request related data
+  );
+
+//
+// the buffer structure of rcvd data and send data used by socket
+//
+typedef struct _SOCK_BUFFER {
+  UINT32        HighWater;  // the buffersize upper limit of sock_buffer
+  UINT32        LowWater;   // the low warter mark of sock_buffer
+  NET_BUF_QUEUE *DataQueue; // the queue to buffer data
+} SOCK_BUFFER;
+
+//
+// the initialize data for create a new socket
+//
+typedef struct _SOCK_INIT_DATA {
+  SOCK_TYPE   Type;
+  SOCK_STATE  State;
+
+  SOCKET      *Parent;        // the parent of this socket
+  UINT32      BackLog;        // the connection limit for listening socket
+  UINT32      SndBufferSize;  // the high warter mark of send buffer
+  UINT32      RcvBufferSize;  // the high warter mark of receive buffer
+  VOID        *Protocol;      // the pointer to protocol function template
+                              // wanted to install on socket
+
+  SOCK_PROTO_HANDLER  ProtoHandler;
+
+  EFI_HANDLE   DriverBinding; // the driver binding handle
+} SOCK_INIT_DATA;
+
+//
+// socket provided oprerations for low layer protocol
+//
+
+//
+// socket provided operations for user interface
+//
+VOID
+SockSetState (
+  IN SOCKET     *Sock,
+  IN SOCK_STATE State
+  );
+
+//
+// when the connection establishment process for a Sock
+// is finished low layer protocol calling this function
+// to notify socket layer
+//
+VOID
+SockConnEstablished (
+  IN SOCKET *Sock
+  );
+
+VOID
+SockConnClosed (
+  IN SOCKET *Sock
+  );
+
+//
+// called by low layer protocol to trim send buffer of
+// Sock, when Count data is sent out completely
+//
+VOID
+SockDataSent (
+  IN SOCKET  *Sock,
+  IN UINT32  Count
+  );
+
+//
+// called by low layer protocol to get Len of data from
+// socket to send and copy it in Dest
+//
+UINT32
+SockGetDataToSend (
+  IN SOCKET *Sock,
+  IN UINT32 Offset,
+  IN UINT32 Len,
+  IN UINT8  *Dest
+  );
+
+//
+//  called by low layer protocol to notify socket no more data can be
+//  received
+//
+VOID
+SockNoMoreData (
+  IN SOCKET *Sock
+  );
+
+//
+// called by low layer protocol to append a NetBuffer
+// to rcv buffer of sock
+//
+VOID
+SockDataRcvd (
+  IN SOCKET    *Sock,
+  IN NET_BUF   *NetBuffer,
+  IN UINT32     UrgLen
+  );
+
+UINT32
+SockGetFreeSpace (
+  IN SOCKET   *Sock,
+  IN UINT32   Which
+  );
+
+SOCKET  *
+SockClone (
+  IN SOCKET *Sock
+  );
+
+VOID
+SockRcvdErr (
+  IN SOCKET       *Sock,
+  IN EFI_STATUS   Error
+  );
+
+//
+// the socket structure representing a network service access point
+//
+typedef struct _SOCKET {
+
+  //
+  // socket description information
+  //
+  UINT32                Signature;
+  EFI_HANDLE            SockHandle;     // the virtual handle of the socket
+  EFI_HANDLE            DriverBinding;  // socket't driver binding protocol
+  SOCK_CONFIGURE_STATE  ConfigureState;
+  SOCK_TYPE             Type;
+  SOCK_STATE            State;
+  UINT16                Flag;
+  NET_LOCK              Lock;       // the lock of socket
+  SOCK_BUFFER           SndBuffer;  // send buffer of application's data
+  SOCK_BUFFER           RcvBuffer;  // receive buffer of received data
+  EFI_STATUS            SockError;  // the error returned by low layer protocol
+  BOOLEAN               IsDestroyed;
+
+  //
+  // fields used to manage the connection request
+  //
+  UINT32          BackLog;        // the limit of connection to this socket
+  UINT32          ConnCnt;        // the current count of connections to it
+  SOCKET          *Parent;        // listening parent that accept the connection
+  NET_LIST_ENTRY  ConnectionList; // the connections maintained by this socket
+  //
+  // the queue to buffer application's asynchronous token
+  //
+  NET_LIST_ENTRY  ListenTokenList;
+  NET_LIST_ENTRY  RcvTokenList;
+  NET_LIST_ENTRY  SndTokenList;
+  NET_LIST_ENTRY  ProcessingSndTokenList;
+
+  SOCK_COMPLETION_TOKEN *ConnectionToken; // app's token to signal if connected
+  SOCK_COMPLETION_TOKEN *CloseToken;      // app's token to signal if closed
+
+  //
+  // interface for low level protocol
+  //
+  SOCK_PROTO_HANDLER    ProtoHandler; // the request handler of protocol
+  UINT8 ProtoReserved[PROTO_RESERVED_LEN];  // Data fields reserved for protocol
+  union {
+    EFI_TCP4_PROTOCOL TcpProtocol;
+    EFI_UDP4_PROTOCOL UdpProtocol;
+  } NetProtocol;
+} SOCKET;
+
+//
+// the token structure buffered in socket layer
+//
+typedef struct _SOCK_TOKEN {
+  NET_LIST_ENTRY        TokenList;      // the entry to add in the token list
+  SOCK_COMPLETION_TOKEN *Token;         // The application's token
+  UINT32                RemainDataLen;  // unprocessed data length
+  SOCKET                *Sock;          // the poninter to the socket this token
+                                        // belongs to
+} SOCK_TOKEN;
+
+//
+// reserved data to access the NET_BUF delivered by UDP driver
+//
+typedef struct _UDP_RSV_DATA {
+  EFI_TIME              TimeStamp;
+  EFI_UDP4_SESSION_DATA Session;
+} UDP_RSV_DATA;
+
+//
+// reserved data to access the NET_BUF delivered by TCP driver
+//
+typedef struct _TCP_RSV_DATA {
+  UINT32 UrgLen;
+} TCP_RSV_DATA;
+
+//
+// call it to creat a socket and attach it to a PCB
+//
+SOCKET  *
+SockCreateChild (
+  IN SOCK_INIT_DATA *SockInitData,
+  IN VOID           *ProtoData,
+  IN UINT32         Len
+  );
+
+//
+// call it to destroy a socket and its related PCB
+//
+EFI_STATUS
+SockDestroyChild (
+  IN SOCKET *Sock
+  );
+
+//
+// call it to configure a socket and its related PCB
+//
+EFI_STATUS
+SockConfigure (
+  IN SOCKET *Sock,
+  IN VOID   *ConfigData
+  );
+
+//
+// call it to connect a socket to the peer
+//
+EFI_STATUS
+SockConnect (
+  IN SOCKET *Sock,
+  IN VOID   *Token
+  );
+
+//
+// call it to issue an asynchronous listen token to the socket
+//
+EFI_STATUS
+SockAccept (
+  IN SOCKET *Sock,
+  IN VOID   *Token
+  );
+
+//
+// Call it to send data using this socket
+//
+EFI_STATUS
+SockSend (
+  IN SOCKET *Sock,
+  IN VOID   *Token
+  );
+
+//
+// Call it to receive data from this socket
+//
+EFI_STATUS
+SockRcv (
+  IN SOCKET *Sock,
+  IN VOID   *Token
+  );
+
+//
+// Call it to flush a socket
+//
+EFI_STATUS
+SockFlush (
+  IN SOCKET *Sock
+  );
+
+//
+// Call it to close a socket in the light of policy in Token
+//
+EFI_STATUS
+SockClose (
+  IN SOCKET  *Sock,
+  IN VOID    *Token,
+  IN BOOLEAN OnAbort
+  );
+
+//
+// Call it to get the mode data of low layer protocol
+//
+EFI_STATUS
+SockGetMode (
+  IN SOCKET *Sock,
+  IN VOID   *Mode
+  );
+
+//
+// call it to add this socket instance into a group
+//
+EFI_STATUS
+SockGroup (
+  IN SOCKET *Sock,
+  IN VOID   *GroupInfo
+  );
+
+//
+// call it to add a route entry for this socket instance
+//
+EFI_STATUS
+SockRoute (
+  IN SOCKET    *Sock,
+  IN VOID      *RouteInfo
+  );
+
+//
+// Supporting function to operate on socket buffer
+//
+NET_BUF *
+SockBufFirst (
+  IN SOCK_BUFFER *Sockbuf
+  );
+
+NET_BUF *
+SockBufNext (
+  IN SOCK_BUFFER *Sockbuf,
+  IN NET_BUF     *SockEntry
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dispatcher.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dispatcher.c
new file mode 100644 (file)
index 0000000..9039905
--- /dev/null
@@ -0,0 +1,680 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Dispatcher.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+#define TCP_COMP_VAL(Min, Max, Default, Val) \\r
+  ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))\r
+\r
+STATIC\r
+EFI_STATUS\r
+Tcp4Route (\r
+  IN TCP_CB           *Tcb,\r
+  IN TCP4_ROUTE_INFO  *RouteInfo\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add or remove a route entry in the IP route table associated\r
+  with this TCP instance.\r
+\r
+Arguments:\r
+\r
+  Tcb       - Pointer to the TCP_CB of this TCP instance.\r
+  RouteInfo - Pointer to the route info to be processed.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The operation completed successfully.\r
+  EFI_NOT_STARTED      - The driver instance has not been started.\r
+  EFI_NO_MAPPING       - When using the default address, configuration(DHCP,\r
+                         BOOTP, RARP, etc.) is not finished yet.\r
+  EFI_OUT_OF_RESOURCES - Could not add the entry to the routing table.\r
+  EFI_NOT_FOUND        - This route is not in the routing table\r
+                         (when RouteInfo->DeleteRoute is TRUE).\r
+  EFI_ACCESS_DENIED    - The route is already defined in the routing table\r
+                         (when RouteInfo->DeleteRoute is FALSE).\r
+\r
+--*/\r
+{\r
+  EFI_IP4_PROTOCOL  *Ip;\r
+\r
+  Ip = Tcb->IpInfo->Ip;\r
+\r
+  ASSERT (Ip);\r
+\r
+  return Ip->Routes (\r
+              Ip,\r
+              RouteInfo->DeleteRoute,\r
+              RouteInfo->SubnetAddress,\r
+              RouteInfo->SubnetMask,\r
+              RouteInfo->GatewayAddress\r
+              );\r
+\r
+}\r
+\r
+\r
+/**\r
+  Get the operational settings of this TCP instance.\r
+\r
+  @param  Tcb                    Pointer to the TCP_CB of this TCP instance.\r
+  @param  Mode                   Pointer to the buffer to store the operational\r
+                                 settings.\r
+\r
+  @retval EFI_SUCCESS            The mode data is read.\r
+  @retval EFI_NOT_STARTED        No configuration data is available because this\r
+                                 instance hasn't been started.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4GetMode (\r
+  IN TCP_CB         *Tcb,\r
+  IN TCP4_MODE_DATA *Mode\r
+  )\r
+{\r
+  SOCKET                *Sock;\r
+  EFI_TCP4_CONFIG_DATA  *ConfigData;\r
+  EFI_TCP4_ACCESS_POINT *AccessPoint;\r
+  EFI_TCP4_OPTION       *Option;\r
+  EFI_IP4_PROTOCOL      *Ip;\r
+\r
+  Sock = Tcb->Sk;\r
+\r
+  if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (Mode->Tcp4State) {\r
+    *(Mode->Tcp4State) = Tcb->State;\r
+  }\r
+\r
+  if (Mode->Tcp4ConfigData) {\r
+\r
+    ConfigData                      = Mode->Tcp4ConfigData;\r
+    AccessPoint                     = &(ConfigData->AccessPoint);\r
+    Option                          = ConfigData->ControlOption;\r
+\r
+    ConfigData->TypeOfService       = Tcb->TOS;\r
+    ConfigData->TimeToLive          = Tcb->TTL;\r
+\r
+    AccessPoint->UseDefaultAddress  = Tcb->UseDefaultAddr;\r
+\r
+    EFI_IP4 (AccessPoint->StationAddress) = Tcb->LocalEnd.Ip;\r
+    AccessPoint->SubnetMask         = Tcb->SubnetMask;\r
+    AccessPoint->StationPort        = NTOHS (Tcb->LocalEnd.Port);\r
+\r
+    EFI_IP4 (AccessPoint->RemoteAddress) = Tcb->RemoteEnd.Ip;\r
+    AccessPoint->RemotePort         = NTOHS (Tcb->RemoteEnd.Port);\r
+    AccessPoint->ActiveFlag         = (BOOLEAN) (Tcb->State != TCP_LISTEN);\r
+\r
+    if (Option != NULL) {\r
+      Option->ReceiveBufferSize       = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+      Option->SendBufferSize          = GET_SND_BUFFSIZE (Tcb->Sk);\r
+      Option->MaxSynBackLog           = GET_BACKLOG (Tcb->Sk);\r
+\r
+      Option->ConnectionTimeout       = Tcb->ConnectTimeout / TCP_TICK_HZ;\r
+      Option->DataRetries             = Tcb->MaxRexmit;\r
+      Option->FinTimeout              = Tcb->FinWait2Timeout / TCP_TICK_HZ;\r
+      Option->TimeWaitTimeout         = Tcb->TimeWaitTimeout / TCP_TICK_HZ;\r
+      Option->KeepAliveProbes         = Tcb->MaxKeepAlive;\r
+      Option->KeepAliveTime           = Tcb->KeepAliveIdle / TCP_TICK_HZ;\r
+      Option->KeepAliveInterval       = Tcb->KeepAlivePeriod / TCP_TICK_HZ;\r
+\r
+      Option->EnableNagle      = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);\r
+      Option->EnableTimeStamp     = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS);\r
+      Option->EnableWindowScaling = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS);\r
+\r
+      Option->EnableSelectiveAck      = FALSE;\r
+      Option->EnablePathMtuDiscovery  = FALSE;\r
+    }\r
+  }\r
+\r
+  Ip = Tcb->IpInfo->Ip;\r
+  ASSERT (Ip);\r
+\r
+  return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);\r
+}\r
+\r
+\r
+/**\r
+  If AP->StationPort isn't zero, check whether the access point\r
+  is registered, else generate a random station port for this\r
+  access point.\r
+\r
+  @param  AP                     Pointer to the access point.\r
+\r
+  @retval EFI_SUCCESS            The check is passed or the port is assigned.\r
+  @retval EFI_INVALID_PARAMETER  The non-zero station port is already used.\r
+  @retval EFI_OUT_OF_RESOURCES   No port can be allocated.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4Bind (\r
+  IN EFI_TCP4_ACCESS_POINT *AP\r
+  )\r
+{\r
+  BOOLEAN Cycle;\r
+\r
+  if (0 != AP->StationPort) {\r
+    //\r
+    // check if a same endpoint is bound\r
+    //\r
+    if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {\r
+\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // generate a random port\r
+    //\r
+    Cycle = FALSE;\r
+\r
+    if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {\r
+      mTcp4RandomPort = TCP4_PORT_KNOWN;\r
+    }\r
+\r
+    mTcp4RandomPort++;\r
+\r
+    while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {\r
+\r
+      mTcp4RandomPort++;\r
+\r
+      if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {\r
+\r
+        if (Cycle) {\r
+          TCP4_DEBUG_ERROR (("Tcp4Bind: no port can be allocated "\r
+            "for this pcb\n"));\r
+\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+\r
+        mTcp4RandomPort = TCP4_PORT_KNOWN + 1;\r
+\r
+        Cycle = TRUE;\r
+      }\r
+\r
+    }\r
+\r
+    AP->StationPort = mTcp4RandomPort;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Flush the Tcb add its associated protocols..\r
+\r
+  @param  Tcb                    Pointer to the TCP_CB to be flushed.\r
+\r
+  @retval EFI_SUCCESS            The operation is completed successfully.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Tcp4FlushPcb (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  SOCKET           *Sock;\r
+  TCP4_PROTO_DATA  *TcpProto;\r
+\r
+  IpIoConfigIp (Tcb->IpInfo, NULL);\r
+\r
+  Sock     = Tcb->Sk;\r
+  TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+  if (SOCK_IS_CONFIGURED (Sock)) {\r
+    NetListRemoveEntry (&Tcb->List);\r
+\r
+    TcpSetVariableData (TcpProto->TcpService);\r
+  }\r
+\r
+  NetbufFreeList (&Tcb->SndQue);\r
+  NetbufFreeList (&Tcb->RcvQue);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+Tcp4AttachPcb (\r
+  IN SOCKET  *Sk\r
+  )\r
+{\r
+  TCP_CB            *Tcb;\r
+  TCP4_PROTO_DATA   *ProtoData;\r
+  IP_IO             *IpIo;\r
+\r
+  Tcb = NetAllocateZeroPool (sizeof (TCP_CB));\r
+\r
+  if (Tcb == NULL) {\r
+\r
+    TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: failed to allocate a TCB\n"));\r
+\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ProtoData  = (TCP4_PROTO_DATA *) Sk->ProtoReserved;\r
+  IpIo       = ProtoData->TcpService->IpIo;\r
+\r
+  //\r
+  // Create an IpInfo for this Tcb.\r
+  //\r
+  Tcb->IpInfo = IpIoAddIp (IpIo);\r
+  if (Tcb->IpInfo == NULL) {\r
+\r
+    NetFreePool (Tcb);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetListInit (&Tcb->List);\r
+  NetListInit (&Tcb->SndQue);\r
+  NetListInit (&Tcb->RcvQue);\r
+\r
+  Tcb->State        = TCP_CLOSED;\r
+  Tcb->Sk           = Sk;\r
+  ProtoData->TcpPcb = Tcb;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+Tcp4DetachPcb (\r
+  IN SOCKET  *Sk\r
+  )\r
+{\r
+  TCP4_PROTO_DATA  *ProtoData;\r
+  TCP_CB           *Tcb;\r
+\r
+  ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;\r
+  Tcb       = ProtoData->TcpPcb;\r
+\r
+  ASSERT (Tcb != NULL);\r
+\r
+  Tcp4FlushPcb (Tcb);\r
+\r
+  IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);\r
+\r
+  NetFreePool (Tcb);\r
+\r
+  ProtoData->TcpPcb = NULL;\r
+}\r
+\r
+\r
+/**\r
+  Configure the Tcb using CfgData.\r
+\r
+  @param  Sk                     Pointer to the socket of this TCP instance.\r
+  @param  SkTcb                  Pointer to the TCP_CB of this TCP instance.\r
+  @param  CfgData                Pointer to the TCP configuration data.\r
+\r
+  @retval EFI_SUCCESS            The operation is completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  A same access point has been configured in\r
+                                 another TCP instance.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed due to resource limit.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4ConfigurePcb (\r
+  IN SOCKET               *Sk,\r
+  IN EFI_TCP4_CONFIG_DATA *CfgData\r
+  )\r
+{\r
+  IP_IO               *IpIo;\r
+  EFI_IP4_CONFIG_DATA IpCfgData;\r
+  EFI_STATUS          Status;\r
+  EFI_TCP4_OPTION     *Option;\r
+  TCP4_PROTO_DATA     *TcpProto;\r
+  TCP_CB              *Tcb;\r
+\r
+  ASSERT (CfgData && Sk && Sk->SockHandle);\r
+\r
+  TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved;\r
+  Tcb      = TcpProto->TcpPcb;\r
+  IpIo     = TcpProto->TcpService->IpIo;\r
+\r
+  ASSERT (Tcb != NULL);\r
+\r
+  //\r
+  // Add Ip for send pkt to the peer\r
+  //\r
+  IpCfgData                   = mIpIoDefaultIpConfigData;\r
+  IpCfgData.DefaultProtocol   = EFI_IP_PROTO_TCP;\r
+  IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;\r
+  IpCfgData.StationAddress    = CfgData->AccessPoint.StationAddress;\r
+  IpCfgData.SubnetMask        = CfgData->AccessPoint.SubnetMask;\r
+  IpCfgData.ReceiveTimeout    = (UINT32) (-1);\r
+\r
+  //\r
+  // Configure the IP instance this Tcb consumes.\r
+  //\r
+  Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto OnExit;\r
+  }\r
+\r
+  //\r
+  // Get the default address info if the instance is configured to use default address.\r
+  //\r
+  if (CfgData->AccessPoint.UseDefaultAddress) {\r
+    CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;\r
+    CfgData->AccessPoint.SubnetMask     = IpCfgData.SubnetMask;\r
+  }\r
+\r
+  //\r
+  // check if we can bind this endpoint in CfgData\r
+  //\r
+  Status = Tcp4Bind (&(CfgData->AccessPoint));\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: Bind endpoint failed "\r
+      "with %r\n", Status));\r
+\r
+    goto OnExit;\r
+  }\r
+\r
+  //\r
+  // Initalize the operating information in this Tcb\r
+  //\r
+  ASSERT (Tcb->State == TCP_CLOSED &&\r
+    NetListIsEmpty (&Tcb->SndQue) &&\r
+    NetListIsEmpty (&Tcb->RcvQue));\r
+\r
+  TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);\r
+  Tcb->State            = TCP_CLOSED;\r
+\r
+  Tcb->SndMss           = 536;\r
+  Tcb->RcvMss           = TcpGetRcvMss (Sk);\r
+\r
+  Tcb->SRtt             = 0;\r
+  Tcb->Rto              = 3 * TCP_TICK_HZ;\r
+\r
+  Tcb->CWnd             = Tcb->SndMss;\r
+  Tcb->Ssthresh         = 0xffffffff;\r
+\r
+  Tcb->CongestState     = TCP_CONGEST_OPEN;\r
+\r
+  Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;\r
+  Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;\r
+  Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;\r
+  Tcb->MaxRexmit        = TCP_MAX_LOSS;\r
+  Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;\r
+  Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;\r
+  Tcb->ConnectTimeout   = TCP_CONNECT_TIME;\r
+\r
+  //\r
+  // initialize Tcb in the light of CfgData\r
+  //\r
+  Tcb->TTL            = CfgData->TimeToLive;\r
+  Tcb->TOS            = CfgData->TypeOfService;\r
+\r
+  Tcb->LocalEnd.Ip    = EFI_IP4 (CfgData->AccessPoint.StationAddress);\r
+  Tcb->LocalEnd.Port  = HTONS (CfgData->AccessPoint.StationPort);\r
+  Tcb->SubnetMask     = CfgData->AccessPoint.SubnetMask;\r
+\r
+  Tcb->RemoteEnd.Ip   = EFI_IP4 (CfgData->AccessPoint.RemoteAddress);\r
+  Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);\r
+\r
+  Option              = CfgData->ControlOption;\r
+\r
+  if (Option != NULL) {\r
+    SET_RCV_BUFFSIZE (\r
+      Sk,\r
+      TCP_COMP_VAL (TCP_RCV_BUF_SIZE_MIN,\r
+      TCP_RCV_BUF_SIZE,\r
+      TCP_RCV_BUF_SIZE,\r
+      Option->ReceiveBufferSize)\r
+      );\r
+    SET_SND_BUFFSIZE (\r
+      Sk,\r
+      TCP_COMP_VAL (TCP_SND_BUF_SIZE_MIN,\r
+      TCP_SND_BUF_SIZE,\r
+      TCP_SND_BUF_SIZE,\r
+      Option->SendBufferSize)\r
+      );\r
+\r
+    SET_BACKLOG (\r
+      Sk,\r
+      TCP_COMP_VAL (TCP_BACKLOG_MIN,\r
+      TCP_BACKLOG,\r
+      TCP_BACKLOG,\r
+      Option->MaxSynBackLog)\r
+      );\r
+\r
+    Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (\r
+                                TCP_MAX_LOSS_MIN,\r
+                                TCP_MAX_LOSS,\r
+                                TCP_MAX_LOSS,\r
+                                Option->DataRetries\r
+                                );\r
+    Tcb->FinWait2Timeout = TCP_COMP_VAL (\r
+                              TCP_FIN_WAIT2_TIME,\r
+                              TCP_FIN_WAIT2_TIME_MAX,\r
+                              TCP_FIN_WAIT2_TIME,\r
+                              Option->FinTimeout * TCP_TICK_HZ\r
+                              );\r
+\r
+    if (Option->TimeWaitTimeout != 0) {\r
+      Tcb->TimeWaitTimeout = TCP_COMP_VAL (\r
+                               TCP_TIME_WAIT_TIME,\r
+                               TCP_TIME_WAIT_TIME_MAX,\r
+                               TCP_TIME_WAIT_TIME,\r
+                               Option->TimeWaitTimeout * TCP_TICK_HZ\r
+                               );\r
+    } else {\r
+      Tcb->TimeWaitTimeout = 0;\r
+    }\r
+\r
+    if (Option->KeepAliveProbes != 0) {\r
+      TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);\r
+\r
+      Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (\r
+                                    TCP_MAX_KEEPALIVE_MIN,\r
+                                    TCP_MAX_KEEPALIVE,\r
+                                    TCP_MAX_KEEPALIVE,\r
+                                    Option->KeepAliveProbes\r
+                                    );\r
+      Tcb->KeepAliveIdle = TCP_COMP_VAL (\r
+                             TCP_KEEPALIVE_IDLE_MIN,\r
+                             TCP_KEEPALIVE_IDLE_MAX,\r
+                             TCP_KEEPALIVE_IDLE_MIN,\r
+                             Option->KeepAliveTime * TCP_TICK_HZ\r
+                             );\r
+      Tcb->KeepAlivePeriod = TCP_COMP_VAL (\r
+                               TCP_KEEPALIVE_PERIOD_MIN,\r
+                               TCP_KEEPALIVE_PERIOD,\r
+                               TCP_KEEPALIVE_PERIOD,\r
+                               Option->KeepAliveInterval * TCP_TICK_HZ\r
+                               );\r
+    }\r
+\r
+    Tcb->ConnectTimeout = TCP_COMP_VAL (\r
+                            TCP_CONNECT_TIME_MIN,\r
+                            TCP_CONNECT_TIME,\r
+                            TCP_CONNECT_TIME,\r
+                            Option->ConnectionTimeout * TCP_TICK_HZ\r
+                            );\r
+\r
+    if (Option->EnableNagle == FALSE) {\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);\r
+    }\r
+\r
+    if (Option->EnableTimeStamp == FALSE) {\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);\r
+    }\r
+\r
+    if (Option->EnableWindowScaling == FALSE) {\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);\r
+    }\r
+  }\r
+\r
+  //\r
+  // update state of Tcb and socket\r
+  //\r
+  if (CfgData->AccessPoint.ActiveFlag == FALSE) {\r
+\r
+    TcpSetState (Tcb, TCP_LISTEN);\r
+    SockSetState (Sk, SO_LISTENING);\r
+\r
+    Sk->ConfigureState = SO_CONFIGURED_PASSIVE;\r
+  } else {\r
+\r
+    Sk->ConfigureState = SO_CONFIGURED_ACTIVE;\r
+  }\r
+\r
+  TcpInsertTcb (Tcb);\r
+\r
+OnExit:\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  The procotol handler provided to the socket layer, used to\r
+  dispatch the socket level requests by calling the corresponding\r
+  TCP layer functions.\r
+\r
+  @param  Sock                   Pointer to the socket of this TCP instance.\r
+  @param  Request                The code of this operation request.\r
+  @param  Data                   Pointer to the operation specific data passed in\r
+                                 together with the operation request.\r
+\r
+  @retval EFI_SUCCESS            The socket request is completed successfully.\r
+  @retval other                  The error status returned by the corresponding TCP\r
+                                 layer function.\r
+\r
+**/\r
+EFI_STATUS\r
+Tcp4Dispatcher (\r
+  IN SOCKET                  *Sock,\r
+  IN SOCK_REQUEST            Request,\r
+  IN VOID                    *Data    OPTIONAL\r
+  )\r
+{\r
+  TCP_CB            *Tcb;\r
+  TCP4_PROTO_DATA   *ProtoData;\r
+  EFI_IP4_PROTOCOL  *Ip;\r
+\r
+  ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+  Tcb       = ProtoData->TcpPcb;\r
+\r
+  switch (Request) {\r
+  case SOCK_POLL:\r
+    Ip = ProtoData->TcpService->IpIo->Ip;\r
+    Ip->Poll (Ip);\r
+    break;\r
+\r
+  case SOCK_CONSUMED:\r
+    //\r
+    // After user received data from socket buffer, socket will\r
+    // notify TCP using this message to give it a chance to send out\r
+    // window update information\r
+    //\r
+    ASSERT (Tcb);\r
+    TcpOnAppConsume (Tcb);\r
+    break;\r
+\r
+  case SOCK_SND:\r
+\r
+    ASSERT (Tcb);\r
+    TcpOnAppSend (Tcb);\r
+    break;\r
+\r
+  case SOCK_CLOSE:\r
+\r
+    TcpOnAppClose (Tcb);\r
+\r
+    break;\r
+\r
+  case SOCK_ABORT:\r
+\r
+    TcpOnAppAbort (Tcb);\r
+\r
+    break;\r
+\r
+  case SOCK_SNDPUSH:\r
+    Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);\r
+\r
+    break;\r
+\r
+  case SOCK_SNDURG:\r
+    Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
+\r
+    break;\r
+\r
+  case SOCK_CONNECT:\r
+\r
+    TcpOnAppConnect (Tcb);\r
+\r
+    break;\r
+\r
+  case SOCK_ATTACH:\r
+\r
+    return Tcp4AttachPcb (Sock);\r
+\r
+    break;\r
+\r
+  case SOCK_FLUSH:\r
+\r
+    Tcp4FlushPcb (Tcb);\r
+\r
+    break;\r
+\r
+  case SOCK_DETACH:\r
+\r
+    Tcp4DetachPcb (Sock);\r
+\r
+    break;\r
+\r
+  case SOCK_CONFIGURE:\r
+\r
+    return Tcp4ConfigurePcb (\r
+            Sock,\r
+            (EFI_TCP4_CONFIG_DATA *) Data\r
+            );\r
+\r
+    break;\r
+\r
+  case SOCK_MODE:\r
+\r
+    ASSERT (Data && Tcb);\r
+\r
+    return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);\r
+\r
+    break;\r
+\r
+  case SOCK_ROUTE:\r
+\r
+    ASSERT (Data && Tcb);\r
+\r
+    return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.c
new file mode 100644 (file)
index 0000000..2927849
--- /dev/null
@@ -0,0 +1,669 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Driver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+UINT16                               mTcp4RandomPort;\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gTcp4ComponentName;\r
+\r
+TCP4_HEARTBEAT_TIMER  mTcp4Timer = {\r
+  NULL,\r
+  0\r
+};\r
+\r
+EFI_TCP4_PROTOCOL mTcp4ProtocolTemplate = {\r
+  Tcp4GetModeData,\r
+  Tcp4Configure,\r
+  Tcp4Routes,\r
+  Tcp4Connect,\r
+  Tcp4Accept,\r
+  Tcp4Transmit,\r
+  Tcp4Receive,\r
+  Tcp4Close,\r
+  Tcp4Cancel,\r
+  Tcp4Poll\r
+};\r
+\r
+SOCK_INIT_DATA mTcp4DefaultSockData = {\r
+  SOCK_STREAM,\r
+  0,\r
+  NULL,\r
+  TCP_BACKLOG,\r
+  TCP_SND_BUF_SIZE,\r
+  TCP_RCV_BUF_SIZE,\r
+  &mTcp4ProtocolTemplate,\r
+  Tcp4Dispatcher,\r
+  NULL,\r
+};\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL mTcp4DriverBinding = {\r
+  Tcp4DriverBindingSupported,\r
+  Tcp4DriverBindingStart,\r
+  Tcp4DriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL mTcp4ServiceBinding = {\r
+  Tcp4ServiceBindingCreateChild,\r
+  Tcp4ServiceBindingDestroyChild\r
+};\r
+\r
+\r
+/**\r
+  Create and start the heartbeat timer for TCP driver.\r
+\r
+  None.\r
+\r
+  @retval EFI_SUCCESS            The timer is successfully created and started.\r
+  @retval other                  The timer is not created.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4CreateTimer (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (mTcp4Timer.RefCnt == 0) {\r
+\r
+    Status = gBS->CreateEvent (\r
+                    EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                    NET_TPL_TIMER,\r
+                    TcpTicking,\r
+                    NULL,\r
+                    &mTcp4Timer.TimerEvent\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      Status = gBS->SetTimer (\r
+                      mTcp4Timer.TimerEvent,\r
+                      TimerPeriodic,\r
+                      (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)\r
+                      );\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+\r
+    mTcp4Timer.RefCnt++;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop and destroy the heartbeat timer for TCP driver.\r
+\r
+  None.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Tcp4DestroyTimer (\r
+  VOID\r
+  )\r
+{\r
+  ASSERT (mTcp4Timer.RefCnt > 0);\r
+\r
+  mTcp4Timer.RefCnt--;\r
+\r
+  if (mTcp4Timer.RefCnt > 0) {\r
+    return;\r
+  }\r
+\r
+  gBS->SetTimer (mTcp4Timer.TimerEvent, TimerCancel, 0);\r
+  gBS->CloseEvent (mTcp4Timer.TimerEvent);\r
+  mTcp4Timer.TimerEvent = NULL;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Tcp4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The entry point for Tcp4 driver. used to install\r
+  Tcp4 driver on the ImageHandle.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The firmware allocated handle for this\r
+                driver image.\r
+  SystemTable - Pointer to the EFI system table.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - Driver loaded.\r
+  other       - Driver not loaded.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      Seed;\r
+\r
+  //\r
+  // Install the TCP4 Driver Binding Protocol\r
+  //\r
+  Status = NetLibInstallAllDriverProtocols (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &mTcp4DriverBinding,\r
+             ImageHandle,\r
+             &gTcp4ComponentName,\r
+             NULL,\r
+             NULL\r
+             );\r
+\r
+  //\r
+  // Initialize ISS and random port.\r
+  //\r
+  Seed            = NetRandomInitSeed ();\r
+  mTcpGlobalIss   = NET_RANDOM (Seed) % mTcpGlobalIss;\r
+  mTcp4RandomPort = TCP4_PORT_KNOWN +\r
+                    (UINT16) (NET_RANDOM(Seed) % TCP4_PORT_KNOWN);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to test.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCESS            This driver supports this device.\r
+  @retval EFI_ALREADY_STARTED    This driver is already running on this device.\r
+  @retval other                  This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Test for the Tcp4ServiceBinding Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  //\r
+  // Test for the Ip4 Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiIp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start this driver on ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCESS            The driver is added to ControllerHandle.\r
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to start the\r
+                                 driver.\r
+  @retval other                  The driver cannot be added to ControllerHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  TCP4_SERVICE_DATA        *TcpServiceData;\r
+  IP_IO_OPEN_DATA          OpenData;\r
+\r
+  TcpServiceData = NetAllocateZeroPool (sizeof (TCP4_SERVICE_DATA));\r
+\r
+  if (NULL == TcpServiceData) {\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Have no enough"\r
+      " resource to create a Tcp Servcie Data!\n"));\r
+\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Create a new IP IO to Consume it\r
+  //\r
+  TcpServiceData->IpIo = IpIoCreate (This->DriverBindingHandle, ControllerHandle);\r
+  if (NULL == TcpServiceData->IpIo) {\r
+\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Have no enough"\r
+      " resource to create an Ip Io!\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ReleaseServiceData;\r
+  }\r
+\r
+  //\r
+  // Configure and start IpIo.\r
+  //\r
+  NetZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));\r
+\r
+  OpenData.IpConfigData                 = mIpIoDefaultIpConfigData;\r
+  OpenData.IpConfigData.DefaultProtocol = EFI_IP_PROTO_TCP;\r
+\r
+  OpenData.PktRcvdNotify = Tcp4RxCallback;\r
+  Status                 = IpIoOpen (TcpServiceData->IpIo, &OpenData);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+      goto ReleaseServiceData;\r
+  }\r
+\r
+  //\r
+  // Create the timer event used by TCP driver\r
+  //\r
+  Status = Tcp4CreateTimer ();\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Create TcpTimer"\r
+      " Event failed with %r\n", Status));\r
+\r
+    goto ReleaseIpIo;\r
+  }\r
+\r
+  //\r
+  // Install the Tcp4ServiceBinding Protocol on the\r
+  // controller handle\r
+  //\r
+  TcpServiceData->Tcp4ServiceBinding = mTcp4ServiceBinding;\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ControllerHandle,\r
+                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                  &TcpServiceData->Tcp4ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Install Tcp4 Service Binding"\r
+      " Protocol failed for %r\n", Status));\r
+\r
+    goto ReleaseTimer;\r
+  }\r
+\r
+  //\r
+  // Initialize member in TcpServiceData\r
+  //\r
+  TcpServiceData->ControllerHandle    = ControllerHandle;\r
+  TcpServiceData->Signature           = TCP4_DRIVER_SIGNATURE;\r
+  TcpServiceData->DriverBindingHandle = This->DriverBindingHandle;\r
+\r
+  TcpSetVariableData (TcpServiceData);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ReleaseTimer:\r
+\r
+  Tcp4DestroyTimer ();\r
+\r
+ReleaseIpIo:\r
+\r
+  IpIoDestroy (TcpServiceData->IpIo);\r
+\r
+ReleaseServiceData:\r
+\r
+  NetFreePool (TcpServiceData);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to stop driver on.\r
+  @param  NumberOfChildren       Number of Handles in ChildHandleBuffer. If number\r
+                                 of children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer      List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS            This driver is removed from ControllerHandle.\r
+  @retval other                  This driver is not removed from ControllerHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          NicHandle;\r
+  EFI_SERVICE_BINDING_PROTOCOL        *Tcp4ServiceBinding;\r
+  TCP4_SERVICE_DATA                   *TcpServiceData;\r
+  TCP_CB                              *TcpPcb;\r
+  SOCKET                              *Sock;\r
+  TCP4_PROTO_DATA                     *TcpProto;\r
+  NET_LIST_ENTRY                      *Entry;\r
+  NET_LIST_ENTRY                      *NextEntry;\r
+\r
+  // Find the NicHandle where Tcp4 ServiceBinding Protocol is installed.\r
+  //\r
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);\r
+  if (NicHandle == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Retrieve the TCP driver Data Structure\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  NicHandle,\r
+                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                  (VOID **) &Tcp4ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Locate Tcp4 Service "\r
+      " Binding Protocol failed with %r\n", Status));\r
+\r
+    return Status;\r
+  }\r
+\r
+  TcpServiceData = TCP4_FROM_THIS (Tcp4ServiceBinding);\r
+\r
+  //\r
+  // Kill TCP driver\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mTcpRunQue) {\r
+    TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    //\r
+    // Try to destroy this child\r
+    //\r
+    Sock     = TcpPcb->Sk;\r
+    TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == TcpServiceData) {\r
+      Status = SockDestroyChild (Sock);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+\r
+        TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Destroy Tcp "\r
+          "instance failed with %r\n", Status));\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mTcpListenQue) {\r
+    TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    //\r
+    // Try to destroy this child\r
+    //\r
+    Sock     = TcpPcb->Sk;\r
+    TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == TcpServiceData) {\r
+      Status = SockDestroyChild (TcpPcb->Sk);\r
+      if (EFI_ERROR (Status)) {\r
+\r
+        TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Destroy Tcp "\r
+          "instance failed with %r\n", Status));\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Uninstall TCP servicebinding protocol\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  NicHandle,\r
+                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                  Tcp4ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Uninstall TCP service "\r
+      "binding protocol failed with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Destroy the IpIO consumed by TCP driver\r
+  //\r
+  Status = IpIoDestroy (TcpServiceData->IpIo);\r
+\r
+  //\r
+  // Destroy the heartbeat timer.\r
+  //\r
+  Tcp4DestroyTimer ();\r
+\r
+  //\r
+  // Clear the variable.\r
+  //\r
+  TcpClearVariableData (TcpServiceData);\r
+\r
+  //\r
+  // Release the TCP service data\r
+  //\r
+  NetFreePool (TcpServiceData);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Creates a child handle with a set of TCP4 services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Pointer to the handle of the child to create.  If\r
+                                 it is NULL, then a new handle is created. If it is\r
+                                 not NULL, then the I/O services are added to the\r
+                                 existing child handle.\r
+\r
+  @retval EFI_SUCCESS            The child handle is created.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to create the\r
+                                 child.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4ServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    *ChildHandle\r
+  )\r
+{\r
+  SOCKET            *Sock;\r
+  TCP4_SERVICE_DATA *TcpServiceData;\r
+  TCP4_PROTO_DATA   TcpProto;\r
+  EFI_STATUS        Status;\r
+  VOID              *Ip4;\r
+  EFI_TPL           OldTpl;\r
+\r
+  if (NULL == This || NULL == ChildHandle) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl              = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  TcpServiceData      = TCP4_FROM_THIS (This);\r
+  TcpProto.TcpService = TcpServiceData;\r
+  TcpProto.TcpPcb     = NULL;\r
+\r
+  //\r
+  // Create a tcp instance with defualt Tcp default\r
+  // sock init data and TcpProto\r
+  //\r
+  mTcp4DefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;\r
+\r
+  Sock = SockCreateChild (&mTcp4DefaultSockData, &TcpProto, sizeof (TCP4_PROTO_DATA));\r
+  if (NULL == Sock) {\r
+    TCP4_DEBUG_ERROR (("Tcp4DriverBindingCreateChild: "\r
+      "No resource to create a Tcp Child\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  *ChildHandle = Sock->SockHandle;\r
+\r
+  //\r
+  // Open the default Ip4 protocol of IP_IO BY_DRIVER.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  TcpServiceData->IpIo->ChildHandle,\r
+                  &gEfiIp4ProtocolGuid,\r
+                  (VOID **) &Ip4,\r
+                  TcpServiceData->DriverBindingHandle,\r
+                  Sock->SockHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    SockDestroyChild (Sock);\r
+  }\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Destroys a child handle with a set of UDP4 services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Handle of the child to be destroyed.\r
+\r
+  @retval EFI_SUCCESS            The TCP4 services are removed from  the child\r
+                                 handle.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval other                  The child handle is not destroyed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4ServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  EFI_TCP4_PROTOCOL  *Tcp4;\r
+  SOCKET             *Sock;\r
+  TCP4_PROTO_DATA    *TcpProtoData;\r
+  TCP4_SERVICE_DATA  *TcpServiceData;\r
+  EFI_TPL            OldTpl;\r
+\r
+  if (NULL == This || NULL == ChildHandle) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // retrieve the Tcp4 protocol from ChildHandle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  (VOID **) &Tcp4,\r
+                  mTcp4DriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // destroy this sock and related Tcp protocol control\r
+  // block\r
+  //\r
+  Sock           = SOCK_FROM_THIS (Tcp4);\r
+  TcpProtoData   = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+  TcpServiceData = TcpProtoData->TcpService;\r
+\r
+  Status = SockDestroyChild (Sock);\r
+\r
+  //\r
+  // Close the Ip4 protocol.\r
+  //\r
+  gBS->CloseProtocol (\r
+         TcpServiceData->IpIo->ChildHandle,\r
+         &gEfiIp4ProtocolGuid,\r
+         TcpServiceData->DriverBindingHandle,\r
+         ChildHandle\r
+         );\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.h
new file mode 100644 (file)
index 0000000..af3444e
--- /dev/null
@@ -0,0 +1,141 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Tcp4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_DRIVER_H_
+#define _TCP4_DRIVER_H_
+
+#include <Protocol/ServiceBinding.h>
+#include <Library/IpIoLib.h>
+
+#define TCP4_DRIVER_SIGNATURE   EFI_SIGNATURE_32 ('T', 'C', 'P', '4')
+
+#define TCP4_PORT_KNOWN         1024
+#define TCP4_PORT_USER_RESERVED 65535
+
+typedef struct _TCP4_HEARTBEAT_TIMER {
+  EFI_EVENT  TimerEvent;
+  INTN       RefCnt;
+} TCP4_HEARTBEAT_TIMER;
+
+typedef struct _TCP4_SERVICE_DATA {
+  UINT32                        Signature;
+  EFI_HANDLE                    ControllerHandle;
+  IP_IO                         *IpIo;  // IP Io consumed by TCP4
+  EFI_SERVICE_BINDING_PROTOCOL  Tcp4ServiceBinding;
+  EFI_HANDLE                    DriverBindingHandle;
+  CHAR16                        *MacString;
+} TCP4_SERVICE_DATA;
+
+//
+// Prototype for TCP4 driver Rcv callback function registered to IP_IO
+//
+VOID
+Tcp4RxCallback (
+  IN EFI_STATUS                       Status,
+  IN ICMP_ERROR                       IcmpErr,
+  IN EFI_NET_SESSION_DATA             *NetSession,
+  IN NET_BUF                          *Pkt,
+  IN VOID                             *Context    OPTIONAL
+  );
+
+INTN
+TcpSendIpPacket (
+  IN TCP_CB    *Tcb,
+  IN NET_BUF   *Nbuf,
+  IN UINT32    Src,
+  IN UINT32    Dest
+  );
+
+EFI_STATUS
+Tcp4Dispatcher (
+  IN SOCKET                  *Sock,
+  IN SOCK_REQUEST            Request,
+  IN VOID                    *Data   OPTIONAL
+  );
+
+typedef struct _TCP4_PROTO_DATA {
+  TCP4_SERVICE_DATA *TcpService;
+  TCP_CB            *TcpPcb;
+} TCP4_PROTO_DATA;
+
+#define TCP4_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  TCP4_SERVICE_DATA, \
+  Tcp4ServiceBinding, \
+  TCP4_DRIVER_SIGNATURE \
+  )
+
+//
+// Function prototype for the driver's entry point
+//
+EFI_STATUS
+EFIAPI
+Tcp4DriverEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+//
+// Function prototypes for the Drivr Binding Protocol
+//
+EFI_STATUS
+EFIAPI
+Tcp4DriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Tcp4DriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Tcp4DriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ControllerHandle,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+//
+// Function ptototypes for the ServiceBinding Prococol
+//
+EFI_STATUS
+EFIAPI
+Tcp4ServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  );
+
+EFI_STATUS
+EFIAPI
+Tcp4ServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
new file mode 100644 (file)
index 0000000..9baea4e
--- /dev/null
@@ -0,0 +1,77 @@
+#/** @file\r
+# Component name for module Tcp4\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. 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
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = Tcp4Dxe\r
+  FILE_GUID                      = 6d6963ab-906d-4a65-a7ca-bd40e5d6af4d\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = Tcp4DriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  SockImpl.c\r
+  SockInterface.c\r
+  Tcp4Proto.h\r
+  Tcp4Main.h\r
+  SockImpl.h\r
+  Tcp4Output.c\r
+  Tcp4Timer.c\r
+  Tcp4Option.h\r
+  Tcp4Dispatcher.c\r
+  Tcp4Input.c\r
+  Tcp4Misc.c\r
+  Tcp4Main.c\r
+  Socket.h\r
+  ComponentName.c\r
+  Tcp4Driver.h\r
+  Tcp4Io.c\r
+  Tcp4Driver.c\r
+  Tcp4Func.h\r
+  Tcp4Option.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  UefiLib\r
+  BaseLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  UefiRuntimeServicesTableLib\r
+  DebugLib\r
+  NetLib\r
+  IpIoLib\r
+\r
+[Protocols]\r
+  gEfiIp4ProtocolGuid                           # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiTcp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiIp4ServiceBindingProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiTcp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.msa b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.msa
new file mode 100644 (file)
index 0000000..fec1934
--- /dev/null
@@ -0,0 +1,90 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>Tcp4Dxe</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>6d6963ab-906d-4a65-a7ca-bd40e5d6af4d</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Tcp4</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <License>All rights reserved. This program and the accompanying materials
+      are licensed and made available under the terms and conditions of the BSD License
+      which accompanies this distribution.  The full text of the license may be found at
+      http://opensource.org/licenses/bsd-license.php
+
+      THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+      WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>Tcp4Dxe</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiRuntimeServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>Tcp4Option.c</Filename>\r
+    <Filename>Tcp4Func.h</Filename>\r
+    <Filename>Tcp4Driver.c</Filename>\r
+    <Filename>Tcp4Io.c</Filename>\r
+    <Filename>Tcp4Driver.h</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>Socket.h</Filename>\r
+    <Filename>Tcp4Main.c</Filename>\r
+    <Filename>Tcp4Misc.c</Filename>\r
+    <Filename>Tcp4Input.c</Filename>\r
+    <Filename>Tcp4Dispatcher.c</Filename>\r
+    <Filename>Tcp4Option.h</Filename>\r
+    <Filename>Tcp4Timer.c</Filename>\r
+    <Filename>Tcp4Output.c</Filename>\r
+    <Filename>SockImpl.h</Filename>\r
+    <Filename>Tcp4Main.h</Filename>\r
+    <Filename>Tcp4Proto.h</Filename>\r
+    <Filename>SockInterface.c</Filename>\r
+    <Filename>SockImpl.c</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiTcp4ProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiTcp4ServiceBindingProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>Tcp4DriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Func.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Func.h
new file mode 100644 (file)
index 0000000..6441c13
--- /dev/null
@@ -0,0 +1,353 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Tcp4Func.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_FUNC_H_
+#define _TCP4_FUNC_H_
+
+//
+// Declaration of all the functions in TCP
+// protocol. It is intended to keep tcp.h
+// clear.
+//
+
+//
+// Functions in tcp.c
+//
+BOOLEAN
+TcpFindTcbByPeer (
+  IN EFI_IPv4_ADDRESS  *Addr,
+  IN TCP_PORTNO        Port
+  );
+
+TCP_CB  *
+TcpLocateTcb (
+  IN TCP_PORTNO  LocalPort,
+  IN UINT32      LocalIp,
+  IN TCP_PORTNO  RemotePort,
+  IN UINT32      RemoteIp,
+  IN BOOLEAN     Syn
+  );
+
+INTN
+TcpInsertTcb (
+  IN TCP_CB *Tcb
+  );
+
+TCP_CB  *
+TcpCloneTcb (
+  IN TCP_CB *Tcb
+  );
+
+TCP_SEQNO
+TcpGetIss (
+  VOID
+  );
+
+VOID
+TcpInitTcbLocal (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpInitTcbPeer (
+  IN TCP_CB     *Tcb,
+  IN TCP_SEG    *Seg,
+  IN TCP_OPTION *Opt
+  );
+
+UINT16
+TcpGetRcvMss (
+  IN SOCKET *Sock
+  );
+
+VOID
+TcpSetState (
+  IN TCP_CB *Tcb,
+  IN UINT8  State
+  );
+
+//
+// Functions in Tcp4Output.c
+//
+INTN
+TcpSendIpPacket (
+  IN TCP_CB  *Tcb,
+  IN NET_BUF *Nbuf,
+  IN UINT32  Src,
+  IN UINT32  Dst
+  );
+
+INTN
+TcpToSendData (
+  IN TCP_CB *Tcb,
+  IN INTN    Force
+  );
+
+VOID
+TcpToSendAck (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpSendAck (
+  IN TCP_CB *Tcb
+  );
+
+INTN
+TcpSendZeroProbe (
+  IN TCP_CB *Tcb
+  );
+
+INTN
+TcpDeliverData (
+  IN TCP_CB *Tcb
+  );
+
+INTN
+TcpSendReset (
+  IN TCP_CB   *Tcb,
+  IN TCP_HEAD *Head,
+  IN INT32    Len,
+  IN UINT32   Local,
+  IN UINT32   Remote
+  );
+
+UINT32
+TcpRcvWinOld (
+  IN TCP_CB *Tcb
+  );
+
+UINT32
+TcpRcvWinNow (
+  IN TCP_CB *Tcb
+  );
+
+INTN
+TcpRetransmit (
+  IN TCP_CB    *Tcb,
+  IN TCP_SEQNO Seq
+  );
+
+UINT32
+TcpDataToSend (
+  IN TCP_CB *Tcb,
+  IN INTN   Force
+  );
+
+INTN
+TcpVerifySegment (
+  IN NET_BUF *Nbuf
+  );
+
+INTN
+TcpCheckSndQue (
+  IN NET_LIST_ENTRY *Head
+  );
+
+NET_BUF *
+TcpGetSegmentSndQue (
+  IN TCP_CB    *Tcb,
+  IN TCP_SEQNO Seq,
+  IN UINT32    Len
+  );
+
+NET_BUF *
+TcpGetSegmentSock (
+  IN TCP_CB    *Tcb,
+  IN TCP_SEQNO Seq,
+  IN UINT32    Len
+  );
+
+NET_BUF *
+TcpGetSegment (
+  IN TCP_CB    *Tcb,
+  IN TCP_SEQNO Seq,
+  IN UINT32    Len
+  );
+
+TCP_SEQNO
+TcpGetMaxSndNxt (
+  IN TCP_CB *Tcb
+  );
+
+//
+// Functions from Tcp4Input.c
+//
+VOID
+TcpIcmpInput (
+  IN NET_BUF     *Nbuf,
+  IN ICMP_ERROR  IcmpErr,
+  IN UINT32      Src,
+  IN UINT32      Dst
+  );
+
+INTN
+TcpInput (
+  IN NET_BUF *Nbuf,
+  IN UINT32  Src,
+  IN UINT32  Dst
+  );
+
+INTN
+TcpSeqAcceptable (
+  IN TCP_CB  *Tcb,
+  IN TCP_SEG *Seg
+  );
+
+VOID
+TcpFastRecover (
+  IN TCP_CB  *Tcb,
+  IN TCP_SEG *Seg
+  );
+
+VOID
+TcpFastLossRecover (
+  IN TCP_CB  *Tcb,
+  IN TCP_SEG *Seg
+  );
+
+VOID
+TcpComputeRtt (
+  IN TCP_CB *Tcb,
+  IN UINT32 Measure
+  );
+
+INTN
+TcpTrimInWnd (
+  IN TCP_CB  *Tcb,
+  IN NET_BUF *Buf
+  );
+
+VOID
+TcpQueueData (
+  IN TCP_CB  *Tcb,
+  IN NET_BUF *Nbuf
+  );
+
+VOID
+TcpAdjustSndQue (
+  IN TCP_CB    *Tcb,
+  IN TCP_SEQNO Ack
+  );
+
+//
+// Functions from Tcp4Misc.c
+//
+UINT16
+TcpChecksum (
+  IN NET_BUF *Buf,
+  IN UINT16  HeadChecksum
+  );
+
+TCP_SEG *
+TcpFormatNetbuf (
+  IN TCP_CB  *Tcb,
+  IN NET_BUF *Nbuf
+  );
+
+VOID
+TcpOnAppConnect (
+  IN TCP_CB  *Tcb
+  );
+
+INTN
+TcpOnAppConsume (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpOnAppClose (
+  IN TCP_CB *Tcb
+  );
+
+INTN
+TcpOnAppSend (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpOnAppAbort (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpResetConnection (
+  IN TCP_CB *Tcb
+  );
+
+//
+// Functions in Tcp4Timer.c
+//
+VOID
+TcpClose (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+EFIAPI
+TcpTicking (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  );
+
+VOID
+TcpSetTimer (
+  IN TCP_CB *Tcb,
+  IN UINT16 Timer,
+  IN UINT32 TimeOut
+  );
+
+VOID
+TcpClearTimer (
+  IN TCP_CB *Tcb,
+  IN UINT16 Timer
+  );
+
+VOID
+TcpClearAllTimer (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpSetProbeTimer (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpSetKeepaliveTimer (
+  IN TCP_CB *Tcb
+  );
+
+VOID
+TcpBackoffRto (
+  IN TCP_CB *Tcb
+  );
+
+EFI_STATUS
+TcpSetVariableData (
+  IN TCP4_SERVICE_DATA  *Tcp4Service
+  );
+
+VOID
+TcpClearVariableData (
+  IN TCP4_SERVICE_DATA  *Tcp4Service
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
new file mode 100644 (file)
index 0000000..b636016
--- /dev/null
@@ -0,0 +1,1486 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Input.c\r
+\r
+Abstract:\r
+\r
+  TCP input process routines.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+/**\r
+  Check whether the sequence number of the incoming segment\r
+  is acceptable.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seg      Pointer to the incoming segment.\r
+\r
+  @return 1 if the sequence number is acceptable, otherwise 0.\r
+\r
+**/\r
+INTN\r
+TcpSeqAcceptable (\r
+  IN TCP_CB  *Tcb,\r
+  IN TCP_SEG *Seg\r
+  )\r
+{\r
+  return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&\r
+          TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));\r
+}\r
+\r
+\r
+/**\r
+  NewReno fast recovery, RFC3782.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seg      Segment that triggers the fast recovery.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpFastRecover (\r
+  IN TCP_CB  *Tcb,\r
+  IN TCP_SEG *Seg\r
+  )\r
+{\r
+  UINT32  FlightSize;\r
+  UINT32  Acked;\r
+\r
+  //\r
+  // Step 1: Three duplicate ACKs and not in fast recovery\r
+  //\r
+  if (Tcb->CongestState != TCP_CONGEST_RECOVER) {\r
+\r
+    //\r
+    // Step 1A: Invoking fast retransmission.\r
+    //\r
+    FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
+\r
+    Tcb->Ssthresh     = NET_MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss));\r
+    Tcb->Recover      = Tcb->SndNxt;\r
+\r
+    Tcb->CongestState = TCP_CONGEST_RECOVER;\r
+    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+\r
+    //\r
+    // Step 2: Entering fast retransmission\r
+    //\r
+    TcpRetransmit (Tcb, Tcb->SndUna);\r
+    Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;\r
+\r
+    TCP4_DEBUG_TRACE (("TcpFastRecover: enter fast retransmission"\r
+      " for TCB %x, recover point is %d\n", Tcb, Tcb->Recover));\r
+    return;\r
+  }\r
+\r
+  //\r
+  // During fast recovery, execute Step 3, 4, 5 of RFC3782\r
+  //\r
+  if (Seg->Ack == Tcb->SndUna) {\r
+\r
+    //\r
+    // Step 3: Fast Recovery,\r
+    // If this is a duplicated ACK, increse Cwnd by SMSS.\r
+    //\r
+\r
+    // Step 4 is skipped here only to be executed later\r
+    // by TcpToSendData\r
+    //\r
+    Tcb->CWnd += Tcb->SndMss;\r
+    TCP4_DEBUG_TRACE (("TcpFastRecover: received another"\r
+      " duplicated ACK (%d) for TCB %x\n", Seg->Ack, Tcb));\r
+\r
+  } else {\r
+\r
+    //\r
+    // New data is ACKed, check whether it is a\r
+    // full ACK or partial ACK\r
+    //\r
+    if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) {\r
+\r
+      //\r
+      // Step 5 - Full ACK:\r
+      // deflate the congestion window, and exit fast recovery\r
+      //\r
+      FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
+\r
+      Tcb->CWnd         = NET_MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss);\r
+\r
+      Tcb->CongestState = TCP_CONGEST_OPEN;\r
+      TCP4_DEBUG_TRACE (("TcpFastRecover: received a full ACK(%d)"\r
+        " for TCB %x, exit fast recovery\n", Seg->Ack, Tcb));\r
+\r
+    } else {\r
+\r
+      //\r
+      // Step 5 - Partial ACK:\r
+      // fast retransmit the first unacknowledge field\r
+      // , then deflate the CWnd\r
+      //\r
+      TcpRetransmit (Tcb, Seg->Ack);\r
+      Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna);\r
+\r
+      //\r
+      // Deflate the CWnd by the amount of new data\r
+      // ACKed by SEG.ACK. If more than one SMSS data\r
+      // is ACKed, add back SMSS byte to CWnd after\r
+      //\r
+      if (Acked >= Tcb->SndMss) {\r
+        Acked -= Tcb->SndMss;\r
+\r
+      }\r
+\r
+      Tcb->CWnd -= Acked;\r
+\r
+      TCP4_DEBUG_TRACE (("TcpFastRecover: received a partial"\r
+        " ACK(%d) for TCB %x\n", Seg->Ack, Tcb));\r
+\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  NewReno fast loss recovery, RFC3792.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seg      Segment that triggers the fast loss recovery.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpFastLossRecover (\r
+  IN TCP_CB  *Tcb,\r
+  IN TCP_SEG *Seg\r
+  )\r
+{\r
+  if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+    //\r
+    // New data is ACKed, check whether it is a\r
+    // full ACK or partial ACK\r
+    //\r
+    if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) {\r
+\r
+      //\r
+      // Full ACK: exit the loss recovery.\r
+      //\r
+      Tcb->LossTimes    = 0;\r
+      Tcb->CongestState = TCP_CONGEST_OPEN;\r
+\r
+      TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "\r
+        "full ACK(%d) for TCB %x\n", Seg->Ack, Tcb));\r
+\r
+    } else {\r
+\r
+      //\r
+      // Partial ACK:\r
+      // fast retransmit the first unacknowledge field.\r
+      //\r
+      TcpRetransmit (Tcb, Seg->Ack);\r
+      TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "\r
+        "partial ACK(%d) for TCB %x\n", Seg->Ack, Tcb));\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Compute the RTT as specified in RFC2988\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Measure  Currently measured RTT in heart beats.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpComputeRtt (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT32 Measure\r
+  )\r
+{\r
+  INT32 Var;\r
+\r
+  //\r
+  // Step 2.3: Compute the RTO for subsequent RTT measurement.\r
+  //\r
+  if (Tcb->SRtt != 0) {\r
+\r
+    Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT);\r
+\r
+    if (Var < 0) {\r
+      Var = -Var;\r
+    }\r
+\r
+    Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2;\r
+    Tcb->SRtt   = 7 * (Tcb->SRtt >> 3) + Measure;\r
+\r
+  } else {\r
+    //\r
+    // Step 2.2: compute the first RTT measure\r
+    //\r
+    Tcb->SRtt   = Measure << TCP_RTT_SHIFT;\r
+    Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1);\r
+  }\r
+\r
+  Tcb->Rto = (Tcb->SRtt + NET_MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT;\r
+\r
+  //\r
+  // Step 2.4: Limit the RTO to at least 1 second\r
+  // Step 2.5: Limit the RTO to a maxium value that\r
+  // is at least 60 second\r
+  //\r
+  if (Tcb->Rto < TCP_RTO_MIN) {\r
+    Tcb->Rto = TCP_RTO_MIN;\r
+\r
+  } else if (Tcb->Rto > TCP_RTO_MAX) {\r
+    Tcb->Rto = TCP_RTO_MAX;\r
+\r
+  }\r
+\r
+  TCP4_DEBUG_TRACE (("TcpComputeRtt: new RTT for TCB %x"\r
+    " computed SRTT: %d RTTVAR: %d RTO: %d\n",\r
+    Tcb, Tcb->SRtt, Tcb->RttVar, Tcb->Rto));\r
+\r
+}\r
+\r
+\r
+/**\r
+  Trim the data, SYN and FIN to fit into the window defined by\r
+  Left and Right.\r
+\r
+  @param  Nbuf     Buffer that contains received TCP segment without IP header.\r
+  @param  Left     The sequence number of the window's left edge.\r
+  @param  Right    The sequence number of the window's right edge.\r
+\r
+  @return 0, the data is successfully trimmed.\r
+\r
+**/\r
+STATIC\r
+INTN\r
+TcpTrimSegment (\r
+  IN NET_BUF   *Nbuf,\r
+  IN TCP_SEQNO Left,\r
+  IN TCP_SEQNO Right\r
+  )\r
+{\r
+  TCP_SEG   *Seg;\r
+  TCP_SEQNO Urg;\r
+  UINT32    Drop;\r
+\r
+  Seg = TCPSEG_NETBUF (Nbuf);\r
+\r
+  //\r
+  // If the segment is completely out of window,\r
+  // truncate every thing, include SYN and FIN.\r
+  //\r
+  if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {\r
+\r
+    TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
+    TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
+\r
+    Seg->Seq = Seg->End;\r
+    NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Adjust the buffer header\r
+  //\r
+  if (TCP_SEQ_LT (Seg->Seq, Left)) {\r
+\r
+    Drop      = TCP_SUB_SEQ (Left, Seg->Seq);\r
+    Urg       = Seg->Seq + Seg->Urg;\r
+    Seg->Seq  = Left;\r
+\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+      TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
+      Drop--;\r
+    }\r
+\r
+    //\r
+    // Adjust the urgent point\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {\r
+\r
+      if (TCP_SEQ_LT (Urg, Seg->Seq)) {\r
+\r
+        TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
+      } else {\r
+        Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);\r
+      }\r
+    }\r
+\r
+    if (Drop) {\r
+      NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Adjust the buffer tail\r
+  //\r
+  if (TCP_SEQ_GT (Seg->End, Right)) {\r
+\r
+    Drop      = TCP_SUB_SEQ (Seg->End, Right);\r
+    Seg->End  = Right;\r
+\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+      TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
+      Drop--;\r
+    }\r
+\r
+    if (Drop) {\r
+      NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);\r
+    }\r
+  }\r
+\r
+  ASSERT (TcpVerifySegment (Nbuf));\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Trim off the data outside the tcb's receive window.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf     Pointer to the NET_BUF containing the received tcp segment.\r
+\r
+  @return 0, the data is trimmed.\r
+\r
+**/\r
+INTN\r
+TcpTrimInWnd (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  return TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
+}\r
+\r
+\r
+/**\r
+  Process the data and FIN flag, check whether to deliver\r
+  data to the socket layer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @retval 0        No error occurred to deliver data.\r
+  @retval -1       Error condition occurred. Proper response is to reset the\r
+                   connection.\r
+\r
+**/\r
+INTN\r
+TcpDeliverData (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *Entry;\r
+  NET_BUF         *Nbuf;\r
+  TCP_SEQNO       Seq;\r
+  TCP_SEG         *Seg;\r
+  UINT32          Urgent;\r
+\r
+  ASSERT (Tcb && Tcb->Sk);\r
+\r
+  //\r
+  // make sure there is some data queued,\r
+  // and TCP is in a proper state\r
+  //\r
+  if (NetListIsEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {\r
+\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Deliver data to the socket layer\r
+  //\r
+  Entry = Tcb->RcvQue.ForwardLink;\r
+  Seq   = Tcb->RcvNxt;\r
+\r
+  while (Entry != &Tcb->RcvQue) {\r
+    Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+    Seg   = TCPSEG_NETBUF (Nbuf);\r
+\r
+    ASSERT (TcpVerifySegment (Nbuf));\r
+    ASSERT (Nbuf->Tcp == NULL);\r
+\r
+    if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
+      break;\r
+    }\r
+\r
+    Entry       = Entry->ForwardLink;\r
+    Seq         = Seg->End;\r
+    Tcb->RcvNxt = Seq;\r
+\r
+    NetListRemoveEntry (&Nbuf->List);\r
+\r
+    //\r
+    // RFC793 Eighth step: process FIN in sequence\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+\r
+      //\r
+      // The peer sends to us junky data after FIN,\r
+      // reset the connection.\r
+      //\r
+      if (!NetListIsEmpty (&Tcb->RcvQue)) {\r
+        TCP4_DEBUG_ERROR (("TcpDeliverData: data received after"\r
+          " FIN from peer of TCB %x, reset connection\n", Tcb));\r
+\r
+        NetbufFree (Nbuf);\r
+        return -1;\r
+      }\r
+\r
+      TCP4_DEBUG_TRACE (("TcpDeliverData: processing FIN "\r
+        "from peer of TCB %x\n", Tcb));\r
+\r
+      switch (Tcb->State) {\r
+      case TCP_SYN_RCVD:\r
+      case TCP_ESTABLISHED:\r
+\r
+        TcpSetState (Tcb, TCP_CLOSE_WAIT);\r
+        break;\r
+\r
+      case TCP_FIN_WAIT_1:\r
+\r
+        if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+          TcpSetState (Tcb, TCP_CLOSING);\r
+          break;\r
+        }\r
+\r
+      //\r
+      // fall through\r
+      //\r
+      case TCP_FIN_WAIT_2:\r
+\r
+        TcpSetState (Tcb, TCP_TIME_WAIT);\r
+        TcpClearAllTimer (Tcb);\r
+\r
+        if (Tcb->TimeWaitTimeout != 0) {\r
+\r
+          TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
+        } else {\r
+\r
+          TCP4_DEBUG_WARN (("Connection closed immediately "\r
+            "because app disables TIME_WAIT timer for %x\n", Tcb));\r
+\r
+          TcpSendAck (Tcb);\r
+          TcpClose (Tcb);\r
+        }\r
+        break;\r
+\r
+      case TCP_CLOSE_WAIT:\r
+      case TCP_CLOSING:\r
+      case TCP_LAST_ACK:\r
+      case TCP_TIME_WAIT:\r
+        //\r
+        // The peer sends to us junk FIN byte. Discard\r
+        // the buffer then reset the connection\r
+        //\r
+        NetbufFree (Nbuf);\r
+        return -1;\r
+        break;\r
+      }\r
+\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+\r
+      Seg->End--;\r
+    }\r
+\r
+    //\r
+    // Don't delay the ack if PUSH flag is on.\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {\r
+\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+    }\r
+\r
+    if (Nbuf->TotalSize) {\r
+      Urgent = 0;\r
+\r
+      if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
+          TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp)) {\r
+\r
+        if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {\r
+          Urgent = Nbuf->TotalSize;\r
+        } else {\r
+          Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;\r
+        }\r
+      }\r
+\r
+      SockDataRcvd (Tcb->Sk, Nbuf, Urgent);\r
+    }\r
+\r
+    if (TCP_FIN_RCVD (Tcb->State)) {\r
+\r
+      SockNoMoreData (Tcb->Sk);\r
+    }\r
+\r
+    NetbufFree (Nbuf);\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Store the data into the reassemble queue.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf     Pointer to the buffer containing the data to be queued.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpQueueData (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  TCP_SEG         *Seg;\r
+  NET_LIST_ENTRY  *Head;\r
+  NET_LIST_ENTRY  *Prev;\r
+  NET_LIST_ENTRY  *Cur;\r
+  NET_BUF         *Node;\r
+\r
+  ASSERT (Tcb && Nbuf && (Nbuf->Tcp == NULL));\r
+\r
+  NET_GET_REF (Nbuf);\r
+\r
+  Seg   = TCPSEG_NETBUF (Nbuf);\r
+  Head  = &Tcb->RcvQue;\r
+\r
+  //\r
+  // Fast path to process normal case. That is,\r
+  // no out-of-order segments are received.\r
+  //\r
+  if (NetListIsEmpty (Head)) {\r
+\r
+    NetListInsertTail (Head, &Nbuf->List);\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Find the point to insert the buffer\r
+  //\r
+  for (Prev = Head, Cur = Head->ForwardLink;\r
+      Cur != Head;\r
+      Prev = Cur, Cur = Cur->ForwardLink) {\r
+\r
+    Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+\r
+    if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check whether the current segment overlaps with the\r
+  // previous segment.\r
+  //\r
+  if (Prev != Head) {\r
+    Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
+\r
+    if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {\r
+\r
+      if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {\r
+\r
+        NetbufFree (Nbuf);\r
+        return ;\r
+      }\r
+\r
+      TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);\r
+    }\r
+  }\r
+\r
+  NetListInsertHead (Prev, &Nbuf->List);\r
+\r
+  TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+\r
+  //\r
+  // Check the segments after the insert point.\r
+  //\r
+  while (Cur != Head) {\r
+    Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+\r
+    if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {\r
+\r
+      Cur = Cur->ForwardLink;\r
+\r
+      NetListRemoveEntry (&Node->List);\r
+      NetbufFree (Node);\r
+      continue;\r
+    }\r
+\r
+    if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {\r
+\r
+      if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {\r
+\r
+        NetListRemoveEntry (&Nbuf->List);\r
+        NetbufFree (Nbuf);\r
+        return ;\r
+      }\r
+\r
+      TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);\r
+      break;\r
+    }\r
+\r
+    Cur = Cur->ForwardLink;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Ajust the send queue or the retransmit queue.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Ack      The acknowledge seuqence number of the received segment.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpAdjustSndQue (\r
+  IN TCP_CB    *Tcb,\r
+  IN TCP_SEQNO Ack\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *Head;\r
+  NET_LIST_ENTRY  *Cur;\r
+  NET_BUF         *Node;\r
+  TCP_SEG         *Seg;\r
+\r
+  Head  = &Tcb->SndQue;\r
+  Cur   = Head->ForwardLink;\r
+\r
+  while (Cur != Head) {\r
+    Node  = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+    Seg   = TCPSEG_NETBUF (Node);\r
+\r
+    if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Remove completely ACKed segments\r
+    //\r
+    if (TCP_SEQ_LEQ (Seg->End, Ack)) {\r
+      Cur = Cur->ForwardLink;\r
+\r
+      NetListRemoveEntry (&Node->List);\r
+      NetbufFree (Node);\r
+      continue;\r
+    }\r
+\r
+    TcpTrimSegment (Node, Ack, Seg->End);\r
+    break;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Process the received TCP segments.\r
+\r
+  @param  Nbuf     Buffer that contains received TCP segment without IP header.\r
+  @param  Src      Source address of the segment, or the peer's IP address.\r
+  @param  Dst      Destination address of the segment, or the local end's IP\r
+                   address.\r
+\r
+  @retval 0        Segment is processed successfully. It is either accepted or\r
+                   discarded. But no connection is reset by the segment.\r
+  @retval -1       A connection is reset by the segment.\r
+\r
+**/\r
+INTN\r
+TcpInput (\r
+  IN NET_BUF *Nbuf,\r
+  IN UINT32  Src,\r
+  IN UINT32  Dst\r
+  )\r
+{\r
+  TCP_CB      *Tcb;\r
+  TCP_CB      *Parent;\r
+  TCP_OPTION  Option;\r
+  TCP_HEAD    *Head;\r
+  INT32       Len;\r
+  TCP_SEG     *Seg;\r
+  TCP_SEQNO   Right;\r
+  TCP_SEQNO   Urg;\r
+\r
+  NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
+\r
+  Parent  = NULL;\r
+  Tcb     = NULL;\r
+\r
+  Head    = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
+  Len     = Nbuf->TotalSize - (Head->HeadLen << 2);\r
+\r
+  if ((Head->HeadLen < 5) || (Len < 0) ||\r
+      TcpChecksum (Nbuf, NetPseudoHeadChecksum (Src, Dst, 6, 0))) {\r
+\r
+    TCP4_DEBUG_TRACE (("TcpInput: received an mal-formated packet\n"));\r
+    goto DISCARD;\r
+  }\r
+\r
+  if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {\r
+    Len++;\r
+  }\r
+\r
+  if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {\r
+    Len++;\r
+  }\r
+\r
+  Tcb = TcpLocateTcb (\r
+          Head->DstPort,\r
+          Dst,\r
+          Head->SrcPort,\r
+          Src,\r
+          (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)\r
+          );\r
+\r
+  if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
+    TCP4_DEBUG_TRACE (("TcpInput: send reset because no TCB find\n"));\r
+\r
+    Tcb = NULL;\r
+    goto SEND_RESET;\r
+  }\r
+\r
+  Seg = TcpFormatNetbuf (Tcb, Nbuf);\r
+\r
+  //\r
+  // RFC1122 recommended reaction to illegal option\r
+  // (in fact, an illegal option length) is reset.\r
+  //\r
+  if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
+    TCP4_DEBUG_ERROR (("TcpInput: reset the peer because"\r
+      " of mal-format option for Tcb %x\n", Tcb));\r
+\r
+    goto SEND_RESET;\r
+  }\r
+\r
+  //\r
+  // From now on, the segment is headless\r
+  //\r
+  NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);\r
+  Nbuf->Tcp = NULL;\r
+\r
+  //\r
+  // TODO: add fast path process here\r
+  //\r
+\r
+  //\r
+  // Process the segment in LISTEN state.\r
+  //\r
+  if (Tcb->State == TCP_LISTEN) {\r
+    //\r
+    // First step: Check RST\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+      TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "\r
+        "for TCB %x in listening\n", Tcb));\r
+\r
+      goto DISCARD;\r
+    }\r
+\r
+    //\r
+    // Second step: Check ACK.\r
+    // Any ACK sent to TCP in LISTEN is reseted.\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+      TCP4_DEBUG_WARN (("TcpInput: send reset because of"\r
+        " segment with ACK for TCB %x in listening\n", Tcb));\r
+\r
+      goto SEND_RESET;\r
+    }\r
+\r
+    //\r
+    // Third step: Check SYN\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+      //\r
+      // create a child TCB to handle the data\r
+      //\r
+      Parent  = Tcb;\r
+\r
+      Tcb     = TcpCloneTcb (Parent);\r
+      if (Tcb == NULL) {\r
+        TCP4_DEBUG_ERROR (("TcpInput: discard a segment because"\r
+          "failed to clone a child for TCB%x\n", Tcb));\r
+\r
+        goto DISCARD;\r
+      }\r
+\r
+      TCP4_DEBUG_TRACE (("TcpInput: create a child for TCB %x"\r
+        " in listening\n", Tcb));\r
+\r
+      //\r
+      // init the TCB structure\r
+      //\r
+      Tcb->LocalEnd.Ip    = Dst;\r
+      Tcb->LocalEnd.Port  = Head->DstPort;\r
+      Tcb->RemoteEnd.Ip   = Src;\r
+      Tcb->RemoteEnd.Port = Head->SrcPort;\r
+\r
+      TcpInitTcbLocal (Tcb);\r
+      TcpInitTcbPeer (Tcb, Seg, &Option);\r
+\r
+      TcpSetState (Tcb, TCP_SYN_RCVD);\r
+      TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
+      TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+      goto StepSix;\r
+    }\r
+\r
+    goto DISCARD;\r
+\r
+  } else if (Tcb->State == TCP_SYN_SENT) {\r
+    //\r
+    // First step: Check ACK bit\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {\r
+\r
+      TCP4_DEBUG_WARN (("TcpInput: send reset because of "\r
+        "wrong ACK received for TCB %x in SYN_SENT\n", Tcb));\r
+\r
+      goto SEND_RESET;\r
+    }\r
+\r
+    //\r
+    // Second step: Check RST bit\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+\r
+      if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+\r
+        TCP4_DEBUG_WARN (("TcpInput: connection reset by"\r
+          " peer for TCB%x in SYN_SENT\n", Tcb));\r
+\r
+        SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
+        goto DROP_CONNECTION;\r
+      } else {\r
+\r
+        TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "\r
+          "because of no ACK for TCB%x in SYN_SENT\n", Tcb));\r
+\r
+        goto DISCARD;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Third step: Check security and precedence. Skipped\r
+    //\r
+\r
+    //\r
+    // Fourth step: Check SYN. Pay attention to sitimulatous open\r
+    //\r
+    if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+\r
+      TcpInitTcbPeer (Tcb, Seg, &Option);\r
+\r
+      if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+\r
+        Tcb->SndUna = Seg->Ack;\r
+      }\r
+\r
+      TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
+\r
+      if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {\r
+\r
+        TcpSetState (Tcb, TCP_ESTABLISHED);\r
+\r
+        TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
+        TcpDeliverData (Tcb);\r
+\r
+        if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
+            TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+\r
+          TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
+          TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+        }\r
+\r
+        TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+        TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+\r
+        TCP4_DEBUG_TRACE (("TcpInput: connection established"\r
+          " for TCB %x in SYN_SENT\n", Tcb));\r
+\r
+        goto StepSix;\r
+      } else {\r
+        //\r
+        // Received a SYN segment without ACK, simultanous open.\r
+        //\r
+        TcpSetState (Tcb, TCP_SYN_RCVD);\r
+\r
+        ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
+        TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
+\r
+        TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+        TCP4_DEBUG_WARN (("TcpInput: simultanous open "\r
+          "for TCB %x in SYN_SENT\n", Tcb));\r
+\r
+        goto StepSix;\r
+      }\r
+    }\r
+\r
+    goto DISCARD;\r
+  }\r
+\r
+  //\r
+  // Process segment in SYN_RCVD or TCP_CONNECTED states\r
+  //\r
+\r
+  //\r
+  // First step: Check whether SEG.SEQ is acceptable\r
+  //\r
+  if (!TcpSeqAcceptable (Tcb, Seg)) {\r
+    TCP4_DEBUG_WARN (("TcpInput: sequence acceptance"\r
+      " test failed for segment of TCB %x\n", Tcb));\r
+\r
+    if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+      TcpSendAck (Tcb);\r
+    }\r
+\r
+    goto DISCARD;\r
+  }\r
+\r
+  if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
+      (Tcb->RcvWl2 == Seg->End) &&\r
+      !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) {\r
+\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+  }\r
+\r
+  //\r
+  // Second step: Check the RST\r
+  //\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+\r
+    TCP4_DEBUG_WARN (("TcpInput: connection reset for TCB %x\n", Tcb));\r
+\r
+    if (Tcb->State == TCP_SYN_RCVD) {\r
+\r
+      SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
+\r
+      //\r
+      // This TCB comes from either a LISTEN TCB,\r
+      // or active open TCB with simultanous open.\r
+      // Do NOT signal user CONNECTION refused\r
+      // if it comes from a LISTEN TCB.\r
+      //\r
+    } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
+             (Tcb->State == TCP_FIN_WAIT_1) ||\r
+             (Tcb->State == TCP_FIN_WAIT_2) ||\r
+             (Tcb->State == TCP_CLOSE_WAIT)\r
+            ) {\r
+\r
+      SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
+\r
+    } else {\r
+      //\r
+      // TODO: set socket error to CLOSED\r
+      //\r
+    }\r
+\r
+    goto DROP_CONNECTION;\r
+  }\r
+\r
+  //\r
+  // Trim the data and flags.\r
+  //\r
+  TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+  //\r
+  // Third step: Check security and precedence, Ignored\r
+  //\r
+\r
+  //\r
+  // Fourth step: Check the SYN bit.\r
+  //\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+\r
+    TCP4_DEBUG_WARN (("TcpInput: connection reset "\r
+      "because received extra SYN for TCB %x\n", Tcb));\r
+\r
+    SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
+    goto RESET_THEN_DROP;\r
+  }\r
+\r
+  //\r
+  // Fifth step: Check the ACK\r
+  //\r
+  if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+    TCP4_DEBUG_WARN (("TcpInput: segment discard because"\r
+      " of no ACK for connected TCB %x\n", Tcb));\r
+\r
+    goto DISCARD;\r
+\r
+  }\r
+\r
+  if (Tcb->State == TCP_SYN_RCVD) {\r
+\r
+    if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
+        TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {\r
+\r
+      Tcb->SndWnd     = Seg->Wnd;\r
+      Tcb->SndWndMax  = NET_MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
+      Tcb->SndWl1     = Seg->Seq;\r
+      Tcb->SndWl2     = Seg->Ack;\r
+      TcpSetState (Tcb, TCP_ESTABLISHED);\r
+\r
+      TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
+      TcpDeliverData (Tcb);\r
+\r
+      TCP4_DEBUG_TRACE (("TcpInput: connection established "\r
+        " for TCB %x in SYN_RCVD\n", Tcb));\r
+\r
+      //\r
+      // Continue the process as ESTABLISHED state\r
+      //\r
+    } else {\r
+      TCP4_DEBUG_WARN (("TcpInput: send reset because of"\r
+        " wrong ACK for TCB %x in SYN_RCVD\n", Tcb));\r
+\r
+      goto SEND_RESET;\r
+    }\r
+  }\r
+\r
+  if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+    TCP4_DEBUG_WARN (("TcpInput: ignore the out-of-data"\r
+      " ACK for connected TCB %x\n", Tcb));\r
+\r
+    goto StepSix;\r
+\r
+  } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
+\r
+    TCP4_DEBUG_WARN (("TcpInput: discard segment for "\r
+      "future ACK for connected TCB %x\n", Tcb));\r
+\r
+    TcpSendAck (Tcb);\r
+    goto DISCARD;\r
+  }\r
+\r
+  //\r
+  // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
+  //\r
+  if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
+    //\r
+    // update TsRecent as specified in page 16 RFC1323.\r
+    // RcvWl2 equals to the variable "LastAckSent"\r
+    // defined there.\r
+    //\r
+    if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
+        TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {\r
+\r
+      Tcb->TsRecent     = Option.TSVal;\r
+      Tcb->TsRecentAge  = mTcpTick;\r
+    }\r
+\r
+    TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
+\r
+  } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+\r
+    ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
+\r
+    TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
+    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+  }\r
+\r
+  if (Seg->Ack == Tcb->SndNxt) {\r
+\r
+    TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
+  } else {\r
+\r
+    TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
+  }\r
+\r
+  //\r
+  // Count duplicate acks.\r
+  //\r
+  if ((Seg->Ack == Tcb->SndUna) &&\r
+      (Tcb->SndUna != Tcb->SndNxt) &&\r
+      (Seg->Wnd == Tcb->SndWnd) &&\r
+      (0 == Len)) {\r
+\r
+    Tcb->DupAck++;\r
+  } else {\r
+\r
+    Tcb->DupAck = 0;\r
+  }\r
+\r
+  //\r
+  // Congestion avoidance, fast recovery and fast retransmission.\r
+  //\r
+  if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
+      (Tcb->CongestState == TCP_CONGEST_LOSS)) {\r
+\r
+    if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+      if (Tcb->CWnd < Tcb->Ssthresh) {\r
+\r
+        Tcb->CWnd += Tcb->SndMss;\r
+      } else {\r
+\r
+        Tcb->CWnd += NET_MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
+      }\r
+\r
+      Tcb->CWnd = NET_MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
+    }\r
+\r
+    if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
+      TcpFastLossRecover (Tcb, Seg);\r
+    }\r
+  } else {\r
+\r
+    TcpFastRecover (Tcb, Seg);\r
+  }\r
+\r
+  if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+    TcpAdjustSndQue (Tcb, Seg->Ack);\r
+    Tcb->SndUna = Seg->Ack;\r
+\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
+        (TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))) {\r
+\r
+      TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Update window info\r
+  //\r
+  if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
+      ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) {\r
+\r
+    Right = Seg->Ack + Seg->Wnd;\r
+\r
+    if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
+\r
+      if ((Tcb->SndWl1 == Seg->Seq) &&\r
+          (Tcb->SndWl2 == Seg->Ack) &&\r
+          (Len == 0)) {\r
+\r
+        goto NO_UPDATE;\r
+      }\r
+\r
+      TCP4_DEBUG_WARN (("TcpInput: peer shrinks the"\r
+        " window  for connected TCB %x\n", Tcb));\r
+\r
+      if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
+          (TCP_SEQ_LT (Right, Tcb->Recover))) {\r
+\r
+        Tcb->Recover = Right;\r
+      }\r
+\r
+      if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
+          (TCP_SEQ_LT (Right, Tcb->LossRecover))) {\r
+\r
+        Tcb->LossRecover = Right;\r
+      }\r
+\r
+      if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
+\r
+        Tcb->SndNxt = Right;\r
+\r
+        if (Right == Tcb->SndUna) {\r
+\r
+          TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
+          TcpSetProbeTimer (Tcb);\r
+        }\r
+      }\r
+    }\r
+\r
+    Tcb->SndWnd     = Seg->Wnd;\r
+    Tcb->SndWndMax  = NET_MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
+    Tcb->SndWl1     = Seg->Seq;\r
+    Tcb->SndWl2     = Seg->Ack;\r
+  }\r
+\r
+NO_UPDATE:\r
+\r
+  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
+      (Tcb->SndUna == Tcb->SndNxt)) {\r
+\r
+    TCP4_DEBUG_TRACE (("TcpInput: local FIN is ACKed by"\r
+      " peer for connected TCB %x\n", Tcb));\r
+\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
+  }\r
+\r
+  //\r
+  // Transit the state if proper.\r
+  //\r
+  switch (Tcb->State) {\r
+  case TCP_FIN_WAIT_1:\r
+\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+      TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
+\r
+      TcpClearAllTimer (Tcb);\r
+      TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
+    }\r
+\r
+  case TCP_FIN_WAIT_2:\r
+\r
+    break;\r
+\r
+  case TCP_CLOSE_WAIT:\r
+    break;\r
+\r
+  case TCP_CLOSING:\r
+\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+      TcpSetState (Tcb, TCP_TIME_WAIT);\r
+\r
+      TcpClearAllTimer (Tcb);\r
+\r
+      if (Tcb->TimeWaitTimeout != 0) {\r
+\r
+        TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
+      } else {\r
+\r
+        TCP4_DEBUG_WARN (("Connection closed immediately "\r
+          "because app disables TIME_WAIT timer for %x\n", Tcb));\r
+\r
+        TcpClose (Tcb);\r
+      }\r
+    }\r
+    break;\r
+\r
+  case TCP_LAST_ACK:\r
+\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+      TcpSetState (Tcb, TCP_CLOSED);\r
+    }\r
+\r
+    break;\r
+\r
+  case TCP_TIME_WAIT:\r
+\r
+    TcpSendAck (Tcb);\r
+\r
+    if (Tcb->TimeWaitTimeout != 0) {\r
+\r
+      TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
+    } else {\r
+\r
+      TCP4_DEBUG_WARN (("Connection closed immediately "\r
+        "because app disables TIME_WAIT timer for %x\n", Tcb));\r
+\r
+      TcpClose (Tcb);\r
+    }\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Sixth step: Check the URG bit.update the Urg point\r
+  // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
+  //\r
+StepSix:\r
+\r
+  Tcb->Idle = 0;\r
+  TcpSetKeepaliveTimer (Tcb);\r
+\r
+  if (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {\r
+\r
+    TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
+  }\r
+\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) &&\r
+      !TCP_FIN_RCVD (Tcb->State)) {\r
+\r
+    TCP4_DEBUG_TRACE (("TcpInput: received urgent data "\r
+      "from peer for connected TCB %x\n", Tcb));\r
+\r
+    Urg = Seg->Seq + Seg->Urg;\r
+\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
+        TCP_SEQ_GT (Urg, Tcb->RcvUp)) {\r
+\r
+      Tcb->RcvUp = Urg;\r
+    } else {\r
+\r
+      Tcb->RcvUp = Urg;\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Seventh step: Process the segment data\r
+  //\r
+  if (Seg->End != Seg->Seq) {\r
+\r
+    if (TCP_FIN_RCVD (Tcb->State)) {\r
+\r
+      TCP4_DEBUG_WARN (("TcpInput: connection reset because"\r
+        " data is lost for connected TCB %x\n", Tcb));\r
+\r
+      goto RESET_THEN_DROP;\r
+    }\r
+\r
+    if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
+      TCP4_DEBUG_WARN (("TcpInput: connection reset because"\r
+        " data is lost for connected TCB %x\n", Tcb));\r
+\r
+      goto RESET_THEN_DROP;\r
+    }\r
+\r
+    TcpQueueData (Tcb, Nbuf);\r
+    if (TcpDeliverData (Tcb) == -1) {\r
+      goto RESET_THEN_DROP;\r
+    }\r
+\r
+    if (!NetListIsEmpty (&Tcb->RcvQue)) {\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Eighth step: check the FIN.\r
+  // This step is moved to TcpDeliverData. FIN will be\r
+  // processed in sequence there. Check the comments in\r
+  // the beginning of the file header for information.\r
+  //\r
+\r
+  //\r
+  // Tcb is a new child of the listening Parent,\r
+  // commit it.\r
+  //\r
+  if (Parent) {\r
+    Tcb->Parent = Parent;\r
+    TcpInsertTcb (Tcb);\r
+  }\r
+\r
+  if ((Tcb->State != TCP_CLOSED) &&\r
+      (!TcpToSendData (Tcb, 0)) &&\r
+      (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || Nbuf->TotalSize)) {\r
+\r
+    TcpToSendAck (Tcb);\r
+  }\r
+\r
+  NetbufFree (Nbuf);\r
+  return 0;\r
+\r
+RESET_THEN_DROP:\r
+  TcpSendReset (Tcb, Head, Len, Dst, Src);\r
+\r
+DROP_CONNECTION:\r
+  ASSERT (Tcb && Tcb->Sk);\r
+\r
+  NetbufFree (Nbuf);\r
+  TcpClose (Tcb);\r
+\r
+  return -1;\r
+\r
+SEND_RESET:\r
+\r
+  TcpSendReset (Tcb, Head, Len, Dst, Src);\r
+\r
+DISCARD:\r
+\r
+  //\r
+  // Tcb is a child of Parent, and it doesn't survive\r
+  //\r
+  TCP4_DEBUG_WARN (("Tcp4Input: Discard a packet\n"));\r
+  NetbufFree (Nbuf);\r
+\r
+  if (Parent && Tcb) {\r
+\r
+    ASSERT (Tcb->Sk);\r
+    TcpClose (Tcb);\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Process the received ICMP error messages for TCP.\r
+\r
+  @param  Nbuf     Buffer that contains part of the TCP segment without IP header\r
+                   truncated from the ICMP error packet.\r
+  @param  IcmpErr  The ICMP error code interpreted from ICMP error packet.\r
+  @param  Src      Source address of the ICMP error message.\r
+  @param  Dst      Destination address of the ICMP error message.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpIcmpInput (\r
+  IN NET_BUF     *Nbuf,\r
+  IN ICMP_ERROR  IcmpErr,\r
+  IN UINT32      Src,\r
+  IN UINT32      Dst\r
+  )\r
+{\r
+  TCP_HEAD         *Head;\r
+  TCP_CB           *Tcb;\r
+  TCP_SEQNO        Seq;\r
+  EFI_STATUS       IcmpErrStatus;\r
+  BOOLEAN          IcmpErrIsHard;\r
+  BOOLEAN          IcmpErrNotify;\r
+\r
+  Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
+  Tcb = TcpLocateTcb (\r
+          Head->DstPort,\r
+          Dst,\r
+          Head->SrcPort,\r
+          Src,\r
+          FALSE\r
+          );\r
+  if (Tcb == NULL || Tcb->State == TCP_CLOSED) {\r
+\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  //\r
+  // Validate the sequence number.\r
+  //\r
+  Seq = NTOHL (Head->Seq);\r
+  if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
+\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  IcmpErrStatus = IpIoGetIcmpErrStatus (IcmpErr, &IcmpErrIsHard, &IcmpErrNotify);\r
+\r
+  if (IcmpErrNotify) {\r
+\r
+    SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
+  }\r
+\r
+  if (IcmpErrIsHard) {\r
+\r
+    TcpClose (Tcb);\r
+  }\r
+\r
+CLEAN_EXIT:\r
+  NetbufFree (Nbuf);\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Io.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Io.c
new file mode 100644 (file)
index 0000000..2f7a49f
--- /dev/null
@@ -0,0 +1,117 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Io.c\r
+\r
+Abstract:\r
+\r
+  I/O interfaces between TCP and IpIo.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+/**\r
+  Packet receive callback function provided to IP_IO, used to call\r
+  the proper function to handle the packet received by IP.\r
+\r
+  @param  Status      Status of the received packet.\r
+  @param  IcmpErr     ICMP error number.\r
+  @param  NetSession  Pointer to the net session of this packet.\r
+  @param  Pkt         Pointer to the recieved packet.\r
+  @param  Context     Pointer to the context configured in IpIoOpen(), not used\r
+                      now.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+Tcp4RxCallback (\r
+  IN EFI_STATUS                       Status,\r
+  IN ICMP_ERROR                       IcmpErr,\r
+  IN EFI_NET_SESSION_DATA             *NetSession,\r
+  IN NET_BUF                          *Pkt,\r
+  IN VOID                             *Context    OPTIONAL\r
+  )\r
+{\r
+  if (EFI_SUCCESS == Status) {\r
+    TcpInput (Pkt, NetSession->Source, NetSession->Dest);\r
+  } else {\r
+    TcpIcmpInput (Pkt, IcmpErr, NetSession->Source, NetSession->Dest);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Send the segment to IP via IpIo function.\r
+\r
+  @param  Tcb         Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf        Pointer to the TCP segment to be sent.\r
+  @param  Src         Source address of the TCP segment.\r
+  @param  Dest        Destination address of the TCP segment.\r
+\r
+  @retval 0           The segment was sent out successfully.\r
+  @retval -1          The segment was failed to send.\r
+\r
+**/\r
+INTN\r
+TcpSendIpPacket (\r
+  IN TCP_CB    *Tcb,\r
+  IN NET_BUF   *Nbuf,\r
+  IN UINT32    Src,\r
+  IN UINT32    Dest\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  IP_IO            *IpIo;\r
+  IP_IO_OVERRIDE   Override;\r
+  SOCKET           *Sock;\r
+  VOID             *IpSender;\r
+  TCP4_PROTO_DATA  *TcpProto;\r
+\r
+  if (NULL == Tcb) {\r
+\r
+    IpIo     = NULL;\r
+    IpSender = IpIoFindSender (&IpIo, Src);\r
+\r
+    if (IpSender == NULL) {\r
+      TCP4_DEBUG_WARN (("TcpSendIpPacket: No appropriate IpSender.\n"));\r
+      return -1;\r
+    }\r
+  } else {\r
+\r
+    Sock     = Tcb->Sk;\r
+    TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+    IpIo     = TcpProto->TcpService->IpIo;\r
+    IpSender = Tcb->IpInfo;\r
+  }\r
+\r
+  Override.TypeOfService            = 0;\r
+  Override.TimeToLive               = 255;\r
+  Override.DoNotFragment            = FALSE;\r
+  Override.Protocol                 = EFI_IP_PROTO_TCP;\r
+  EFI_IP4 (Override.GatewayAddress) = 0;\r
+  EFI_IP4 (Override.SourceAddress)  = Src;\r
+\r
+  Status = IpIoSend (IpIo, Nbuf, IpSender, NULL, NULL, Dest, &Override);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    TCP4_DEBUG_ERROR (("TcpSendIpPacket: return %r error\n", Status));\r
+    return -1;\r
+  }\r
+\r
+  return 0;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.c
new file mode 100644 (file)
index 0000000..8a8cd8a
--- /dev/null
@@ -0,0 +1,564 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Main.c\r
+\r
+Abstract:\r
+\r
+  Implementation of TCP4 protocol services.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+/**\r
+  Check the integrity of the data buffer.\r
+\r
+  @param  DataLen                  The total length of the data buffer.\r
+  @param  FragmentCount            The fragment count of the fragment table.\r
+  @param  FragmentTable            Pointer to the fragment table of the data\r
+                                   buffer.\r
+\r
+  @retval EFI_SUCCESS              The integrity check is passed.\r
+  @retval EFI_INVALID_PARAMETER    The integrity check is failed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4ChkDataBuf (\r
+  IN UINT32                 DataLen,\r
+  IN UINT32                 FragmentCount,\r
+  IN EFI_TCP4_FRAGMENT_DATA *FragmentTable\r
+  )\r
+{\r
+  UINT32 Index;\r
+\r
+  UINT32 Len;\r
+\r
+  for (Index = 0, Len = 0; Index < FragmentCount; Index++) {\r
+    Len = Len + FragmentTable[Index].FragmentLength;\r
+  }\r
+\r
+  if (DataLen != Len) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Get the current operational status.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance.\r
+  @param  Tcp4State                Pointer to the buffer to receive the current TCP\r
+                                   state.\r
+  @param  Tcp4ConfigData           Pointer to the buffer to receive the current TCP\r
+                                   configuration.\r
+  @param  Ip4ModeData              Pointer to the buffer to receive the current\r
+                                   IPv4 configuration.\r
+  @param  MnpConfigData            Pointer to the buffer to receive the current MNP\r
+                                   configuration data indirectly used by the TCPv4\r
+                                   Instance.\r
+  @param  SnpModeData              Pointer to the buffer to receive the current SNP\r
+                                   configuration data indirectly used by the TCPv4\r
+                                   Instance.\r
+\r
+  @retval EFI_SUCCESS              The mode data was read.\r
+  @retval EFI_NOT_STARTED          No configuration data is available because this\r
+                                   instance hasn't been started.\r
+  @retval EFI_INVALID_PARAMETER    This is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4GetModeData (\r
+  IN  CONST EFI_TCP4_PROTOCOL                  * This,\r
+  OUT       EFI_TCP4_CONNECTION_STATE          * Tcp4State OPTIONAL,\r
+  OUT       EFI_TCP4_CONFIG_DATA               * Tcp4ConfigData OPTIONAL,\r
+  OUT       EFI_IP4_MODE_DATA                  * Ip4ModeData OPTIONAL,\r
+  OUT       EFI_MANAGED_NETWORK_CONFIG_DATA    * MnpConfigData OPTIONAL,\r
+  OUT       EFI_SIMPLE_NETWORK_MODE            * SnpModeData OPTIONAL\r
+  )\r
+{\r
+  TCP4_MODE_DATA  TcpMode;\r
+  SOCKET          *Sock;\r
+\r
+  if (NULL == This) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Sock                    = SOCK_FROM_THIS (This);\r
+\r
+  TcpMode.Tcp4State       = Tcp4State;\r
+  TcpMode.Tcp4ConfigData  = Tcp4ConfigData;\r
+  TcpMode.Ip4ModeData     = Ip4ModeData;\r
+  TcpMode.MnpConfigData   = MnpConfigData;\r
+  TcpMode.SnpModeData     = SnpModeData;\r
+\r
+  return SockGetMode (Sock, &TcpMode);\r
+}\r
+\r
+\r
+/**\r
+  Initialize or brutally reset the operational parameters for\r
+  this EFI TCPv4 instance.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance.\r
+  @param  TcpConfigData            Pointer to the configure data to configure the\r
+                                   instance.\r
+\r
+  @retval EFI_SUCCESS              The operational settings are set, changed, or\r
+                                   reset successfully.\r
+  @retval EFI_NO_MAPPING           When using a default address, configuration\r
+                                   (through DHCP, BOOTP, RARP, etc.) is not\r
+                                   finished.\r
+  @retval EFI_INVALID_PARAMETER    One or more parameters are invalid.\r
+  @retval EFI_ACCESS_DENIED        Configuring TCP instance when it is already\r
+                                   configured.\r
+  @retval EFI_DEVICE_ERROR         An unexpected network or system error occurred.\r
+  @retval EFI_UNSUPPORTED          One or more of the control options are not\r
+                                   supported in the implementation.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate enough system resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Configure (\r
+  IN EFI_TCP4_PROTOCOL        * This,\r
+  IN EFI_TCP4_CONFIG_DATA     * TcpConfigData OPTIONAL\r
+  )\r
+{\r
+  EFI_TCP4_OPTION  *Option;\r
+  SOCKET           *Sock;\r
+  EFI_STATUS       Status;\r
+\r
+  if (NULL == This) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Tcp protocol related parameter check will be conducted here\r
+  //\r
+  if (NULL != TcpConfigData) {\r
+    if ((EFI_IP4 (TcpConfigData->AccessPoint.RemoteAddress) != 0) &&\r
+      !Ip4IsUnicast (EFI_NTOHL (TcpConfigData->AccessPoint.RemoteAddress), 0)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (!TcpConfigData->AccessPoint.UseDefaultAddress) {\r
+      if (!Ip4IsUnicast (EFI_NTOHL (TcpConfigData->AccessPoint.StationAddress), 0) ||\r
+          !IP4_IS_VALID_NETMASK (EFI_NTOHL (TcpConfigData->AccessPoint.SubnetMask))\r
+            ) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+\r
+    if (TcpConfigData->AccessPoint.ActiveFlag &&\r
+        (0 == TcpConfigData->AccessPoint.RemotePort ||\r
+        (EFI_IP4 (TcpConfigData->AccessPoint.RemoteAddress) == 0))\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Option = TcpConfigData->ControlOption;\r
+    if ((NULL != Option) &&\r
+        (Option->EnableSelectiveAck || Option->EnablePathMtuDiscovery)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  Sock = SOCK_FROM_THIS (This);\r
+\r
+  if (NULL == TcpConfigData) {\r
+    return SockFlush (Sock);\r
+  }\r
+\r
+  Status = SockConfigure (Sock, TcpConfigData);\r
+\r
+  if (EFI_NO_MAPPING == Status) {\r
+    Sock->ConfigureState = SO_NO_MAPPING;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Add or delete routing entries.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance.\r
+  @param  DeleteRoute              If TRUE, delete the specified route from routing\r
+                                   table; if FALSE, add the specified route to\r
+                                   routing table.\r
+  @param  SubnetAddress            The destination network.\r
+  @param  SubnetMask               The subnet mask for the destination network.\r
+  @param  GatewayAddress           The gateway address for this route.\r
+\r
+  @retval EFI_SUCCESS              The operation completed successfully.\r
+  @retval EFI_NOT_STARTED          The EFI_TCP4_PROTOCOL instance has not been\r
+                                   configured.\r
+  @retval EFI_NO_MAPPING           When using a default address, configuration\r
+                                   (through DHCP, BOOTP, RARP, etc.) is not\r
+                                   finished.\r
+  @retval EFI_INVALID_PARAMETER    One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate enough resources to add the\r
+                                   entry to the routing table.\r
+  @retval EFI_NOT_FOUND            This route is not in the routing table.\r
+  @retval EFI_ACCESS_DENIED        This route is already in the routing table.\r
+  @retval EFI_UNSUPPORTED          The TCP driver does not support this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Routes (\r
+  IN EFI_TCP4_PROTOCOL           *This,\r
+  IN BOOLEAN                     DeleteRoute,\r
+  IN EFI_IPv4_ADDRESS            *SubnetAddress,\r
+  IN EFI_IPv4_ADDRESS            *SubnetMask,\r
+  IN EFI_IPv4_ADDRESS            *GatewayAddress\r
+  )\r
+{\r
+  SOCKET          *Sock;\r
+  TCP4_ROUTE_INFO RouteInfo;\r
+\r
+  if (NULL == This) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Sock                      = SOCK_FROM_THIS (This);\r
+\r
+  RouteInfo.DeleteRoute     = DeleteRoute;\r
+  RouteInfo.SubnetAddress   = SubnetAddress;\r
+  RouteInfo.SubnetMask      = SubnetMask;\r
+  RouteInfo.GatewayAddress  = GatewayAddress;\r
+\r
+  return SockRoute (Sock, &RouteInfo);\r
+}\r
+\r
+\r
+/**\r
+  Initiate a nonblocking TCP connection request for an active TCP instance.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance\r
+  @param  ConnectionToken          Pointer to the connection token to return when\r
+                                   the TCP three way handshake finishes.\r
+\r
+  @retval EFI_SUCCESS              The connection request is successfully\r
+                                   initiated.\r
+  @retval EFI_NOT_STARTED          This EFI_TCP4_PROTOCOL instance hasn't been\r
+                                   configured.\r
+  @retval EFI_ACCESS_DENIED        The instance is not configured as an active one\r
+                                   or it is not in Tcp4StateClosed state.\r
+  @retval EFI_INVALID_PARAMETER    One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     The driver can't allocate enough resource to\r
+                                   initiate the active open.\r
+  @retval EFI_DEVICE_ERROR         An unexpected system or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Connect (\r
+  IN EFI_TCP4_PROTOCOL           *This,\r
+  IN EFI_TCP4_CONNECTION_TOKEN   *ConnectionToken\r
+  )\r
+{\r
+  SOCKET  *Sock;\r
+\r
+  if (NULL == This ||\r
+      NULL == ConnectionToken ||\r
+      NULL == ConnectionToken->CompletionToken.Event) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Sock = SOCK_FROM_THIS (This);\r
+\r
+  return SockConnect (Sock, ConnectionToken);\r
+}\r
+\r
+\r
+/**\r
+  Listen on the passive instance to accept an incoming connection request.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance\r
+  @param  ListenToken              Pointer to the listen token to return when\r
+                                   operation finishes.\r
+\r
+  @retval EFI_SUCCESS              The listen token has been queued successfully.\r
+  @retval EFI_NOT_STARTED          The EFI_TCP4_PROTOCOL instance hasn't been\r
+                                   configured.\r
+  @retval EFI_ACCESS_DENIED        The instatnce is not a passive one or it is not\r
+                                   in Tcp4StateListen state or a same listen token\r
+                                   has already existed in the listen token queue of\r
+                                   this TCP instance.\r
+  @retval EFI_INVALID_PARAMETER    One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate enough resources to finish\r
+                                   the operation.\r
+  @retval EFI_DEVICE_ERROR         An unexpected system or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Accept (\r
+  IN EFI_TCP4_PROTOCOL             *This,\r
+  IN EFI_TCP4_LISTEN_TOKEN         *ListenToken\r
+  )\r
+{\r
+  SOCKET  *Sock;\r
+\r
+  if (NULL == This ||\r
+      NULL == ListenToken ||\r
+      NULL == ListenToken->CompletionToken.Event) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Sock = SOCK_FROM_THIS (This);\r
+\r
+  return SockAccept (Sock, ListenToken);\r
+}\r
+\r
+\r
+/**\r
+  Queues outgoing data into the transmit queue\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance\r
+  @param  Token                    Pointer to the completion token to queue to the\r
+                                   transmit queue\r
+\r
+  @retval EFI_SUCCESS              The data has been queued for transmission\r
+  @retval EFI_NOT_STARTED          The EFI_TCP4_PROTOCOL instance hasn't been\r
+                                   configured.\r
+  @retval EFI_NO_MAPPING           When using a default address, configuration\r
+                                   (DHCP, BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_INVALID_PARAMETER    One or more parameters are invalid\r
+  @retval EFI_ACCESS_DENIED        One or more of the following conditions is TRUE:\r
+                                   * A transmit completion token with the same\r
+                                   Token-> CompletionToken.Event was already in the\r
+                                   transmission queue. * The current instance is in\r
+                                   Tcp4StateClosed state * The current instance is\r
+                                   a passive one and it is in Tcp4StateListen\r
+                                   state. * User has called Close() to disconnect\r
+                                   this connection.\r
+  @retval EFI_NOT_READY            The completion token could not be queued because\r
+                                   the transmit queue is full.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not queue the transmit data because of\r
+                                   resource shortage.\r
+  @retval EFI_NETWORK_UNREACHABLE  There is no route to the destination network or\r
+                                   address.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Transmit (\r
+  IN EFI_TCP4_PROTOCOL            *This,\r
+  IN EFI_TCP4_IO_TOKEN            *Token\r
+  )\r
+{\r
+  SOCKET      *Sock;\r
+  EFI_STATUS  Status;\r
+\r
+  if (NULL == This ||\r
+      NULL == Token ||\r
+      NULL == Token->CompletionToken.Event ||\r
+      NULL == Token->Packet.TxData ||\r
+      0 == Token->Packet.TxData->FragmentCount ||\r
+      0 == Token->Packet.TxData->DataLength\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = Tcp4ChkDataBuf (\r
+            Token->Packet.TxData->DataLength,\r
+            Token->Packet.TxData->FragmentCount,\r
+            Token->Packet.TxData->FragmentTable\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Sock = SOCK_FROM_THIS (This);\r
+\r
+  return SockSend (Sock, Token);\r
+\r
+}\r
+\r
+\r
+/**\r
+  Place an asynchronous receive request into the receiving queue.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance.\r
+  @param  Token                    Pointer to a token that is associated with the\r
+                                   receive data descriptor.\r
+\r
+  @retval EFI_SUCCESS              The receive completion token was cached\r
+  @retval EFI_NOT_STARTED          The EFI_TCP4_PROTOCOL instance hasn't been\r
+                                   configured.\r
+  @retval EFI_NO_MAPPING           When using a default address, configuration\r
+                                   (DHCP, BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_INVALID_PARAMETER    One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     The receive completion token could not be queued\r
+                                   due to a lack of system resources.\r
+  @retval EFI_DEVICE_ERROR         An unexpected system or network error occurred.\r
+  @retval EFI_ACCESS_DENIED        One or more of the following conditions is TRUE:\r
+                                   * A receive completion token with the same\r
+                                   Token->CompletionToken.Event was already in the\r
+                                   receive queue. * The current instance is in\r
+                                   Tcp4StateClosed state. * The current instance is\r
+                                   a passive one and it is in Tcp4StateListen\r
+                                   state. * User has called Close() to disconnect\r
+                                   this connection.\r
+  @retval EFI_CONNECTION_FIN       The communication peer has closed the connection\r
+                                   and there is no any buffered data in the receive\r
+                                   buffer of this instance.\r
+  @retval EFI_NOT_READY            The receive request could not be queued because\r
+                                   the receive queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Receive (\r
+  IN EFI_TCP4_PROTOCOL           *This,\r
+  IN EFI_TCP4_IO_TOKEN           *Token\r
+  )\r
+{\r
+  SOCKET      *Sock;\r
+  EFI_STATUS  Status;\r
+\r
+  if (NULL == This ||\r
+      NULL == Token ||\r
+      NULL == Token->CompletionToken.Event ||\r
+      NULL == Token->Packet.RxData ||\r
+      0 == Token->Packet.RxData->FragmentCount ||\r
+      0 == Token->Packet.RxData->DataLength\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = Tcp4ChkDataBuf (\r
+            Token->Packet.RxData->DataLength,\r
+            Token->Packet.RxData->FragmentCount,\r
+            Token->Packet.RxData->FragmentTable\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Sock = SOCK_FROM_THIS (This);\r
+\r
+  return SockRcv (Sock, Token);\r
+\r
+}\r
+\r
+\r
+/**\r
+  Disconnecting a TCP connection gracefully or reset a TCP connection.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance\r
+  @param  CloseToken               Pointer to the close token to return when\r
+                                   operation finishes.\r
+\r
+  @retval EFI_SUCCESS              The operation completed successfully\r
+  @retval EFI_NOT_STARTED          The EFI_TCP4_PROTOCOL instance hasn't been\r
+                                   configured.\r
+  @retval EFI_ACCESS_DENIED        One or more of the following are TRUE: *\r
+                                   Configure() has been called with TcpConfigData\r
+                                   set to NULL and this function has not returned.\r
+                                   * Previous Close() call on this instance has not\r
+                                   finished.\r
+  @retval EFI_INVALID_PARAMETER    One ore more parameters are invalid\r
+  @retval EFI_OUT_OF_RESOURCES     Could not allocate enough resource to finish the\r
+                                   operation\r
+  @retval EFI_DEVICE_ERROR         Any unexpected and not belonged to above\r
+                                   category error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Close (\r
+  IN EFI_TCP4_PROTOCOL           *This,\r
+  IN EFI_TCP4_CLOSE_TOKEN        *CloseToken\r
+  )\r
+{\r
+  SOCKET  *Sock;\r
+\r
+  if (NULL == This ||\r
+      NULL == CloseToken ||\r
+      NULL == CloseToken->CompletionToken.Event) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Sock = SOCK_FROM_THIS (This);\r
+\r
+  return SockClose (Sock, CloseToken, CloseToken->AbortOnClose);\r
+}\r
+\r
+\r
+/**\r
+  Abort an asynchronous connection, listen, transmission or receive request.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance.\r
+  @param  Token                    Pointer to a token that has been issued by\r
+                                   Connect(), Accept(), Transmit() or Receive(). If\r
+                                   NULL, all pending tokens issued by above four\r
+                                   functions will be aborted.\r
+\r
+  @retval EFI_UNSUPPORTED          The operation is not supported in current\r
+                                   implementation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Cancel (\r
+  IN EFI_TCP4_PROTOCOL           * This,\r
+  IN EFI_TCP4_COMPLETION_TOKEN   * Token OPTIONAL\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Poll to receive incoming data and transmit outgoing segments.\r
+\r
+  @param  This                     Pointer to the EFI_TCP4_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS              Incoming or outgoing data was processed.\r
+  @retval EFI_INVALID_PARAMETER    This is NULL.\r
+  @retval EFI_DEVICE_ERROR         An unexpected system or network error occurred.\r
+  @retval EFI_NOT_READY            No incoming or outgoing data was processed.\r
+  @retval EFI_TIMEOUT              Data was dropped out of the transmission or\r
+                                   receive queue. Consider increasing the polling\r
+                                   rate.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Poll (\r
+  IN EFI_TCP4_PROTOCOL        *This\r
+  )\r
+{\r
+  SOCKET      *Sock;\r
+  EFI_STATUS  Status;\r
+\r
+  if (NULL == This) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Sock    = SOCK_FROM_THIS (This);\r
+\r
+  Status  = Sock->ProtoHandler (Sock, SOCK_POLL, NULL);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.h
new file mode 100644 (file)
index 0000000..dba46aa
--- /dev/null
@@ -0,0 +1,176 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Tcp4Main.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_MAIN_H_
+#define _TCP4_MAIN_H_
+
+#include "Socket.h"
+
+#include "Tcp4Proto.h"
+#include "Tcp4Driver.h"
+
+
+extern UINT16  mTcp4RandomPort;
+
+//
+// Driver Produced Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_PRODUCER (Tcp4)
+
+#define TCP4_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR   ("Tcp", PrintArg)
+#define TCP4_DEBUG_WARN(PrintArg)  NET_DEBUG_WARNING ("Tcp", PrintArg)
+#define TCP4_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE   ("Tcp", PrintArg)
+
+//
+// Function prototype for the Tcp4 socket request handler
+//
+EFI_STATUS
+Tcp4Dispatcher (
+  IN SOCKET                  *Sock,
+  IN SOCK_REQUEST            Request,
+  IN VOID                    *Data    OPTIONAL
+  );
+
+typedef struct _TCP4_MODE_DATA {
+  EFI_TCP4_CONNECTION_STATE       *Tcp4State;
+  EFI_TCP4_CONFIG_DATA            *Tcp4ConfigData;
+  EFI_IP4_MODE_DATA               *Ip4ModeData;
+  EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData;
+  EFI_SIMPLE_NETWORK_MODE         *SnpModeData;
+} TCP4_MODE_DATA;
+
+typedef struct _TCP4_ROUTE_INFO {
+  BOOLEAN           DeleteRoute;
+  EFI_IPv4_ADDRESS  *SubnetAddress;
+  EFI_IPv4_ADDRESS  *SubnetMask;
+  EFI_IPv4_ADDRESS  *GatewayAddress;
+} TCP4_ROUTE_INFO;
+
+//
+// Get the mode data of a TCP instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4GetModeData (
+  IN  CONST EFI_TCP4_PROTOCOL                  * This,
+  OUT       EFI_TCP4_CONNECTION_STATE          * Tcp4State OPTIONAL,
+  OUT       EFI_TCP4_CONFIG_DATA               * Tcp4ConfigData OPTIONAL,
+  OUT       EFI_IP4_MODE_DATA                  * Ip4ModeData OPTIONAL,
+  OUT       EFI_MANAGED_NETWORK_CONFIG_DATA    * MnpConfigData OPTIONAL,
+  OUT       EFI_SIMPLE_NETWORK_MODE            * SnpModeData OPTIONAL
+  );
+
+//
+// Initialize or reset a TCP instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4Configure (
+  IN EFI_TCP4_PROTOCOL        * This,
+  IN EFI_TCP4_CONFIG_DATA     * TcpConfigData OPTIONAL
+  );
+
+//
+// Add a route entry to the route table
+//
+EFI_STATUS
+EFIAPI
+Tcp4Routes (
+  IN EFI_TCP4_PROTOCOL           *This,
+  IN BOOLEAN                     DeleteRoute,
+  IN EFI_IPv4_ADDRESS            *SubnetAddress,
+  IN EFI_IPv4_ADDRESS            *SubnetMask,
+  IN EFI_IPv4_ADDRESS            *GatewayAddress
+  );
+
+//
+// Issue an asynchronous connection establishment
+// request to the peer
+//
+EFI_STATUS
+EFIAPI
+Tcp4Connect (
+  IN EFI_TCP4_PROTOCOL           *This,
+  IN EFI_TCP4_CONNECTION_TOKEN   *ConnectionToken
+  );
+
+//
+// Issue an asynchronous listent token to accept an
+// incoming connection reques
+//
+EFI_STATUS
+EFIAPI
+Tcp4Accept (
+  IN EFI_TCP4_PROTOCOL             *This,
+  IN EFI_TCP4_LISTEN_TOKEN         *ListenToken
+  );
+
+//
+// Issue an asynchronous IO token to transmit some data
+// through this TCP instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4Transmit (
+  IN EFI_TCP4_PROTOCOL            *This,
+  IN EFI_TCP4_IO_TOKEN            *Token
+  );
+
+//
+// Issue an asynchronous IO token to receive some data
+// through this TCP instance
+//
+EFI_STATUS
+Tcp4Receive (
+  IN EFI_TCP4_PROTOCOL           *This,
+  IN EFI_TCP4_IO_TOKEN           *Token
+  );
+
+//
+// Issue an asynchronous CloseToken to close a TCP
+// connection represented by instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4Close (
+  IN EFI_TCP4_PROTOCOL           *This,
+  IN EFI_TCP4_CLOSE_TOKEN        *CloseToken
+  );
+
+//
+// cancle an connect, listent or IO token
+//
+EFI_STATUS
+EFIAPI
+Tcp4Cancel (
+  IN EFI_TCP4_PROTOCOL           * This,
+  IN EFI_TCP4_COMPLETION_TOKEN   * Token OPTIONAL
+  );
+
+//
+// poll data from NIC for receive
+//
+EFI_STATUS
+EFIAPI
+Tcp4Poll (
+  IN EFI_TCP4_PROTOCOL        *This
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
new file mode 100644 (file)
index 0000000..7f1f141
--- /dev/null
@@ -0,0 +1,1091 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Misc.c\r
+\r
+Abstract:\r
+\r
+  Misc support routines for tcp.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Tcp4Main.h"\r
+\r
+NET_LIST_ENTRY  mTcpRunQue = {\r
+  &mTcpRunQue,\r
+  &mTcpRunQue\r
+};\r
+\r
+NET_LIST_ENTRY  mTcpListenQue = {\r
+  &mTcpListenQue,\r
+  &mTcpListenQue\r
+};\r
+\r
+TCP_SEQNO       mTcpGlobalIss = 0x4d7e980b;\r
+\r
+STATIC 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  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+TcpInitTcbLocal (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  //\r
+  // Compute the checksum of the fixed parts of pseudo header\r
+  //\r
+  Tcb->HeadSum = NetPseudoHeadChecksum (\r
+                  Tcb->LocalEnd.Ip,\r
+                  Tcb->RemoteEnd.Ip,\r
+                  0x06,\r
+                  0\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
+  // Fisrt window size is never scaled\r
+  //\r
+  Tcb->RcvWndScale = 0;\r
+}\r
+\r
+\r
+/**\r
+  Initialize the peer related members.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seg                   Pointer to the segment that contains the peer's\r
+                                intial info.\r
+  @param  Opt                   Pointer to the options announced by the peer.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+TcpInitTcbPeer (\r
+  IN TCP_CB     *Tcb,\r
+  IN TCP_SEG    *Seg,\r
+  IN TCP_OPTION *Opt\r
+  )\r
+{\r
+  UINT16  RcvMss;\r
+\r
+  ASSERT (Tcb && Seg && Opt);\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 = NET_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) &&\r
+      !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) &&\r
+      !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
+/**\r
+  Locate a listen TCB that matchs the Local and Remote.\r
+\r
+  @param  Local                 Pointer to the local (IP, Port).\r
+  @param  Remote                Pointer to the remote (IP, Port).\r
+\r
+  @return Pointer to the TCP_CB with the least number of wildcard, if NULL no match is found.\r
+\r
+**/\r
+STATIC\r
+TCP_CB *\r
+TcpLocateListenTcb (\r
+  IN TCP_PEER *Local,\r
+  IN TCP_PEER *Remote\r
+  )\r
+{\r
+  NET_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 ((Local->Port != Node->LocalEnd.Port) ||\r
+        !TCP_PEER_MATCH (Remote, &Node->RemoteEnd) ||\r
+        !TCP_PEER_MATCH (Local, &Node->LocalEnd)\r
+          ) {\r
+\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Compute the number of wildcard\r
+    //\r
+    Cur = 0;\r
+    if (Node->RemoteEnd.Ip == 0) {\r
+      Cur++;\r
+    }\r
+\r
+    if (Node->RemoteEnd.Port == 0) {\r
+      Cur++;\r
+    }\r
+\r
+    if (Node->LocalEnd.Ip == 0) {\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
+/**\r
+  Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.\r
+\r
+  @param  Addr                  Pointer to the IP address needs to match.\r
+  @param  Port                  The port number needs to match.\r
+\r
+  @return The Tcb which matches the <Addr Port> paire exists or not.\r
+\r
+**/\r
+BOOLEAN\r
+TcpFindTcbByPeer (\r
+  IN EFI_IPv4_ADDRESS  *Addr,\r
+  IN TCP_PORTNO        Port\r
+  )\r
+{\r
+  TCP_PORTNO      LocalPort;\r
+  NET_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 ((EFI_IP4 (*Addr) == Tcb->LocalEnd.Ip) &&\r
+      (LocalPort == Tcb->LocalEnd.Port)) {\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 (((EFI_IP4 (*Addr) == Tcb->LocalEnd.Ip)) &&\r
+      (LocalPort == Tcb->LocalEnd.Port)) {\r
+\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Locate the TCP_CB related to the socket pair.\r
+\r
+  @param  LocalPort             The local port number.\r
+  @param  LocalIp               The local IP address.\r
+  @param  RemotePort            The remote port number.\r
+  @param  RemoteIp              The remote IP address.\r
+  @param  Syn                   Whether to search the listen sockets, if TRUE, the\r
+                                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 UINT32      LocalIp,\r
+  IN TCP_PORTNO  RemotePort,\r
+  IN UINT32      RemoteIp,\r
+  IN BOOLEAN     Syn\r
+  )\r
+{\r
+  TCP_PEER        Local;\r
+  TCP_PEER        Remote;\r
+  NET_LIST_ENTRY  *Entry;\r
+  TCP_CB          *Tcb;\r
+\r
+  Local.Port  = LocalPort;\r
+  Local.Ip    = LocalIp;\r
+\r
+  Remote.Port = RemotePort;\r
+  Remote.Ip   = RemoteIp;\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 (TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd) &&\r
+        TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd)) {\r
+\r
+      NetListRemoveEntry (&Tcb->List);\r
+      NetListInsertHead (&mTcpRunQue, &Tcb->List);\r
+\r
+      return Tcb;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Only check listen queue when SYN flag is on\r
+  //\r
+  if (Syn) {\r
+    return TcpLocateListenTcb (&Local, &Remote);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Insert a Tcb into the proper queue.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB to be inserted.\r
+\r
+  @retval 0                     The Tcb is inserted successfully.\r
+  @retval -1                    Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpInsertTcb (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NET_LIST_ENTRY   *Entry;\r
+  NET_LIST_ENTRY   *Head;\r
+  TCP_CB           *Node;\r
+  TCP4_PROTO_DATA  *TcpProto;\r
+\r
+  ASSERT (\r
+    Tcb &&\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 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) &&\r
+        TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd)) {\r
+\r
+      return -1;\r
+    }\r
+  }\r
+\r
+  NetListInsertHead (Head, &Tcb->List);\r
+\r
+  TcpProto = (TCP4_PROTO_DATA *) Tcb->Sk->ProtoReserved;\r
+  TcpSetVariableData (TcpProto->TcpService);\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Clone a TCP_CB from Tcb.\r
+\r
+  @param  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 = NetAllocatePool (sizeof (TCP_CB));\r
+\r
+  if (Clone == NULL) {\r
+    return NULL;\r
+\r
+  }\r
+\r
+  NetCopyMem (Clone, Tcb, sizeof (TCP_CB));\r
+\r
+  //\r
+  // Increate the reference count of the shared IpInfo.\r
+  //\r
+  NET_GET_REF (Tcb->IpInfo);\r
+\r
+  NetListInit (&Clone->List);\r
+  NetListInit (&Clone->SndQue);\r
+  NetListInit (&Clone->RcvQue);\r
+\r
+  Clone->Sk = SockClone (Tcb->Sk);\r
+  if (Clone->Sk == NULL) {\r
+    TCP4_DEBUG_ERROR (("TcpCloneTcb: failed to clone a sock\n"));\r
+    NetFreePool (Clone);\r
+    return NULL;\r
+  }\r
+\r
+  ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
+\r
+  return Clone;\r
+}\r
+\r
+\r
+/**\r
+  Compute an ISS to be used by a new connection.\r
+\r
+  None\r
+\r
+  @return The result ISS.\r
+\r
+**/\r
+TCP_SEQNO\r
+TcpGetIss (\r
+  VOID\r
+  )\r
+{\r
+  mTcpGlobalIss += 2048;\r
+  return mTcpGlobalIss;\r
+}\r
+\r
+\r
+/**\r
+  Get the local mss.\r
+\r
+  None\r
+\r
+  @return The mss size.\r
+\r
+**/\r
+UINT16\r
+TcpGetRcvMss (\r
+  IN SOCKET  *Sock\r
+  )\r
+{\r
+  EFI_SIMPLE_NETWORK_MODE SnpMode;\r
+  TCP4_PROTO_DATA         *TcpProto;\r
+  EFI_IP4_PROTOCOL        *Ip;\r
+\r
+  ASSERT (Sock);\r
+\r
+  TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+  Ip       = TcpProto->TcpService->IpIo->Ip;\r
+  ASSERT (Ip);\r
+\r
+  Ip->GetModeData (Ip, NULL, NULL, &SnpMode);\r
+\r
+  return (UINT16) (SnpMode.MaxPacketSize - 40);\r
+}\r
+\r
+\r
+/**\r
+  Set the Tcb's state.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+  @param  State                 The state to be set.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+TcpSetState (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT8  State\r
+  )\r
+{\r
+  TCP4_DEBUG_TRACE (\r
+    ("Tcb (%x) 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
+    break;\r
+\r
+  case TCP_CLOSED:\r
+\r
+    SockConnClosed (Tcb->Sk);\r
+\r
+    break;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Compute the TCP segment's checksum.\r
+\r
+  @param  Nbuf                  Pointer to the buffer that contains the TCP\r
+                                segment.\r
+  @param  HeadSum               The checksum value of the fixed part of pseudo\r
+                                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 ~Checksum;\r
+}\r
+\r
+\r
+/**\r
+  Translate the information from the head of the received TCP\r
+  segment Nbuf contains and fill it into a TCP_SEG structure.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+  @param  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 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
+  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 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
+/**\r
+  Reset the connection related with Tcb.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of the connection to be\r
+                                reset.\r
+\r
+  @return None\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  = (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);\r
+\r
+  NetbufFree (Nbuf);\r
+}\r
+\r
+\r
+/**\r
+  Initialize an active connection,\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB that wants to initiate a\r
+                                connection.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+TcpOnAppConnect (\r
+  IN 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
+/**\r
+  Initiate the connection close procedure, called when\r
+  applications want to close the connection.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpOnAppClose (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  ASSERT (Tcb);\r
+\r
+  if (!NetListIsEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk)) {\r
+\r
+    TCP4_DEBUG_WARN (("TcpOnAppClose: connection reset "\r
+      "because data is lost for TCB %x\n", Tcb));\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
+  }\r
+\r
+  TcpToSendData (Tcb, 1);\r
+}\r
+\r
+\r
+/**\r
+  Check whether the application's newly delivered data\r
+  can be sent out.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @retval 0                     Whether the data is sent out or is buffered for\r
+                                further sending.\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 TCP_CB *Tcb\r
+  )\r
+{\r
+\r
+  switch (Tcb->State) {\r
+  case TCP_CLOSED:\r
+    return -1;\r
+    break;\r
+\r
+  case TCP_LISTEN:\r
+    return -1;\r
+    break;\r
+\r
+  case TCP_SYN_SENT:\r
+  case TCP_SYN_RCVD:\r
+    return 0;\r
+    break;\r
+\r
+  case TCP_ESTABLISHED:\r
+  case TCP_CLOSE_WAIT:\r
+    TcpToSendData (Tcb, 0);\r
+    return 0;\r
+    break;\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
+    break;\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Application has consumed some data, check whether\r
+  to send a window updata ack or a delayed ack.\r
+\r
+  @param  Tcb                   Pointer to the TCP_CB of this TCP instance.\r
+\r
+\r
+**/\r
+INTN\r
+TcpOnAppConsume (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+\r
+  switch (Tcb->State) {\r
+  case TCP_CLOSED:\r
+    return -1;\r
+    break;\r
+\r
+  case TCP_LISTEN:\r
+    return -1;\r
+    break;\r
+\r
+  case TCP_SYN_SENT:\r
+  case TCP_SYN_RCVD:\r
+    return 0;\r
+    break;\r
+\r
+  case TCP_ESTABLISHED:\r
+    if (TcpRcvWinNow (Tcb) > TcpRcvWinOld (Tcb)) {\r
+\r
+      if (TcpRcvWinOld (Tcb) < Tcb->RcvMss) {\r
+\r
+        TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"\r
+          " update for a window closed Tcb(%x)\n", Tcb));\r
+\r
+        TcpSendAck (Tcb);\r
+      } else if (Tcb->DelayedAck == 0) {\r
+\r
+        TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"\r
+          " ACK to update window for Tcb(%x)\n", Tcb));\r
+\r
+        Tcb->DelayedAck = 1;\r
+      }\r
+    }\r
+\r
+    break;\r
+\r
+  case TCP_CLOSE_WAIT:\r
+    return 0;\r
+    break;\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
+    break;\r
+  }\r
+\r
+  return -1;\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  Tcb                   Pointer to the TCP_CB of the TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpOnAppAbort (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "\r
+    "issued by application for TCB %x\n", Tcb));\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
+  }\r
+\r
+  TcpSetState (Tcb, TCP_CLOSED);\r
+}\r
+\r
+\r
+/**\r
+  Set the Tdp4 variable data.\r
+\r
+  @param  Tcp4Service           Tcp4 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 TCP4_SERVICE_DATA  *Tcp4Service\r
+  )\r
+{\r
+  UINT32                  NumConfiguredInstance;\r
+  NET_LIST_ENTRY          *Entry;\r
+  TCP_CB                  *TcpPcb;\r
+  TCP4_PROTO_DATA         *TcpProto;\r
+  UINTN                   VariableDataSize;\r
+  EFI_TCP4_VARIABLE_DATA  *Tcp4VariableData;\r
+  EFI_TCP4_SERVICE_POINT  *Tcp4ServicePoint;\r
+  CHAR16                  *NewMacString;\r
+  EFI_STATUS              Status;\r
+\r
+  NumConfiguredInstance = 0;\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 = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == Tcp4Service) {\r
+      //\r
+      // This tcp instance belongs to the Tcp4Service.\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 = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == Tcp4Service) {\r
+      //\r
+      // This tcp instance belongs to the Tcp4Service.\r
+      //\r
+      NumConfiguredInstance++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
+  // we should add extra buffer for the service points only if the number of configured\r
+  // children is more than 1.\r
+  //\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 = NetAllocatePool (VariableDataSize);\r
+  if (Tcp4VariableData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
+  Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
+\r
+  Tcp4ServicePoint = &Tcp4VariableData->Services[0];\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 = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == Tcp4Service) {\r
+      //\r
+      // This tcp instance belongs to the Tcp4Service.\r
+      //\r
+      Tcp4ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;\r
+      EFI_IP4 (Tcp4ServicePoint->LocalAddress)  = TcpPcb->LocalEnd.Ip;\r
+      Tcp4ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);\r
+      EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;\r
+      Tcp4ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+      Tcp4ServicePoint++;\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 = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+    if (TcpProto->TcpService == Tcp4Service) {\r
+      //\r
+      // This tcp instance belongs to the Tcp4Service.\r
+      //\r
+      Tcp4ServicePoint->InstanceHandle          = TcpPcb->Sk->SockHandle;\r
+      EFI_IP4 (Tcp4ServicePoint->LocalAddress)  = TcpPcb->LocalEnd.Ip;\r
+      Tcp4ServicePoint->LocalPort               = NTOHS (TcpPcb->LocalEnd.Port);\r
+      EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;\r
+      Tcp4ServicePoint->RemotePort              = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+      Tcp4ServicePoint++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get the mac string.\r
+  //\r
+  Status = NetLibGetMacString (\r
+             Tcp4Service->ControllerHandle,\r
+             Tcp4Service->DriverBindingHandle,\r
+             &NewMacString\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (Tcp4Service->MacString != NULL) {\r
+    //\r
+    // The variable is set already, we're going to update it.\r
+    //\r
+    if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
+      //\r
+      // The mac address is changed, delete the previous variable first.\r
+      //\r
+      gRT->SetVariable (\r
+             Tcp4Service->MacString,\r
+             &gEfiTcp4ServiceBindingProtocolGuid,\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             NULL\r
+             );\r
+    }\r
+\r
+    NetFreePool (Tcp4Service->MacString);\r
+  }\r
+\r
+  Tcp4Service->MacString = NewMacString;\r
+\r
+  Status = gRT->SetVariable (\r
+                  Tcp4Service->MacString,\r
+                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  VariableDataSize,\r
+                  (VOID *) Tcp4VariableData\r
+                  );\r
+\r
+ON_ERROR:\r
+\r
+  NetFreePool (Tcp4VariableData);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the variable and free the resource.\r
+\r
+  @param  Tcp4Service           Tcp4 service data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpClearVariableData (\r
+  IN TCP4_SERVICE_DATA  *Tcp4Service\r
+  )\r
+{\r
+  ASSERT (Tcp4Service->MacString != NULL);\r
+\r
+  gRT->SetVariable (\r
+         Tcp4Service->MacString,\r
+         &gEfiTcp4ServiceBindingProtocolGuid,\r
+         EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+         0,\r
+         NULL\r
+         );\r
+\r
+  NetFreePool (Tcp4Service->MacString);\r
+  Tcp4Service->MacString = NULL;\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.c
new file mode 100644 (file)
index 0000000..d430a2e
--- /dev/null
@@ -0,0 +1,380 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Option.c\r
+\r
+Abstract:\r
+\r
+  Routines to process TCP option.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+STATIC\r
+UINT16\r
+TcpGetUint16 (\r
+  IN UINT8 *Buf\r
+  )\r
+{\r
+  UINT16  Value;\r
+  NetCopyMem (&Value, Buf, sizeof (UINT16));\r
+  return NTOHS (Value);\r
+}\r
+\r
+STATIC\r
+VOID\r
+TcpPutUint16 (\r
+  IN UINT8  *Buf,\r
+  IN UINT16 Data\r
+  )\r
+{\r
+  Data = HTONS (Data);\r
+  NetCopyMem (Buf, &Data, sizeof (UINT16));\r
+}\r
+\r
+STATIC\r
+UINT32\r
+TcpGetUint32 (\r
+  IN UINT8 *Buf\r
+  )\r
+{\r
+  UINT32  Value;\r
+  NetCopyMem (&Value, Buf, sizeof (UINT32));\r
+  return NTOHL (Value);\r
+}\r
+\r
+STATIC\r
+VOID\r
+TcpPutUint32 (\r
+  IN UINT8  *Buf,\r
+  IN UINT32 Data\r
+  )\r
+{\r
+  Data = HTONL (Data);\r
+  NetCopyMem (Buf, &Data, sizeof (UINT32));\r
+}\r
+\r
+\r
+/**\r
+  Compute the window scale value according to the given\r
+  buffer size.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @retval UINT8   The scale value.\r
+\r
+**/\r
+UINT8\r
+TcpComputeScale (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  UINT8   Scale;\r
+  UINT32  BufSize;\r
+\r
+  ASSERT (Tcb && Tcb->Sk);\r
+\r
+  BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+\r
+  Scale   = 0;\r
+  while ((Scale < TCP_OPTION_MAX_WS) &&\r
+         ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {\r
+\r
+    Scale++;\r
+  }\r
+\r
+  return Scale;\r
+}\r
+\r
+\r
+/**\r
+  Build the TCP option in three-way handshake.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf    Pointer to the buffer to store the options.\r
+\r
+  @return The total length of the TCP option field.\r
+\r
+**/\r
+UINT16\r
+TcpSynBuildOption (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  char    *Data;\r
+  UINT16  Len;\r
+\r
+  ASSERT (Tcb && Nbuf && !Nbuf->Tcp);\r
+\r
+  Len = 0;\r
+\r
+  //\r
+  // Add timestamp option if not disabled by application\r
+  // and it is the first SYN segment or the peer has sent\r
+  // us its timestamp.\r
+  //\r
+  if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&\r
+      (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||\r
+      TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))) {\r
+\r
+    Data = NetbufAllocSpace (\r
+            Nbuf,\r
+            TCP_OPTION_TS_ALIGNED_LEN,\r
+            NET_BUF_HEAD\r
+            );\r
+\r
+    ASSERT (Data);\r
+    Len += TCP_OPTION_TS_ALIGNED_LEN;\r
+\r
+    TcpPutUint32 (Data, TCP_OPTION_TS_FAST);\r
+    TcpPutUint32 (Data + 4, mTcpTick);\r
+    TcpPutUint32 (Data + 8, 0);\r
+  }\r
+\r
+  //\r
+  // Build window scale option, only when are configured\r
+  // to send WS option, and either we are doing active\r
+  // open or we have received WS option from peer.\r
+  //\r
+  if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&\r
+      (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||\r
+      TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))) {\r
+\r
+    Data = NetbufAllocSpace (\r
+            Nbuf,\r
+            TCP_OPTION_WS_ALIGNED_LEN,\r
+            NET_BUF_HEAD\r
+            );\r
+\r
+    ASSERT (Data);\r
+\r
+    Len += TCP_OPTION_WS_ALIGNED_LEN;\r
+    TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));\r
+  }\r
+\r
+  //\r
+  // Build MSS option\r
+  //\r
+  Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);\r
+  ASSERT (Data);\r
+\r
+  Len += TCP_OPTION_MSS_LEN;\r
+  TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);\r
+\r
+  return Len;\r
+}\r
+\r
+\r
+/**\r
+  Build the TCP option in synchronized states.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf    Pointer to the buffer to store the options.\r
+\r
+  @return The total length of the TCP option field.\r
+\r
+**/\r
+UINT16\r
+TcpBuildOption (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  char    *Data;\r
+  UINT16  Len;\r
+\r
+  ASSERT (Tcb && Nbuf && !Nbuf->Tcp);\r
+  Len = 0;\r
+\r
+  //\r
+  // Build Timestamp option\r
+  //\r
+  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&\r
+      !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)) {\r
+\r
+    Data = NetbufAllocSpace (\r
+            Nbuf,\r
+            TCP_OPTION_TS_ALIGNED_LEN,\r
+            NET_BUF_HEAD\r
+            );\r
+\r
+    ASSERT (Data);\r
+    Len += TCP_OPTION_TS_ALIGNED_LEN;\r
+\r
+    TcpPutUint32 (Data, TCP_OPTION_TS_FAST);\r
+    TcpPutUint32 (Data + 4, mTcpTick);\r
+    TcpPutUint32 (Data + 8, Tcb->TsRecent);\r
+  }\r
+\r
+  return Len;\r
+}\r
+\r
+\r
+/**\r
+  Parse the supported options.\r
+\r
+  @param  Tcp     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Option  Pointer to the TCP_OPTION used to store the successfully pasrsed\r
+                  options.\r
+\r
+  @retval 0       The options are successfully pasrsed.\r
+  @retval -1      Ilegal option was found.\r
+\r
+**/\r
+INTN\r
+TcpParseOption (\r
+  IN TCP_HEAD   *Tcp,\r
+  IN TCP_OPTION *Option\r
+  )\r
+{\r
+  UINT8 *Head;\r
+  UINT8 TotalLen;\r
+  UINT8 Cur;\r
+  UINT8 Type;\r
+  UINT8 Len;\r
+\r
+  ASSERT (Tcp && Option);\r
+\r
+  Option->Flag  = 0;\r
+\r
+  TotalLen      = (Tcp->HeadLen << 2) - sizeof (TCP_HEAD);\r
+  if (TotalLen <= 0) {\r
+    return 0;\r
+  }\r
+\r
+  Head = (UINT8 *) (Tcp + 1);\r
+\r
+  //\r
+  // Fast process of timestamp option\r
+  //\r
+  if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) &&\r
+      (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {\r
+\r
+    Option->TSVal = TcpGetUint32 (Head + 4);\r
+    Option->TSEcr = TcpGetUint32 (Head + 8);\r
+    Option->Flag  = TCP_OPTION_RCVD_TS;\r
+\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Slow path to process the options.\r
+  //\r
+  Cur = 0;\r
+\r
+  while (Cur < TotalLen) {\r
+    Type = Head[Cur];\r
+\r
+    switch (Type) {\r
+    case TCP_OPTION_MSS:\r
+      Len = Head[Cur + 1];\r
+\r
+      if ((Len != TCP_OPTION_MSS_LEN) ||\r
+          (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {\r
+\r
+        return -1;\r
+      }\r
+\r
+      Option->Mss = TcpGetUint16 (&Head[Cur + 2]);\r
+      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);\r
+\r
+      Cur += TCP_OPTION_MSS_LEN;\r
+      break;\r
+\r
+    case TCP_OPTION_WS:\r
+      Len = Head[Cur + 1];\r
+\r
+      if ((Len != TCP_OPTION_WS_LEN) ||\r
+          (TotalLen - Cur < TCP_OPTION_WS_LEN)) {\r
+\r
+        return -1;\r
+      }\r
+\r
+      Option->WndScale = NET_MIN (14, Head[Cur + 2]);\r
+      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);\r
+\r
+      Cur += TCP_OPTION_WS_LEN;\r
+      break;\r
+\r
+    case TCP_OPTION_TS:\r
+      Len = Head[Cur + 1];\r
+\r
+      if ((Len != TCP_OPTION_TS_LEN) ||\r
+          (TotalLen - Cur < TCP_OPTION_TS_LEN)) {\r
+\r
+        return -1;\r
+      }\r
+\r
+      Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);\r
+      Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);\r
+      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);\r
+\r
+      Cur += TCP_OPTION_TS_LEN;\r
+      break;\r
+\r
+    case TCP_OPTION_NOP:\r
+      Cur++;\r
+      break;\r
+\r
+    case TCP_OPTION_EOP:\r
+      Cur = TotalLen;\r
+      break;\r
+\r
+    default:\r
+      Len = Head[Cur + 1];\r
+\r
+      if (TotalLen - Cur < Len || Len < 2) {\r
+        return -1;\r
+      }\r
+\r
+      Cur = Cur + Len;\r
+      break;\r
+    }\r
+\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Check the segment against PAWS.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  TSVal   The timestamp value.\r
+\r
+  @retval 1       The segment passed the PAWS check.\r
+  @retval 0       The segment failed to pass the PAWS check.\r
+\r
+**/\r
+UINT32\r
+TcpPawsOK (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT32 TSVal\r
+  )\r
+{\r
+  //\r
+  // PAWS as defined in RFC1323, buggy...\r
+  //\r
+  if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&\r
+      TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)) {\r
+\r
+    return 0;\r
+\r
+  }\r
+\r
+  return 1;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.h
new file mode 100644 (file)
index 0000000..8074cb5
--- /dev/null
@@ -0,0 +1,107 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Tcp4Option.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_OPTION_H_
+#define _TCP4_OPTION_H_
+
+//
+// The structure to store the parse option value.
+// ParseOption only parse the options, don't process them.
+//
+typedef struct s_TCP_OPTION {
+  UINT8   Flag;     // flag such as TCP_OPTION_RCVD_MSS
+  UINT8   WndScale; // the WndScale received
+  UINT16  Mss;      // the Mss received
+  UINT32  TSVal;    // the TSVal field in a timestamp option
+  UINT32  TSEcr;    // the TSEcr field in a timestamp option
+} TCP_OPTION;
+
+enum {
+
+  //
+  // supported TCP option type and their length
+  //
+  TCP_OPTION_EOP            = 0,  // End Of oPtion
+  TCP_OPTION_NOP            = 1,  // No-Option.
+  TCP_OPTION_MSS            = 2,  // Maximum Segment Size
+  TCP_OPTION_WS             = 3,  // Window scale
+  TCP_OPTION_TS             = 8,  // Timestamp
+  TCP_OPTION_MSS_LEN        = 4,  // length of MSS option
+  TCP_OPTION_WS_LEN         = 3,  // length of window scale option
+  TCP_OPTION_TS_LEN         = 10, // length of timestamp option
+  TCP_OPTION_WS_ALIGNED_LEN = 4,  // length of window scale option, aligned
+  TCP_OPTION_TS_ALIGNED_LEN = 12, // length of timestamp option, aligned
+
+  //
+  // recommend format of timestamp window scale
+  // option for fast process.
+  //
+  TCP_OPTION_TS_FAST = ((TCP_OPTION_NOP << 24) |
+                        (TCP_OPTION_NOP << 16) |
+                        (TCP_OPTION_TS << 8) |
+                        TCP_OPTION_TS_LEN),
+
+  TCP_OPTION_WS_FAST = ((TCP_OPTION_NOP << 24) |
+                        (TCP_OPTION_WS << 16) |
+                        (TCP_OPTION_WS_LEN << 8)),
+
+  TCP_OPTION_MSS_FAST = ((TCP_OPTION_MSS << 24) |
+                         (TCP_OPTION_MSS_LEN << 16)),
+
+  //
+  // Other misc definations
+  //
+  TCP_OPTION_MAX_WS         = 14,     // Maxium window scale value
+  TCP_OPTION_MAX_WIN        = 0xffff, // max window size in TCP header
+  TCP_OPTION_RCVD_MSS       = 0x01,
+  TCP_OPTION_RCVD_WS        = 0x02,
+  TCP_OPTION_RCVD_TS        = 0x04,
+};
+
+UINT8
+TcpComputeScale (
+  IN TCP_CB *Tcb
+  );
+
+UINT16
+TcpSynBuildOption (
+  IN TCP_CB  *Tcb,
+  IN NET_BUF *Buf
+  );
+
+UINT16
+TcpBuildOption (
+  IN TCP_CB  *Tcb,
+  IN NET_BUF *Buf
+  );
+
+INTN
+TcpParseOption (
+  IN TCP_HEAD   *Tcp,
+  IN TCP_OPTION *Option
+  );
+
+UINT32
+TcpPawsOK (
+  IN TCP_CB *Tcb,
+  IN UINT32 TSVal
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c
new file mode 100644 (file)
index 0000000..f2987e7
--- /dev/null
@@ -0,0 +1,1218 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Output.c\r
+\r
+Abstract:\r
+\r
+  TCP output process routines.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+STATIC UINT8  mTcpOutFlag[] = {\r
+  0,                          // TCP_CLOSED\r
+  0,                          // TCP_LISTEN\r
+  TCP_FLG_SYN,                // TCP_SYN_SENT\r
+  TCP_FLG_SYN | TCP_FLG_ACK,  // TCP_SYN_RCVD\r
+  TCP_FLG_ACK,                // TCP_ESTABLISHED\r
+  TCP_FLG_FIN | TCP_FLG_ACK,  // TCP_FIN_WAIT_1\r
+  TCP_FLG_ACK,                // TCP_FIN_WAIT_2\r
+  TCP_FLG_ACK | TCP_FLG_FIN,  // TCP_CLOSING\r
+  TCP_FLG_ACK,                // TCP_TIME_WAIT\r
+  TCP_FLG_ACK,                // TCP_CLOSE_WAIT\r
+  TCP_FLG_FIN | TCP_FLG_ACK   // TCP_LAST_ACK\r
+};\r
+\r
+\r
+/**\r
+  Compute the sequence space left in the old receive window.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return The sequence space left in the old receive window.\r
+\r
+**/\r
+UINT32\r
+TcpRcvWinOld (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  UINT32  OldWin;\r
+\r
+  OldWin = 0;\r
+\r
+  if (TCP_SEQ_GT (Tcb->RcvWl2 + Tcb->RcvWnd, Tcb->RcvNxt)) {\r
+\r
+    OldWin = TCP_SUB_SEQ (\r
+              Tcb->RcvWl2 + Tcb->RcvWnd,\r
+              Tcb->RcvNxt\r
+              );\r
+  }\r
+\r
+  return OldWin;\r
+}\r
+\r
+\r
+/**\r
+  Compute the current receive window.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return The size of the current receive window, in bytes.\r
+\r
+**/\r
+UINT32\r
+TcpRcvWinNow (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  SOCKET  *Sk;\r
+  UINT32  Win;\r
+  UINT32  Increase;\r
+  UINT32  OldWin;\r
+\r
+  Sk = Tcb->Sk;\r
+  ASSERT (Sk);\r
+\r
+  OldWin    = TcpRcvWinOld (Tcb);\r
+\r
+  Win       = SockGetFreeSpace (Sk, SOCK_RCV_BUF);\r
+\r
+  Increase  = 0;\r
+  if (Win > OldWin) {\r
+    Increase = Win - OldWin;\r
+  }\r
+\r
+  //\r
+  // Receiver's SWS: don't advertise a bigger window\r
+  // unless it can be increased by at least one Mss or\r
+  // half of the receive buffer.\r
+  //\r
+  if ((Increase > Tcb->SndMss) ||\r
+      (2 * Increase >= GET_RCV_BUFFSIZE (Sk))) {\r
+\r
+    return Win;\r
+  }\r
+\r
+  return OldWin;\r
+}\r
+\r
+\r
+/**\r
+  Compute the value to fill in the window size field\r
+  of the outgoing segment.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Syn     The flag to indicate whether the outgoing segment is a SYN\r
+                  segment.\r
+\r
+  @return The value of the local receive window size used to fill the outing segment.\r
+\r
+**/\r
+STATIC\r
+UINT16\r
+TcpComputeWnd (\r
+  IN TCP_CB  *Tcb,\r
+  IN BOOLEAN Syn\r
+  )\r
+{\r
+  UINT32  Wnd;\r
+\r
+  //\r
+  // RFC requires that initial window not be scaled\r
+  //\r
+  if (Syn) {\r
+\r
+    Wnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+  } else {\r
+\r
+    Wnd         = TcpRcvWinNow (Tcb);\r
+\r
+    Tcb->RcvWnd = Wnd;\r
+  }\r
+\r
+  Wnd = NET_MIN (Wnd >> Tcb->RcvWndScale, 0xffff);\r
+  return NTOHS ((UINT16) Wnd);\r
+}\r
+\r
+\r
+/**\r
+  Get the maximum SndNxt.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return The sequence number of the maximum SndNxt.\r
+\r
+**/\r
+TCP_SEQNO\r
+TcpGetMaxSndNxt (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *Entry;\r
+  NET_BUF         *Nbuf;\r
+\r
+  if (NetListIsEmpty (&Tcb->SndQue)) {\r
+    return Tcb->SndNxt;\r
+  }\r
+\r
+  Entry = Tcb->SndQue.BackLink;\r
+  Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+  ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf)->End, Tcb->SndNxt));\r
+  return TCPSEG_NETBUF (Nbuf)->End;\r
+}\r
+\r
+\r
+/**\r
+  Compute how much data to send.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Force   Whether to ignore the sender's SWS avoidance algorithm and send\r
+                  out data by force.\r
+\r
+  @return The length of the data can be sent, if 0, no data can be sent.\r
+\r
+**/\r
+UINT32\r
+TcpDataToSend (\r
+  IN TCP_CB *Tcb,\r
+  IN INTN   Force\r
+  )\r
+{\r
+  SOCKET  *Sk;\r
+  UINT32  Win;\r
+  UINT32  Len;\r
+  UINT32  Left;\r
+  UINT32  Limit;\r
+\r
+  Sk = Tcb->Sk;\r
+  ASSERT (Sk);\r
+\r
+  //\r
+  // TCP should NOT send data beyond the send window\r
+  // and congestion window. The right edge of send\r
+  // window is defined as SND.WL2 + SND.WND. The right\r
+  // edge of congestion window is defined as SND.UNA +\r
+  // CWND.\r
+  //\r
+  Win   = 0;\r
+  Limit = Tcb->SndWl2 + Tcb->SndWnd;\r
+\r
+  if (TCP_SEQ_GT (Limit, Tcb->SndUna + Tcb->CWnd)) {\r
+\r
+    Limit = Tcb->SndUna + Tcb->CWnd;\r
+  }\r
+\r
+  if (TCP_SEQ_GT (Limit, Tcb->SndNxt)) {\r
+    Win = TCP_SUB_SEQ (Limit, Tcb->SndNxt);\r
+  }\r
+\r
+  //\r
+  // The data to send contains two parts: the data on the\r
+  // socket send queue, and the data on the TCB's send\r
+  // buffer. The later can be non-zero if the peer shrinks\r
+  // its advertised window.\r
+  //\r
+  Left  = GET_SND_DATASIZE (Sk) +\r
+          TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb), Tcb->SndNxt);\r
+\r
+  Len   = NET_MIN (Win, Left);\r
+\r
+  if (Len > Tcb->SndMss) {\r
+    Len = Tcb->SndMss;\r
+  }\r
+\r
+  if (Force || (Len == 0 && Left == 0)) {\r
+    return Len;\r
+  }\r
+\r
+  if (Len == 0 && Left != 0) {\r
+    goto SetPersistTimer;\r
+  }\r
+\r
+  //\r
+  // Sender's SWS avoidance: Don't send a small segment unless\r
+  // a)A full-sized segment can be sent,\r
+  // b)at least one-half of the maximum sized windows that\r
+  // the other end has ever advertised.\r
+  // c)It can send everything it has and either it isn't\r
+  // expecting an ACK or the Nagle algorithm is disabled.\r
+  //\r
+  if ((Len == Tcb->SndMss) || (2 * Len >= Tcb->SndWndMax)) {\r
+\r
+    return Len;\r
+  }\r
+\r
+  if ((Len == Left) &&\r
+      ((Tcb->SndNxt == Tcb->SndUna) ||\r
+      TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE))) {\r
+\r
+    return Len;\r
+  }\r
+\r
+  //\r
+  // RFC1122 suggests to set a timer when SWSA forbids TCP\r
+  // sending more data, and combine it with probe timer.\r
+  //\r
+SetPersistTimer:\r
+  if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {\r
+\r
+    TCP4_DEBUG_WARN (\r
+      ("TcpDataToSend: enter persistent state for TCB %x\n",\r
+      Tcb)\r
+      );\r
+\r
+    TcpSetProbeTimer (Tcb);\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Build the TCP header of the TCP segment and transmit the\r
+  segment by IP.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf    Pointer to the buffer containing the segment to be sent out.\r
+\r
+  @retval 0       The segment is sent out successfully.\r
+  @retval other   Error condition occurred.\r
+\r
+**/\r
+STATIC\r
+INTN\r
+TcpTransmitSegment (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  UINT16    Len;\r
+  TCP_HEAD  *Head;\r
+  TCP_SEG   *Seg;\r
+  BOOLEAN   Syn;\r
+  UINT32    DataLen;\r
+\r
+  ASSERT (Nbuf && (Nbuf->Tcp == NULL) && TcpVerifySegment (Nbuf));\r
+\r
+  DataLen = Nbuf->TotalSize;\r
+\r
+  Seg     = TCPSEG_NETBUF (Nbuf);\r
+  Syn     = TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN);\r
+\r
+  if (Syn) {\r
+\r
+    Len = TcpSynBuildOption (Tcb, Nbuf);\r
+  } else {\r
+\r
+    Len = TcpBuildOption (Tcb, Nbuf);\r
+  }\r
+\r
+  ASSERT ((Len % 4 == 0) && (Len <= 40));\r
+\r
+  Len += sizeof (TCP_HEAD);\r
+\r
+  Head = (TCP_HEAD *) NetbufAllocSpace (\r
+                        Nbuf,\r
+                        sizeof (TCP_HEAD),\r
+                        NET_BUF_HEAD\r
+                        );\r
+\r
+  ASSERT (Head != NULL);\r
+\r
+  Nbuf->Tcp       = Head;\r
+\r
+  Head->SrcPort   = Tcb->LocalEnd.Port;\r
+  Head->DstPort   = Tcb->RemoteEnd.Port;\r
+  Head->Seq       = NTOHL (Seg->Seq);\r
+  Head->Ack       = NTOHL (Tcb->RcvNxt);\r
+  Head->HeadLen   = (UINT8) (Len >> 2);\r
+  Head->Res       = 0;\r
+  Head->Wnd       = TcpComputeWnd (Tcb, Syn);\r
+  Head->Checksum  = 0;\r
+\r
+  //\r
+  // Check whether to set the PSH flag.\r
+  //\r
+  TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_PSH);\r
+\r
+  if (DataLen != 0) {\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_PSH) &&\r
+        TCP_SEQ_BETWEEN (Seg->Seq, Tcb->SndPsh, Seg->End)) {\r
+\r
+      TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);\r
+      TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);\r
+\r
+    } else if ((Seg->End == Tcb->SndNxt) &&\r
+               (GET_SND_DATASIZE (Tcb->Sk) == 0)) {\r
+\r
+      TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check whether to set the URG flag and the urgent pointer.\r
+  //\r
+  TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
+\r
+  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
+      TCP_SEQ_LEQ (Seg->Seq, Tcb->SndUp)) {\r
+\r
+    TCP_SET_FLG (Seg->Flag, TCP_FLG_URG);\r
+\r
+    if (TCP_SEQ_LT (Tcb->SndUp, Seg->End)) {\r
+\r
+      Seg->Urg = (UINT16) TCP_SUB_SEQ (Tcb->SndUp, Seg->Seq);\r
+    } else {\r
+\r
+      Seg->Urg = (UINT16) NET_MIN (\r
+                            TCP_SUB_SEQ (Tcb->SndUp,\r
+                            Seg->Seq),\r
+                            0xffff\r
+                            );\r
+    }\r
+  }\r
+\r
+  Head->Flag      = Seg->Flag;\r
+  Head->Urg       = NTOHS (Seg->Urg);\r
+  Head->Checksum  = TcpChecksum (Nbuf, Tcb->HeadSum);\r
+\r
+  //\r
+  // update the TCP session's control information\r
+  //\r
+  Tcb->RcvWl2 = Tcb->RcvNxt;\r
+  if (Syn) {\r
+    Tcb->RcvWnd = NTOHS (Head->Wnd);\r
+  }\r
+\r
+  //\r
+  // clear delayedack flag\r
+  //\r
+  Tcb->DelayedAck = 0;\r
+\r
+  return TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);\r
+}\r
+\r
+\r
+/**\r
+  Get a segment from the Tcb's SndQue.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seq     The sequence number of the segment.\r
+  @param  Len     The maximum length of the segment.\r
+\r
+  @return Pointer to the segment, if NULL some error occurred.\r
+\r
+**/\r
+NET_BUF *\r
+TcpGetSegmentSndQue (\r
+  IN TCP_CB    *Tcb,\r
+  IN TCP_SEQNO Seq,\r
+  IN UINT32    Len\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *Head;\r
+  NET_LIST_ENTRY  *Cur;\r
+  NET_BUF         *Node;\r
+  TCP_SEG         *Seg;\r
+  NET_BUF         *Nbuf;\r
+  TCP_SEQNO       End;\r
+  UINT8           *Data;\r
+  UINT8           Flag;\r
+  INT32           Offset;\r
+  INT32           CopyLen;\r
+\r
+  ASSERT (Tcb && TCP_SEQ_LEQ (Seq, Tcb->SndNxt) && (Len > 0));\r
+\r
+  //\r
+  // Find the segment that contains the Seq.\r
+  //\r
+  Head  = &Tcb->SndQue;\r
+\r
+  Node  = NULL;\r
+  Seg   = NULL;\r
+\r
+  NET_LIST_FOR_EACH (Cur, Head) {\r
+    Node  = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+    Seg   = TCPSEG_NETBUF (Node);\r
+\r
+    if (TCP_SEQ_LT (Seq, Seg->End) && TCP_SEQ_LEQ (Seg->Seq, Seq)) {\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  ASSERT (Cur != Head);\r
+\r
+  //\r
+  // Return the buffer if it can be returned without\r
+  // adjustment:\r
+  //\r
+  if ((Seg->Seq == Seq) &&\r
+      TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) &&\r
+      !NET_BUF_SHARED (Node)) {\r
+\r
+    NET_GET_REF (Node);\r
+    return Node;\r
+  }\r
+\r
+  //\r
+  // Create a new buffer and copy data there.\r
+  //\r
+  Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);\r
+\r
+  if (Nbuf == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+  Flag  = Seg->Flag;\r
+  End   = Seg->End;\r
+\r
+  if (TCP_SEQ_LT (Seq + Len, Seg->End)) {\r
+    End = Seq + Len;\r
+  }\r
+\r
+  CopyLen = TCP_SUB_SEQ (End, Seq);\r
+  Offset  = TCP_SUB_SEQ (Seq, Seg->Seq);\r
+\r
+  //\r
+  // If SYN is set and out of the range, clear the flag.\r
+  // Becuase the sequence of the first byte is SEG.SEQ+1,\r
+  // adjust Offset by -1. If SYN is in the range, copy\r
+  // one byte less.\r
+  //\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+\r
+    if (TCP_SEQ_LT (Seg->Seq, Seq)) {\r
+\r
+      TCP_CLEAR_FLG (Flag, TCP_FLG_SYN);\r
+      Offset--;\r
+    } else {\r
+\r
+      CopyLen--;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If FIN is set and in the range, copy one byte less,\r
+  // and if it is out of the range, clear the flag.\r
+  //\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+\r
+    if (Seg->End == End) {\r
+\r
+      CopyLen--;\r
+    } else {\r
+\r
+      TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);\r
+    }\r
+  }\r
+\r
+  ASSERT (CopyLen >= 0);\r
+\r
+  //\r
+  // copy data to the segment\r
+  //\r
+  if (CopyLen) {\r
+    Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL);\r
+    ASSERT (Data);\r
+\r
+    if ((INT32) NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) {\r
+      goto OnError;\r
+    }\r
+  }\r
+\r
+  NetCopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG));\r
+\r
+  TCPSEG_NETBUF (Nbuf)->Seq   = Seq;\r
+  TCPSEG_NETBUF (Nbuf)->End   = End;\r
+  TCPSEG_NETBUF (Nbuf)->Flag  = Flag;\r
+\r
+  return Nbuf;\r
+\r
+OnError:\r
+  NetbufFree (Nbuf);\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Get a segment from the Tcb's socket buffer.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seq     The sequence number of the segment.\r
+  @param  Len     The maximum length of the segment.\r
+\r
+  @return Pointer to the segment, if NULL some error occurred.\r
+\r
+**/\r
+NET_BUF *\r
+TcpGetSegmentSock (\r
+  IN TCP_CB    *Tcb,\r
+  IN TCP_SEQNO Seq,\r
+  IN UINT32    Len\r
+  )\r
+{\r
+  NET_BUF *Nbuf;\r
+  UINT8   *Data;\r
+  UINT32  DataGet;\r
+\r
+  ASSERT (Tcb && Tcb->Sk);\r
+\r
+  Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);\r
+\r
+  if (Nbuf == NULL) {\r
+    TCP4_DEBUG_ERROR (("TcpGetSegmentSock: failed to allocate "\r
+      "a netbuf for TCB %x\n",Tcb));\r
+\r
+    return NULL;\r
+  }\r
+\r
+  NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+  DataGet = 0;\r
+\r
+  if (Len) {\r
+    //\r
+    // copy data to the segment.\r
+    //\r
+    Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL);\r
+    ASSERT (Data);\r
+\r
+    DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data);\r
+  }\r
+\r
+  NET_GET_REF (Nbuf);\r
+\r
+  TCPSEG_NETBUF (Nbuf)->Seq = Seq;\r
+  TCPSEG_NETBUF (Nbuf)->End = Seq + Len;\r
+\r
+  NetListInsertTail (&(Tcb->SndQue), &(Nbuf->List));\r
+\r
+  if (DataGet != 0) {\r
+\r
+    SockDataSent (Tcb->Sk, DataGet);\r
+  }\r
+\r
+  return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+  Get a segment starting from sequence Seq of a maximum\r
+  length of Len.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seq     The sequence number of the segment.\r
+  @param  Len     The maximum length of the segment.\r
+\r
+  @return Pointer to the segment, if NULL some error occurred.\r
+\r
+**/\r
+NET_BUF *\r
+TcpGetSegment (\r
+  IN TCP_CB    *Tcb,\r
+  IN TCP_SEQNO Seq,\r
+  IN UINT32    Len\r
+  )\r
+{\r
+  NET_BUF *Nbuf;\r
+\r
+  ASSERT (Tcb);\r
+\r
+  //\r
+  // Compare the SndNxt with the max sequence number sent.\r
+  //\r
+  if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) {\r
+\r
+    Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);\r
+  } else {\r
+\r
+    Nbuf = TcpGetSegmentSock (Tcb, Seq, Len);\r
+  }\r
+\r
+  ASSERT (TcpVerifySegment (Nbuf));\r
+  return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+  Retransmit the segment from sequence Seq.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Seq     The sequence number of the segment to be retransmitted.\r
+\r
+  @retval 0       Retransmission succeeded.\r
+  @retval -1      Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpRetransmit (\r
+  IN TCP_CB    *Tcb,\r
+  IN TCP_SEQNO Seq\r
+  )\r
+{\r
+  NET_BUF *Nbuf;\r
+  UINT32  Len;\r
+\r
+  //\r
+  // Compute the maxium length of retransmission. It is\r
+  // limited by three factors:\r
+  // 1. Less than SndMss\r
+  // 2. must in the current send window\r
+  // 3. will not change the boundaries of queued segments.\r
+  //\r
+  if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {\r
+    TCP4_DEBUG_WARN (("TcpRetransmit: retransmission cancelled "\r
+      "because send window too small for TCB %x\n", Tcb));\r
+\r
+    return 0;\r
+  }\r
+\r
+  Len   = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);\r
+  Len   = NET_MIN (Len, Tcb->SndMss);\r
+\r
+  Nbuf  = TcpGetSegmentSndQue (Tcb, Seq, Len);\r
+  if (Nbuf == NULL) {\r
+    return -1;\r
+  }\r
+\r
+  ASSERT (TcpVerifySegment (Nbuf));\r
+\r
+  if (TcpTransmitSegment (Tcb, Nbuf) != 0) {\r
+    goto OnError;\r
+  }\r
+\r
+  //\r
+  // The retransmitted buffer may be on the SndQue,\r
+  // trim TCP head because all the buffer on SndQue\r
+  // are headless.\r
+  //\r
+  ASSERT (Nbuf->Tcp);\r
+  NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
+  Nbuf->Tcp = NULL;\r
+\r
+  NetbufFree (Nbuf);\r
+  return 0;\r
+\r
+OnError:\r
+  if (Nbuf != NULL) {\r
+    NetbufFree (Nbuf);\r
+  }\r
+\r
+  return -1;\r
+}\r
+\r
+\r
+/**\r
+  Check whether to send data/SYN/FIN and piggy back an ACK.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Force   Whether to ignore the sender's SWS avoidance algorithm and send\r
+                  out data by force.\r
+\r
+  @return The number of bytes sent.\r
+\r
+**/\r
+INTN\r
+TcpToSendData (\r
+  IN TCP_CB *Tcb,\r
+  IN INTN Force\r
+  )\r
+{\r
+  UINT32    Len;\r
+  INTN      Sent;\r
+  UINT8     Flag;\r
+  NET_BUF   *Nbuf;\r
+  TCP_SEG   *Seg;\r
+  TCP_SEQNO Seq;\r
+  TCP_SEQNO End;\r
+\r
+  ASSERT (Tcb && Tcb->Sk && (Tcb->State != TCP_LISTEN));\r
+\r
+  Sent = 0;\r
+\r
+  if ((Tcb->State == TCP_CLOSED) ||\r
+      TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {\r
+\r
+    return 0;\r
+  }\r
+\r
+SEND_AGAIN:\r
+  //\r
+  // compute how much data can be sent\r
+  //\r
+  Len   = TcpDataToSend (Tcb, Force);\r
+  Seq   = Tcb->SndNxt;\r
+\r
+  Flag  = mTcpOutFlag[Tcb->State];\r
+\r
+  if (Flag & TCP_FLG_SYN) {\r
+\r
+    Seq = Tcb->Iss;\r
+    Len = 0;\r
+  }\r
+\r
+  //\r
+  // only send a segment without data if SYN or\r
+  // FIN is set.\r
+  //\r
+  if ((Len == 0) && !(Flag & (TCP_FLG_SYN | TCP_FLG_FIN))) {\r
+    return Sent;\r
+  }\r
+\r
+  Nbuf = TcpGetSegment (Tcb, Seq, Len);\r
+\r
+  if (Nbuf == NULL) {\r
+    TCP4_DEBUG_ERROR (\r
+      ("TcpToSendData: failed to get a segment for TCB %x\n",\r
+      Tcb)\r
+      );\r
+\r
+    goto OnError;\r
+  }\r
+\r
+  Seg = TCPSEG_NETBUF (Nbuf);\r
+\r
+  //\r
+  // Set the TcpSeg in Nbuf.\r
+  //\r
+  Len = Nbuf->TotalSize;\r
+  End = Seq + Len;\r
+  if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {\r
+    End++;\r
+  }\r
+\r
+  if (Flag & TCP_FLG_FIN) {\r
+    //\r
+    // Send FIN if all data is sent, and FIN is\r
+    // in the window\r
+    //\r
+    if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&\r
+        (GET_SND_DATASIZE (Tcb->Sk) == 0) &&\r
+        TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)\r
+          ) {\r
+\r
+      TCP4_DEBUG_TRACE (("TcpToSendData: send FIN "\r
+        "to peer for TCB %x in state %d\n", Tcb, Tcb->State));\r
+\r
+      End++;\r
+    } else {\r
+      TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);\r
+    }\r
+  }\r
+\r
+  Seg->Seq  = Seq;\r
+  Seg->End  = End;\r
+  Seg->Flag = Flag;\r
+\r
+  ASSERT (TcpVerifySegment (Nbuf));\r
+  ASSERT (TcpCheckSndQue (&Tcb->SndQue));\r
+\r
+  //\r
+  // don't send an empty segment here.\r
+  //\r
+  if (Seg->End == Seg->Seq) {\r
+    TCP4_DEBUG_WARN (("TcpToSendData: created a empty"\r
+      " segment for TCB %x, free it now\n", Tcb));\r
+\r
+    NetbufFree (Nbuf);\r
+    return Sent;\r
+  }\r
+\r
+  if (TcpTransmitSegment (Tcb, Nbuf) != 0) {\r
+    //\r
+    // TODO: double check this\r
+    //\r
+    NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
+    Nbuf->Tcp = NULL;\r
+\r
+    if (Flag & TCP_FLG_FIN) {\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);\r
+    }\r
+\r
+    goto OnError;\r
+  }\r
+\r
+  Sent += TCP_SUB_SEQ (End, Seq);\r
+\r
+  //\r
+  // All the buffer in the SndQue is headless\r
+  //\r
+  ASSERT (Nbuf->Tcp);\r
+\r
+  NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
+  Nbuf->Tcp = NULL;\r
+\r
+  NetbufFree (Nbuf);\r
+\r
+  //\r
+  // update status in TCB\r
+  //\r
+  Tcb->DelayedAck = 0;\r
+\r
+  if (Flag & TCP_FLG_FIN) {\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);\r
+  }\r
+\r
+  if (TCP_SEQ_GT (End, Tcb->SndNxt)) {\r
+    Tcb->SndNxt = End;\r
+  }\r
+\r
+  if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {\r
+    TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
+  }\r
+\r
+  //\r
+  // Enable RTT measurement only if not in retransmit.\r
+  // Karn's algorithm reqires not to update RTT when in loss.\r
+  //\r
+  if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
+      !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+\r
+    TCP4_DEBUG_TRACE (("TcpToSendData: set RTT measure "\r
+      "sequence %d for TCB %x\n", Seq, Tcb));\r
+\r
+    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+    Tcb->RttSeq     = Seq;\r
+    Tcb->RttMeasure = 0;\r
+  }\r
+\r
+  if (Len == Tcb->SndMss) {\r
+    goto SEND_AGAIN;\r
+  }\r
+\r
+  return Sent;\r
+\r
+OnError:\r
+  if (Nbuf != NULL) {\r
+    NetbufFree (Nbuf);\r
+  }\r
+\r
+  return Sent;\r
+}\r
+\r
+\r
+/**\r
+  Send an ACK immediately.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpSendAck (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NET_BUF *Nbuf;\r
+  TCP_SEG *Seg;\r
+\r
+  Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+  if (Nbuf == NULL) {\r
+    return;\r
+  }\r
+\r
+  NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+  Seg       = TCPSEG_NETBUF (Nbuf);\r
+  Seg->Seq  = Tcb->SndNxt;\r
+  Seg->End  = Tcb->SndNxt;\r
+  Seg->Flag = TCP_FLG_ACK;\r
+\r
+  if (TcpTransmitSegment (Tcb, Nbuf) == 0) {\r
+    TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+    Tcb->DelayedAck = 0;\r
+  }\r
+\r
+  NetbufFree (Nbuf);\r
+}\r
+\r
+\r
+/**\r
+  Send a zero probe segment. It can be used by keepalive\r
+  and zero window probe.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @retval 0       The zero probe segment was sent out successfully.\r
+  @retval other   Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpSendZeroProbe (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NET_BUF *Nbuf;\r
+  TCP_SEG *Seg;\r
+  INTN     Result;\r
+\r
+  Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+  if (Nbuf == NULL) {\r
+    return -1;\r
+  }\r
+\r
+  NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+  //\r
+  // SndNxt-1 is out of window. The peer should respond\r
+  // with an ACK.\r
+  //\r
+  Seg       = TCPSEG_NETBUF (Nbuf);\r
+  Seg->Seq  = Tcb->SndNxt - 1;\r
+  Seg->End  = Tcb->SndNxt - 1;\r
+  Seg->Flag = TCP_FLG_ACK;\r
+\r
+  Result    = TcpTransmitSegment (Tcb, Nbuf);\r
+  NetbufFree (Nbuf);\r
+\r
+  return Result;\r
+}\r
+\r
+\r
+/**\r
+  Check whether to send an ACK or delayed ACK.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpToSendAck (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  //\r
+  // Generally, TCP should send a delayed ACK unless:\r
+  //   1. ACK at least every other FULL sized segment received,\r
+  //   2. Packets received out of order\r
+  //   3. Receiving window is open\r
+  //\r
+  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) ||\r
+      (Tcb->DelayedAck >= 1) ||\r
+      (TcpRcvWinNow (Tcb) > TcpRcvWinOld (Tcb))\r
+      ) {\r
+    TcpSendAck (Tcb);\r
+    return;\r
+  }\r
+\r
+  TCP4_DEBUG_TRACE (("TcpToSendAck: scheduled a delayed"\r
+    " ACK for TCB %x\n", Tcb));\r
+\r
+  //\r
+  // schedule a delayed ACK\r
+  //\r
+  Tcb->DelayedAck++;\r
+}\r
+\r
+\r
+/**\r
+  Send a RESET segment in response to the segment received.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance, may be NULL.\r
+  @param  Head    TCP header of the segment that triggers the reset.\r
+  @param  Len     Length of the segment that triggers the reset.\r
+  @param  Local   Local IP address.\r
+  @param  Remote  Remote peer's IP address.\r
+\r
+  @retval 0       A reset is sent or no need to send it.\r
+  @retval -1      No reset is sent.\r
+\r
+**/\r
+INTN\r
+TcpSendReset (\r
+  IN TCP_CB    *Tcb,\r
+  IN TCP_HEAD  *Head,\r
+  IN INT32     Len,\r
+  IN UINT32    Local,\r
+  IN UINT32    Remote\r
+  )\r
+{\r
+  NET_BUF   *Nbuf;\r
+  TCP_HEAD  *Nhead;\r
+  UINT16    HeadSum;\r
+\r
+  //\r
+  // Don't respond to a Reset with reset\r
+  //\r
+  if (Head->Flag & TCP_FLG_RST) {\r
+    return 0;\r
+  }\r
+\r
+  Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+  if (Nbuf == NULL) {\r
+    return -1;\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
+  Nhead->Flag = TCP_FLG_RST;\r
+\r
+  //\r
+  // Derive Seq/ACK from the segment if no TCB\r
+  // associated with it, otherwise from the Tcb\r
+  //\r
+  if (Tcb == NULL) {\r
+\r
+    if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {\r
+      Nhead->Seq  = Head->Ack;\r
+      Nhead->Ack  = 0;\r
+    } else {\r
+      Nhead->Seq = 0;\r
+      TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);\r
+      Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);\r
+    }\r
+  } else {\r
+\r
+    Nhead->Seq  = HTONL (Tcb->SndNxt);\r
+    Nhead->Ack  = HTONL (Tcb->RcvNxt);\r
+    TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);\r
+  }\r
+\r
+  Nhead->SrcPort  = Head->DstPort;\r
+  Nhead->DstPort  = Head->SrcPort;\r
+  Nhead->HeadLen  = (sizeof (TCP_HEAD) >> 2);\r
+  Nhead->Res      = 0;\r
+  Nhead->Wnd      = HTONS (0xFFFF);\r
+  Nhead->Checksum = 0;\r
+  Nhead->Urg      = 0;\r
+\r
+  HeadSum         = NetPseudoHeadChecksum (Local, Remote, 6, 0);\r
+  Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);\r
+\r
+  TcpSendIpPacket (Tcb, Nbuf, Local, Remote);\r
+\r
+  NetbufFree (Nbuf);\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Verify that the segment is in good shape.\r
+\r
+  @param  Nbuf    Buffer that contains the segment to be checked.\r
+\r
+  @retval 0       The segment is broken.\r
+  @retval 1       The segment is in good shape.\r
+\r
+**/\r
+INTN\r
+TcpVerifySegment (\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  TCP_HEAD  *Head;\r
+  TCP_SEG   *Seg;\r
+  UINT32    Len;\r
+\r
+  if (Nbuf == NULL) {\r
+    return 1;\r
+  }\r
+\r
+  NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
+\r
+  Seg   = TCPSEG_NETBUF (Nbuf);\r
+  Len   = Nbuf->TotalSize;\r
+  Head  = Nbuf->Tcp;\r
+\r
+  if (Head != NULL) {\r
+    if (Head->Flag != Seg->Flag) {\r
+      return 0;\r
+    }\r
+\r
+    Len -= (Head->HeadLen << 2);\r
+  }\r
+\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+    Len++;\r
+  }\r
+\r
+  if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+    Len++;\r
+  }\r
+\r
+  if (Seg->Seq + Len != Seg->End) {\r
+    return 0;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+\r
+/**\r
+  Verify that all the segments in SndQue are in good shape.\r
+\r
+  @param  Head    Pointer to the head node of the SndQue.\r
+\r
+  @retval 0       At least one segment is broken.\r
+  @retval 1       All segments in the specific queue are in good shape.\r
+\r
+**/\r
+INTN\r
+TcpCheckSndQue (\r
+  IN NET_LIST_ENTRY *Head\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *Entry;\r
+  NET_BUF         *Nbuf;\r
+  TCP_SEQNO       Seq;\r
+\r
+  if (NetListIsEmpty (Head)) {\r
+    return 1;\r
+  }\r
+  //\r
+  // Initialize the Seq\r
+  //\r
+  Entry = Head->ForwardLink;\r
+  Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+  Seq   = TCPSEG_NETBUF (Nbuf)->Seq;\r
+\r
+  NET_LIST_FOR_EACH (Entry, Head) {\r
+    Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+    if (TcpVerifySegment (Nbuf) == 0) {\r
+      return 0;\r
+    }\r
+\r
+    //\r
+    // All the node in the SndQue should has:\r
+    // SEG.SEQ = LAST_SEG.END\r
+    //\r
+    if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {\r
+      return 0;\r
+    }\r
+\r
+    Seq = TCPSEG_NETBUF (Nbuf)->End;\r
+  }\r
+\r
+  return 1;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Proto.h b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Proto.h
new file mode 100644 (file)
index 0000000..03daa6f
--- /dev/null
@@ -0,0 +1,355 @@
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Tcp4Proto.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_PROTO_H_
+#define _TCP4_PROTO_H_
+
+typedef struct _TCP_CB  TCP_CB;
+
+#include "Tcp4Driver.h"
+#include "Socket.h"
+#include "Tcp4Option.h"
+
+//
+// tcp states, Don't change their order, it is used as
+// index to mTcpOutFlag and other macros
+//
+enum {
+  TCP_CLOSED      = 0,
+  TCP_LISTEN,
+  TCP_SYN_SENT,
+  TCP_SYN_RCVD,
+  TCP_ESTABLISHED,
+  TCP_FIN_WAIT_1,
+  TCP_FIN_WAIT_2,
+  TCP_CLOSING,
+  TCP_TIME_WAIT,
+  TCP_CLOSE_WAIT,
+  TCP_LAST_ACK,
+};
+
+//
+// flags in the TCP header
+//
+enum {
+
+  TCP_FLG_FIN     = 0x01,
+  TCP_FLG_SYN     = 0x02,
+  TCP_FLG_RST     = 0x04,
+  TCP_FLG_PSH     = 0x08,
+  TCP_FLG_ACK     = 0x10,
+  TCP_FLG_URG     = 0x20,
+  TCP_FLG_FLAG    = 0x3F, // mask for all the flags
+};
+
+enum {
+
+  //
+  // TCP error status
+  //
+  TCP_CONNECT_REFUSED     = -1,
+  TCP_CONNECT_RESET       = -2,
+  TCP_CONNECT_CLOSED      = -3,
+
+  //
+  // Current congestion status as suggested by RFC3782.
+  //
+  TCP_CONGEST_RECOVER     = 1,  // during the NewReno fast recovery
+  TCP_CONGEST_LOSS        = 2,  // retxmit because of retxmit time out
+  TCP_CONGEST_OPEN        = 3,  // TCP is opening its congestion window
+
+  //
+  // TCP control flags
+  //
+  TCP_CTRL_NO_NAGLE       = 0x0001, // disable Nagle algorithm
+  TCP_CTRL_NO_KEEPALIVE   = 0x0002, // disable keepalive timer
+  TCP_CTRL_NO_WS          = 0x0004, // disable window scale option
+  TCP_CTRL_RCVD_WS        = 0x0008, // rcvd a wnd scale option in syn
+  TCP_CTRL_NO_TS          = 0x0010, // disable Timestamp option
+  TCP_CTRL_RCVD_TS        = 0x0020, // rcvd a Timestamp option in syn
+  TCP_CTRL_SND_TS         = 0x0040, // Send Timestamp option to remote
+  TCP_CTRL_SND_URG        = 0x0080, // in urgent send mode
+  TCP_CTRL_RCVD_URG       = 0x0100, // in urgent receive mode
+  TCP_CTRL_SND_PSH        = 0x0200, // in PUSH send mode
+  TCP_CTRL_FIN_SENT       = 0x0400, // FIN is sent
+  TCP_CTRL_FIN_ACKED      = 0x0800, // FIN is ACKed.
+  TCP_CTRL_TIMER_ON       = 0x1000, // At least one of the timer is on
+  TCP_CTRL_RTT_ON         = 0x2000, // The RTT measurement is on
+  TCP_CTRL_ACK_NOW        = 0x4000, // Send the ACK now, don't delay
+
+  //
+  // Timer related values
+  //
+  TCP_TIMER_CONNECT       = 0,                // Connection establishment timer
+  TCP_TIMER_REXMIT        = 1,                // retransmit timer
+  TCP_TIMER_PROBE         = 2,                // Window probe timer
+  TCP_TIMER_KEEPALIVE     = 3,                // Keepalive timer
+  TCP_TIMER_FINWAIT2      = 4,                // FIN_WAIT_2 timer
+  TCP_TIMER_2MSL          = 5,                // TIME_WAIT tiemr
+  TCP_TIMER_NUMBER        = 6,                // the total number of TCP timer.
+  TCP_TICK                = 200,              // every TCP tick is 200ms
+  TCP_TICK_HZ             = 5,                // the frequence of TCP tick
+  TCP_RTT_SHIFT           = 3,                // SRTT & RTTVAR scaled by 8
+  TCP_RTO_MIN             = TCP_TICK_HZ,      // the minium value of RTO
+  TCP_RTO_MAX             = TCP_TICK_HZ *60,  // the maxium value of RTO
+  TCP_FOLD_RTT            = 4,                // timeout threshod to fold RTT
+
+  //
+  // default values for some timers
+  //
+  TCP_MAX_LOSS            = 12,                  // default max times to retxmit
+  TCP_KEEPALIVE_IDLE_MIN  = TCP_TICK_HZ *60 *60 *2, // First keep alive
+  TCP_KEEPALIVE_PERIOD    = TCP_TICK_HZ *60,
+  TCP_MAX_KEEPALIVE       = 8,
+  TCP_FIN_WAIT2_TIME      = 2 *TCP_TICK_HZ,         // * 60,
+  TCP_TIME_WAIT_TIME      = 2 *TCP_TICK_HZ,
+  TCP_PAWS_24DAY          = 24 *24 *60 *60 *TCP_TICK_HZ,
+  TCP_CONNECT_TIME        = 75 *TCP_TICK_HZ,
+
+  //
+  // The header space to be reserved before TCP data to accomodate :
+  // 60byte IP head + 60byte TCP head + link layer head
+  //
+  TCP_MAX_HEAD            = 192,
+
+  //
+  // value ranges for some control option
+  //
+  TCP_RCV_BUF_SIZE        = 2 *1024 *1024,
+  TCP_RCV_BUF_SIZE_MIN    = 8 *1024,
+  TCP_SND_BUF_SIZE        = 2 *1024 *1024,
+  TCP_SND_BUF_SIZE_MIN    = 8 *1024,
+  TCP_BACKLOG             = 10,
+  TCP_BACKLOG_MIN         = 5,
+  TCP_MAX_LOSS_MIN        = 6,
+  TCP_CONNECT_TIME_MIN    = 60 *TCP_TICK_HZ,
+  TCP_MAX_KEEPALIVE_MIN   = 4,
+  TCP_KEEPALIVE_IDLE_MAX  = TCP_TICK_HZ *60 *60 *4,
+  TCP_KEEPALIVE_PERIOD_MIN= TCP_TICK_HZ *30,
+  TCP_FIN_WAIT2_TIME_MAX  = 4 *TCP_TICK_HZ,
+  TCP_TIME_WAIT_TIME_MAX  = 60 *TCP_TICK_HZ,
+};
+
+typedef struct _TCP_SEG {
+  TCP_SEQNO Seq;  // Starting sequence number
+  TCP_SEQNO End;  // The sequence of the last byte + 1,
+                  // include SYN/FIN. End-Seq = SEG.LEN
+  TCP_SEQNO Ack;  // ACK fild in the segment
+  UINT8     Flag; // TCP header flags
+  UINT16    Urg;  // Valid if URG flag is set.
+  UINT32    Wnd;  // TCP window size field
+} TCP_SEG;
+
+typedef struct _TCP_PEER {
+  UINT32      Ip;   // Network byte order
+  TCP_PORTNO  Port; // Network byte order
+} TCP_PEER;
+
+//
+// tcp control block, it includes various states
+//
+typedef struct _TCP_CB {
+  NET_LIST_ENTRY    List;
+  TCP_CB            *Parent;
+
+  SOCKET            *Sk;
+  TCP_PEER          LocalEnd;
+  TCP_PEER          RemoteEnd;
+
+  NET_LIST_ENTRY    SndQue;   // retxmission queue
+  NET_LIST_ENTRY    RcvQue;   // reassemble queue
+  UINT32            CtrlFlag; // control flags, such as NO_NAGLE
+  INT32             Error;    // soft error status,TCP_CONNECT_RESET...
+
+  //
+  // RFC793 and RFC1122 defined variables
+  //
+  UINT8             State;      // TCP state, such as SYN_SENT, LISTEN
+  UINT8             DelayedAck; // number of delayed ACKs
+  UINT16            HeadSum;    // checksum of the fixed parts of pesudo
+                                // header: Src IP, Dst IP, 0, Protocol,
+                                // not include the TCP length.
+
+  TCP_SEQNO         Iss;        // Initial Sending Sequence
+  TCP_SEQNO         SndUna;     // first unacknowledged data
+  TCP_SEQNO         SndNxt;     // next data sequence to send.
+  TCP_SEQNO         SndPsh;     // Send PUSH point
+  TCP_SEQNO         SndUp;      // Send urgent point
+  UINT32            SndWnd;     // Window advertised by the remote peer
+  UINT32            SndWndMax;  // max send window advertised by the peer
+  TCP_SEQNO         SndWl1;     // Seq number used for last window update
+  TCP_SEQNO         SndWl2;     // ack no of last window update
+  UINT16            SndMss;     // Max send segment size
+  TCP_SEQNO         RcvNxt;     // Next sequence no to receive
+  UINT32            RcvWnd;     // Window advertised by the local peer
+  TCP_SEQNO         RcvWl2;     // The RcvNxt (or ACK) of last window update.
+                                // It is necessary because of delayed ACK
+
+  TCP_SEQNO         RcvUp;                   // urgent point;
+  TCP_SEQNO         Irs;                     // Initial Receiving Sequence
+  UINT16            RcvMss;                  // Max receive segment size
+  UINT16            EnabledTimer;            // which timer is currently enabled
+  UINT32            Timer[TCP_TIMER_NUMBER]; // when the timer will expire
+  INT32             NextExpire;  // count down offset for the nearest timer
+  UINT32            Idle;        // How long the connection is in idle
+  UINT32            ProbeTime;   // the time out value for current window prober
+
+  //
+  // RFC1323 defined variables, about window scale,
+  // timestamp and PAWS
+  //
+  UINT8             SndWndScale;  // Wndscale received from the peer
+  UINT8             RcvWndScale;  // Wndscale used to scale local buffer
+  UINT32            TsRecent;     // TsRecent to echo to the remote peer
+  UINT32            TsRecentAge;  // When this TsRecent is updated
+
+  // TCP_SEQNO  LastAckSent;
+  // It isn't necessary to add LastAckSent here,
+  // since it is the same as RcvWl2
+
+  //
+  // RFC2988 defined variables. about RTT measurement
+  //
+  TCP_SEQNO         RttSeq;     // the seq of measured segment now
+  UINT32            RttMeasure; // currently measured RTT in heart beats
+  UINT32            SRtt;       // Smoothed RTT, scaled by 8
+  UINT32            RttVar;     // RTT variance, scaled by 8
+  UINT32            Rto;        // Current RTO, not scaled
+
+  //
+  // RFC2581, and 3782 variables.
+  // Congestion control + NewReno fast recovery.
+  //
+  UINT32            CWnd;         // Sender's congestion window
+  UINT32            Ssthresh;     // Slow start threshold.
+  TCP_SEQNO         Recover;      // recover point for NewReno
+  UINT16            DupAck;       // number of duplicate ACKs
+  UINT8             CongestState; // the current congestion state(RFC3782)
+  UINT8             LossTimes;    // number of retxmit timeouts in a row
+  TCP_SEQNO         LossRecover;  // recover point for retxmit
+
+  //
+  // configuration parameters, for EFI_TCP4_PROTOCOL specification
+  //
+  UINT32            KeepAliveIdle;   // idle time before sending first probe
+  UINT32            KeepAlivePeriod; // interval for subsequent keep alive probe
+  UINT8             MaxKeepAlive;    // Maxium keep alive probe times.
+  UINT8             KeepAliveProbes; // the number of keep alive probe.
+  UINT16            MaxRexmit;      // The maxium number of retxmit before abort
+  UINT32            FinWait2Timeout; // The FIN_WAIT_2 time out
+  UINT32            TimeWaitTimeout; // The TIME_WAIT time out
+  UINT32            ConnectTimeout;
+
+  //
+  // configuration for tcp provided by user
+  //
+  BOOLEAN           UseDefaultAddr;
+  UINT8             TOS;
+  UINT8             TTL;
+  EFI_IPv4_ADDRESS  SubnetMask;
+
+  //
+  // pointer reference to Ip used to send pkt
+  //
+  IP_IO_IP_INFO     *IpInfo;
+} TCP_CB;
+
+extern NET_LIST_ENTRY mTcpRunQue;
+extern NET_LIST_ENTRY mTcpListenQue;
+extern TCP_SEQNO      mTcpGlobalIss;
+extern UINT32         mTcpTick;
+
+//
+// TCP_CONNECTED: both ends have synchronized their ISN.
+//
+#define TCP_CONNECTED(state)  ((state) > TCP_SYN_RCVD)
+
+#define TCP_FIN_RCVD(State) \
+    (((State) == TCP_CLOSE_WAIT) || \
+    ((State) == TCP_LAST_ACK) || \
+    ((State) == TCP_CLOSING) || \
+    ((State) == TCP_TIME_WAIT))
+
+#define TCP_LOCAL_CLOSED(State) \
+      (((State) == TCP_FIN_WAIT_1) || \
+      ((State) == TCP_FIN_WAIT_2) || \
+      ((State) == TCP_CLOSING) || \
+      ((State) == TCP_TIME_WAIT) || \
+      ((State) == TCP_LAST_ACK))
+
+//
+// Get the TCP_SEG point from a net buffer's ProtoData
+//
+#define TCPSEG_NETBUF(NBuf) ((TCP_SEG *) ((NBuf)->ProtoData))
+
+//
+// macros to compare sequence no
+//
+#define TCP_SEQ_LT(SeqA, SeqB)  ((INT32) ((SeqA) - (SeqB)) < 0)
+#define TCP_SEQ_LEQ(SeqA, SeqB) ((INT32) ((SeqA) - (SeqB)) <= 0)
+#define TCP_SEQ_GT(SeqA, SeqB)  ((INT32) ((SeqB) - (SeqA)) < 0)
+#define TCP_SEQ_GEQ(SeqA, SeqB) ((INT32) ((SeqB) - (SeqA)) <= 0)
+
+//
+// TCP_SEQ_BETWEEN return whether b <= m <= e
+//
+#define TCP_SEQ_BETWEEN(b, m, e)  ((e) - (b) >= (m) - (b))
+
+//
+// TCP_SUB_SEQ returns Seq1 - Seq2. Make sure Seq1 >= Seq2
+//
+#define TCP_SUB_SEQ(Seq1, Seq2)     ((UINT32) ((Seq1) - (Seq2)))
+
+#define TCP_FLG_ON(Value, Flag)     ((BOOLEAN) (((Value) & (Flag)) != 0))
+#define TCP_SET_FLG(Value, Flag)    ((Value) |= (Flag))
+#define TCP_CLEAR_FLG(Value, Flag)  ((Value) &= ~(Flag))
+
+//
+// test whether two peers are equal
+//
+#define TCP_PEER_EQUAL(Pa, Pb) \
+  (((Pa)->Ip == (Pb)->Ip) && ((Pa)->Port == (Pb)->Port))
+
+//
+// test whether Pa matches Pb, or Pa is more specific
+// than pb. Zero means wildcard.
+//
+#define TCP_PEER_MATCH(Pa, Pb) \
+    ((((Pb)->Ip == 0) || ((Pb)->Ip == (Pa)->Ip)) && \
+    (((Pb)->Port == 0) || ((Pb)->Port == (Pa)->Port)))
+
+#define TCP_TIMER_ON(Flag, Timer)     ((Flag) & (1 << (Timer)))
+#define TCP_SET_TIMER(Flag, Timer)    ((Flag) |= (1 << (Timer)))
+#define TCP_CLEAR_TIMER(Flag, Timer)  ((Flag) &= ~(1 << (Timer)))
+
+#define TCP_TIME_LT(Ta, Tb)           ((INT32) ((Ta) - (Tb)) < 0)
+#define TCP_TIME_LEQ(Ta, Tb)          ((INT32) ((Ta) - (Tb)) <= 0)
+#define TCP_SUB_TIME(Ta, Tb)          ((UINT32) ((Ta) - (Tb)))
+
+#define TCP_MAX_WIN                   0xFFFFU
+
+typedef
+VOID
+(*TCP_TIMER_HANDLER) (
+  IN TCP_CB * Tcb
+  );
+
+#include "Tcp4Func.h"
+#endif
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Timer.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Timer.c
new file mode 100644 (file)
index 0000000..20679b4
--- /dev/null
@@ -0,0 +1,582 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Tcp4Timer.c\r
+\r
+Abstract:\r
+\r
+  TCP timer related functions.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+UINT32    mTcpTick = 1000;\r
+\r
+STATIC\r
+VOID\r
+TcpConnectTimeout (\r
+  IN TCP_CB *Tcb\r
+  );\r
+\r
+STATIC\r
+VOID\r
+TcpRexmitTimeout (\r
+  IN TCP_CB *Tcb\r
+  );\r
+\r
+STATIC\r
+VOID\r
+TcpProbeTimeout (\r
+  IN TCP_CB *Tcb\r
+  );\r
+\r
+STATIC\r
+VOID\r
+TcpKeepaliveTimeout (\r
+  IN TCP_CB *Tcb\r
+  );\r
+\r
+STATIC\r
+VOID\r
+TcpFinwait2Timeout (\r
+  IN TCP_CB *Tcb\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Tcp2MSLTimeout (\r
+  IN TCP_CB *Tcb\r
+  );\r
+\r
+TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = {\r
+  TcpConnectTimeout,\r
+  TcpRexmitTimeout,\r
+  TcpProbeTimeout,\r
+  TcpKeepaliveTimeout,\r
+  TcpFinwait2Timeout,\r
+  Tcp2MSLTimeout,\r
+};\r
+\r
+\r
+/**\r
+  Close the TCP connection.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpClose (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  NetbufFreeList (&Tcb->SndQue);\r
+  NetbufFreeList (&Tcb->RcvQue);\r
+\r
+  TcpSetState (Tcb, TCP_CLOSED);\r
+}\r
+\r
+\r
+/**\r
+  Connect timeout handler.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpConnectTimeout (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  if (!TCP_CONNECTED (Tcb->State)) {\r
+    TCP4_DEBUG_ERROR (("TcpConnectTimeout: connection closed "\r
+      "because conenction timer timeout for TCB %x\n", Tcb));\r
+\r
+    if (EFI_ABORTED == Tcb->Sk->SockError) {\r
+      SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
+    }\r
+\r
+    if (TCP_SYN_RCVD == Tcb->State) {\r
+      TCP4_DEBUG_WARN (("TcpConnectTimeout: send reset because "\r
+        "connection timer timeout for TCB %x\n", Tcb));\r
+\r
+      TcpResetConnection (Tcb);\r
+\r
+    }\r
+\r
+    TcpClose (Tcb);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Timeout handler for TCP retransmission timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpRexmitTimeout (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  UINT32  FlightSize;\r
+\r
+  TCP4_DEBUG_WARN (("TcpRexmitTimeout: transmission "\r
+    "timeout for TCB %x\n", Tcb));\r
+\r
+  //\r
+  // Set the congestion window. FlightSize is the\r
+  // amount of data that has been sent but not\r
+  // yet ACKed.\r
+  //\r
+  FlightSize        = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
+  Tcb->Ssthresh     = NET_MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2);\r
+\r
+  Tcb->CWnd         = Tcb->SndMss;\r
+  Tcb->LossRecover  = Tcb->SndNxt;\r
+\r
+  Tcb->LossTimes++;\r
+  if (Tcb->LossTimes > Tcb->MaxRexmit &&\r
+      !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {\r
+\r
+    TCP4_DEBUG_ERROR (("TcpRexmitTimeout: connection closed "\r
+      "because too many timeouts for TCB %x\n", Tcb));\r
+\r
+    if (EFI_ABORTED == Tcb->Sk->SockError) {\r
+      SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
+    }\r
+\r
+    TcpClose (Tcb);\r
+    return ;\r
+  }\r
+\r
+  TcpBackoffRto (Tcb);\r
+  TcpRetransmit (Tcb, Tcb->SndUna);\r
+  TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
+\r
+  Tcb->CongestState = TCP_CONGEST_LOSS;\r
+\r
+  TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+}\r
+\r
+\r
+/**\r
+  Timeout handler for window probe timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpProbeTimeout (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  //\r
+  // This is the timer for sender's SWSA. RFC1122 requires\r
+  // a timer set for sender's SWSA, and suggest combine it\r
+  // with window probe timer. If data is sent, don't set\r
+  // the probe timer, since retransmit timer is on.\r
+  //\r
+  if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {\r
+\r
+    ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT));\r
+    return ;\r
+  }\r
+\r
+  TcpSendZeroProbe (Tcb);\r
+  TcpSetProbeTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Timeout handler for keepalive timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpKeepaliveTimeout (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  Tcb->KeepAliveProbes++;\r
+\r
+  //\r
+  // Too many Keep-alive probes, drop the connection\r
+  //\r
+  if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {\r
+\r
+    if (EFI_ABORTED == Tcb->Sk->SockError) {\r
+      SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
+    }\r
+\r
+    TcpClose (Tcb);\r
+    return ;\r
+  }\r
+\r
+  TcpSendZeroProbe (Tcb);\r
+  TcpSetKeepaliveTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Timeout handler for FIN_WAIT_2 timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpFinwait2Timeout (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  TCP4_DEBUG_WARN (("TcpFinwait2Timeout: connection closed "\r
+    "because FIN_WAIT2 timer timeouts for TCB %x\n", Tcb));\r
+\r
+  TcpClose (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Timeout handler for 2MSL timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Tcp2MSLTimeout (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  TCP4_DEBUG_WARN (("Tcp2MSLTimeout: connection closed "\r
+    "because TIME_WAIT timer timeouts for TCB %x\n", Tcb));\r
+\r
+  TcpClose (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Update the timer status and the next expire time\r
+  according to the timers to expire in a specific\r
+  future time slot.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpUpdateTimer (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  UINT16  Index;\r
+\r
+  //\r
+  // Don't use a too large value to init NextExpire\r
+  // since mTcpTick wraps around as sequence no does.\r
+  //\r
+  Tcb->NextExpire = 65535;\r
+  TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
+\r
+  for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
+\r
+    if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
+        TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)) {\r
+\r
+      Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);\r
+      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Enable a TCP timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Timer    The index of the timer to be enabled.\r
+  @param  TimeOut  The timeout value of this timer.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpSetTimer (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT16 Timer,\r
+  IN UINT32 TimeOut\r
+  )\r
+{\r
+  TCP_SET_TIMER (Tcb->EnabledTimer, Timer);\r
+  Tcb->Timer[Timer] = mTcpTick + TimeOut;\r
+\r
+  TcpUpdateTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Clear one TCP timer.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+  @param  Timer    The index of the timer to be cleared.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpClearTimer (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT16 Timer\r
+  )\r
+{\r
+  TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);\r
+  TcpUpdateTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Clear all TCP timers.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpClearAllTimer (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  Tcb->EnabledTimer = 0;\r
+  TcpUpdateTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+  Enable the window prober timer and set the timeout value.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpSetProbeTimer (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {\r
+    Tcb->ProbeTime = Tcb->Rto;\r
+\r
+  } else {\r
+    Tcb->ProbeTime <<= 1;\r
+  }\r
+\r
+  if (Tcb->ProbeTime < TCP_RTO_MIN) {\r
+\r
+    Tcb->ProbeTime = TCP_RTO_MIN;\r
+  } else if (Tcb->ProbeTime > TCP_RTO_MAX) {\r
+\r
+    Tcb->ProbeTime = TCP_RTO_MAX;\r
+  }\r
+\r
+  TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);\r
+}\r
+\r
+\r
+/**\r
+  Enable the keepalive timer and set the timeout value.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpSetKeepaliveTimer (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {\r
+    return ;\r
+\r
+  }\r
+\r
+  //\r
+  // Set the timer to KeepAliveIdle if either\r
+  // 1. the keepalive timer is off\r
+  // 2. The keepalive timer is on, but the idle\r
+  // is less than KeepAliveIdle, that means the\r
+  // connection is alive since our last probe.\r
+  //\r
+  if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||\r
+      (Tcb->Idle < Tcb->KeepAliveIdle)) {\r
+\r
+    TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);\r
+    Tcb->KeepAliveProbes = 0;\r
+\r
+  } else {\r
+\r
+    TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Backoff the RTO.\r
+\r
+  @param  Tcb      Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+TcpBackoffRto (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  //\r
+  // Fold the RTT estimate if too many times, the estimate\r
+  // may be wrong, fold it. So the next time a valid\r
+  // measurement is sampled, we can start fresh.\r
+  //\r
+  if ((Tcb->LossTimes >= TCP_FOLD_RTT) && Tcb->SRtt) {\r
+    Tcb->RttVar += Tcb->SRtt >> 2;\r
+    Tcb->SRtt = 0;\r
+  }\r
+\r
+  Tcb->Rto <<= 1;\r
+\r
+  if (Tcb->Rto < TCP_RTO_MIN) {\r
+\r
+    Tcb->Rto = TCP_RTO_MIN;\r
+  } else if (Tcb->Rto > TCP_RTO_MAX) {\r
+\r
+    Tcb->Rto = TCP_RTO_MAX;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Heart beat timer handler.\r
+\r
+  @param  Event    Timer event signaled, ignored.\r
+  @param  Context  Context of the timer event, ignored.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TcpTicking (\r
+  IN EFI_EVENT Event,\r
+  IN VOID      *Context\r
+  )\r
+{\r
+  NET_LIST_ENTRY  *Entry;\r
+  NET_LIST_ENTRY  *Next;\r
+  TCP_CB          *Tcb;\r
+  INT16           Index;\r
+\r
+  mTcpTick++;\r
+  mTcpGlobalIss += 100;\r
+\r
+  //\r
+  // Don't use LIST_FOR_EACH, which isn't delete safe.\r
+  //\r
+  for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {\r
+\r
+    Next  = Entry->ForwardLink;\r
+\r
+    Tcb   = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+    if (Tcb->State == TCP_CLOSED) {\r
+      continue;\r
+    }\r
+    //\r
+    // The connection is doing RTT measurement.\r
+    //\r
+    if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+      Tcb->RttMeasure++;\r
+    }\r
+\r
+    Tcb->Idle++;\r
+\r
+    if (Tcb->DelayedAck) {\r
+      TcpSendAck (Tcb);\r
+    }\r
+\r
+    //\r
+    // No timer is active or no timer expired\r
+    //\r
+    if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) ||\r
+        ((--Tcb->NextExpire) > 0)) {\r
+\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Call the timeout handler for each expired timer.\r
+    //\r
+    for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
+\r
+      if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
+          TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {\r
+        //\r
+        // disable the timer before calling the handler\r
+        // in case the handler enables it again.\r
+        //\r
+        TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);\r
+        mTcpTimerHandler[Index](Tcb);\r
+\r
+        //\r
+        // The Tcb may have been deleted by the timer, or\r
+        // no other timer is set.\r
+        //\r
+        if ((Next->BackLink != Entry) ||\r
+            (Tcb->EnabledTimer == 0)) {\r
+\r
+          goto NextConnection;\r
+        }\r
+      }\r
+    }\r
+\r
+    TcpUpdateTimer (Tcb);\r
+NextConnection:\r
+    ;\r
+  }\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c b/MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c
new file mode 100644 (file)
index 0000000..b934765
--- /dev/null
@@ -0,0 +1,169 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Udp4Impl.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle OPTIONAL,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gUdp4ComponentName = {\r
+  UdpComponentNameGetDriverName,\r
+  UdpComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mUdpDriverNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"UDP Network Service Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+Arguments:\r
+\r
+  This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  Language   - A pointer to a three character ISO 639-2 language identifier.\r
+               This is the language of the driver name that that the caller\r
+               is requesting, and it must match one of the languages specified\r
+               in SupportedLanguages.  The number of languages supported by a\r
+               driver is up to the driver writer.\r
+  DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+               is the name of the driver specified by This in the language\r
+               specified by Language.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES            - The Unicode string for the Driver specified by This\r
+                          and the language specified by Language was returned\r
+                          in DriverName.\r
+  EFI_INVALID_PARAMETER - Language is NULL.\r
+  EFI_INVALID_PARAMETER - DriverName is NULL.\r
+  EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                          language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gUdp4ComponentName.SupportedLanguages,\r
+          mUdpDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle OPTIONAL,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **ControllerName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+Arguments:\r
+\r
+  This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  ControllerHandle - The handle of a controller that the driver specified by\r
+                     This is managing.  This handle specifies the controller\r
+                     whose name is to be returned.\r
+  ChildHandle      - The handle of the child controller to retrieve the name\r
+                     of.  This is an optional parameter that may be NULL.  It\r
+                     will be NULL for device drivers.  It will also be NULL\r
+                     for a bus drivers that wish to retrieve the name of the\r
+                     bus controller.  It will not be NULL for a bus driver\r
+                     that wishes to retrieve the name of a child controller.\r
+  Language         - A pointer to a three character ISO 639-2 language\r
+                     identifier.  This is the language of the controller name\r
+                     that that the caller is requesting, and it must match one\r
+                     of the languages specified in SupportedLanguages.  The\r
+                     number of languages supported by a driver is up to the\r
+                     driver writer.\r
+  ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                     string is the name of the controller specified by\r
+                     ControllerHandle and ChildHandle in the language specified\r
+                     by Language from the point of view of the driver specified\r
+                     by This.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Unicode string for the user readable name in the\r
+                          language specified by Language for the driver\r
+                          specified by This was returned in DriverName.\r
+  EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+  EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+  EFI_INVALID_PARAMETER - Language is NULL.\r
+  EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+  EFI_UNSUPPORTED       - The driver specified by This is not currently managing\r
+                          the controller specified by ControllerHandle and\r
+                          ChildHandle.\r
+  EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                          language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c
new file mode 100644 (file)
index 0000000..7b47ef4
--- /dev/null
@@ -0,0 +1,526 @@
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Udp4Driver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Udp4Impl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = {\r
+  Udp4DriverBindingSupported,\r
+  Udp4DriverBindingStart,\r
+  Udp4DriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding = {\r
+  Udp4ServiceBindingCreateChild,\r
+  Udp4ServiceBindingDestroyChild\r
+};\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to test.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCES             This driver supports this device.\r
+  @retval EFI_ALREADY_STARTED    This driver is already running on this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Test for the Udp4ServiceBinding Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiUdp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  //\r
+  // Test for the Ip4 Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiIp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start this driver on ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to bind driver to\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
+\r
+  @retval EFI_SUCCES             This driver is added to ControllerHandle\r
+  @retval EFI_ALREADY_STARTED    This driver is already running on ControllerHandle\r
+  @retval other                  This driver does not support this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  UDP4_SERVICE_DATA  *Udp4Service;\r
+\r
+  //\r
+  // Allocate Private Context Data Structure.\r
+  //\r
+  Udp4Service = NetAllocatePool (sizeof (UDP4_SERVICE_DATA));\r
+  if (Udp4Service == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Udp4CreateService (Udp4Service, This->DriverBindingHandle, ControllerHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_SERVICE;\r
+  }\r
+\r
+  //\r
+  // Install the Udp4ServiceBindingProtocol on the ControllerHandle.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ControllerHandle,\r
+                  &gEfiUdp4ServiceBindingProtocolGuid,\r
+                  &Udp4Service->ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto CLEAN_SERVICE;\r
+  }\r
+\r
+  Udp4SetVariableData (Udp4Service);\r
+\r
+  return Status;\r
+\r
+CLEAN_SERVICE:\r
+\r
+  Udp4CleanService (Udp4Service);\r
+\r
+FREE_SERVICE:\r
+\r
+  NetFreePool (Udp4Service);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on ControllerHandle.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ControllerHandle       Handle of device to stop driver on\r
+  @param  NumberOfChildren       Number of Handles in ChildHandleBuffer. If number\r
+                                 of  children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer      List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCES             This driver is removed ControllerHandle.\r
+  @retval other                  This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_HANDLE                    NicHandle;\r
+  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
+  UDP4_SERVICE_DATA             *Udp4Service;\r
+  UDP4_INSTANCE_DATA            *Instance;\r
+\r
+  //\r
+  // Find the NicHandle where UDP4 ServiceBinding Protocol is installed.\r
+  //\r
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);\r
+  if (NicHandle == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Retrieve the UDP4 ServiceBinding Protocol.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  NicHandle,\r
+                  &gEfiUdp4ServiceBindingProtocolGuid,\r
+                  (VOID **) &ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  NicHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (ServiceBinding);\r
+\r
+  //\r
+  // Uninstall the UDP4 ServiceBinding Protocol.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  NicHandle,\r
+                  &gEfiUdp4ServiceBindingProtocolGuid,\r
+                  &Udp4Service->ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  while (!NetListIsEmpty (&Udp4Service->ChildrenList)) {\r
+    //\r
+    // Destroy all instances.\r
+    //\r
+    Instance = NET_LIST_HEAD (&Udp4Service->ChildrenList, UDP4_INSTANCE_DATA, Link);\r
+\r
+    ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);\r
+  }\r
+\r
+  Udp4ClearVariableData (Udp4Service);\r
+\r
+  Udp4CleanService (Udp4Service);\r
+\r
+  NetFreePool (Udp4Service);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Creates a child handle with a set of I/O services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Pointer to the handle of the child to create.   If\r
+                                 it is NULL, then a new handle is created.   If it\r
+                                 is not NULL, then the I/O services are  added to\r
+                                 the existing child handle.\r
+\r
+  @retval EFI_SUCCES             The child handle was created with the I/O services\r
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources availabe to create\r
+                                 the child\r
+  @retval other                  The child handle was not created\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4ServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    *ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDP4_SERVICE_DATA   *Udp4Service;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_TPL             OldTpl;\r
+  VOID                *Ip4;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Allocate the instance private data structure.\r
+  //\r
+  Instance = NetAllocatePool (sizeof (UDP4_INSTANCE_DATA));\r
+  if (Instance == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Udp4InitInstance (Udp4Service, Instance);\r
+\r
+  //\r
+  // Add an IpInfo for this instance.\r
+  //\r
+  Instance->IpInfo = IpIoAddIp (Udp4Service->IpIo);\r
+  if (Instance->IpInfo == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FREE_INSTANCE;\r
+  }\r
+\r
+  //\r
+  // Install the Udp4Protocol for this instance.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiUdp4ProtocolGuid,\r
+                  &Instance->Udp4Proto,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto REMOVE_IPINFO;\r
+  }\r
+\r
+  Instance->ChildHandle = *ChildHandle;\r
+\r
+  //\r
+  // Open the default Ip4 protocol in the IP_IO BY_CHILD.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Udp4Service->IpIo->ChildHandle,\r
+                  &gEfiIp4ProtocolGuid,\r
+                  (VOID **) &Ip4,\r
+                  gUdp4DriverBinding.DriverBindingHandle,\r
+                  Instance->ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto UNINSTALL_PROTOCOL;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // Link this instance into the service context data and increase the ChildrenNumber.\r
+  //\r
+  NetListInsertTail (&Udp4Service->ChildrenList, &Instance->Link);\r
+  Udp4Service->ChildrenNumber++;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+\r
+UNINSTALL_PROTOCOL:\r
+\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         Instance->ChildHandle,\r
+         &gEfiUdp4ProtocolGuid,\r
+         &Instance->Udp4Proto,\r
+         NULL\r
+         );\r
+\r
+REMOVE_IPINFO:\r
+\r
+  IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);\r
+\r
+FREE_INSTANCE:\r
+\r
+  Udp4CleanInstance (Instance);\r
+\r
+  NetFreePool (Instance);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Destroys a child handle with a set of I/O services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Handle of the child to destroy\r
+\r
+  @retval EFI_SUCCES             The I/O services were removed from the child\r
+                                 handle\r
+  @retval EFI_UNSUPPORTED        The child handle does not support the I/O services\r
+                                  that are being removed\r
+  @retval EFI_INVALID_PARAMETER  Child handle is not a valid EFI Handle.\r
+  @retval EFI_ACCESS_DENIED      The child handle could not be destroyed because\r
+                                 its  I/O services are being used.\r
+  @retval other                  The child handle was not destroyed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4ServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDP4_SERVICE_DATA   *Udp4Service;\r
+  EFI_UDP4_PROTOCOL   *Udp4Proto;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_TPL             OldTpl;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Try to get the Udp4 protocol from the ChildHandle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiUdp4ProtocolGuid,\r
+                  (VOID **) &Udp4Proto,\r
+                  gUdp4DriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (Udp4Proto);\r
+\r
+  if (Instance->Destroyed) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Use the Destroyed flag to avoid the re-entering of the following code.\r
+  //\r
+  Instance->Destroyed = TRUE;\r
+\r
+  //\r
+  // Close the Ip4 protocol.\r
+  //\r
+  gBS->CloseProtocol (\r
+         Udp4Service->IpIo->ChildHandle,\r
+         &gEfiIp4ProtocolGuid,\r
+         gUdp4DriverBinding.DriverBindingHandle,\r
+         Instance->ChildHandle\r
+         );\r
+\r
+  //\r
+  // Uninstall the Udp4Protocol previously installed on the ChildHandle.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiUdp4ProtocolGuid,\r
+                  (VOID *) &Instance->Udp4Proto,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Instance->Destroyed = FALSE;\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Reset the configuration in case the instance's consumer forgets to do this.\r
+  //\r
+  Udp4Proto->Configure (Udp4Proto, NULL);\r
+\r
+  //\r
+  // Remove the IpInfo this instance consumes.\r
+  //\r
+  IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // Remove this instance from the service context data's ChildrenList.\r
+  //\r
+  NetListRemoveEntry (&Instance->Link);\r
+  Udp4Service->ChildrenNumber--;\r
+\r
+  //\r
+  // Clean the instance.\r
+  //\r
+  Udp4CleanInstance (Instance);\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  NetFreePool (Instance);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Udp4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The entry point for Udp4 driver which installs the driver binding\r
+  and component name protocol on its ImageHandle.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The image handle of the driver.\r
+  SystemTable - The system table.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - if the driver binding and component name protocols are\r
+                successfully installed, otherwise if failed.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Install the Udp4DriverBinding and Udp4ComponentName protocols.\r
+  //\r
+  Status = NetLibInstallAllDriverProtocols (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gUdp4DriverBinding,\r
+             ImageHandle,\r
+             &gUdp4ComponentName,\r
+             NULL,\r
+             NULL\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Initialize the UDP random port.\r
+    //\r
+    mUdp4RandomPort = ((UINT16) NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h
new file mode 100644 (file)
index 0000000..59acb44
--- /dev/null
@@ -0,0 +1,70 @@
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Udp4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _UDP4_DRIVER_H_
+#define _UDP4_DRIVER_H_
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/NetLib.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ControllerHandle,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4ServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4ServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  );
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
new file mode 100644 (file)
index 0000000..3f97393
--- /dev/null
@@ -0,0 +1,66 @@
+#/** @file\r
+# Component name for module Udp4\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. 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
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = Udp4\r
+  FILE_GUID                      = 6d6963ab-906d-4a65-a7ca-bd40e5d6af2b\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = Udp4DriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  Udp4Impl.h\r
+  Udp4Main.c\r
+  ComponentName.c\r
+  Udp4Impl.c\r
+  Udp4Driver.h\r
+  Udp4Driver.c\r
+  CommonHeader.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  UefiLib\r
+  BaseLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  UefiRuntimeServicesTableLib\r
+  DebugLib\r
+  IpIoLib\r
+  NetLib\r
+\r
+\r
+[Protocols]\r
+  gEfiIp4ProtocolGuid                           # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUdp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiIp4ServiceBindingProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa
new file mode 100644 (file)
index 0000000..1415458
--- /dev/null
@@ -0,0 +1,77 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>Udp4</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>6d6963ab-906d-4a65-a7ca-bd40e5d6af2b</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Udp4</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <License>All rights reserved. This program and the accompanying materials
+      are licensed and made available under the terms and conditions of the BSD License
+      which accompanies this distribution.  The full text of the license may be found at
+      http://opensource.org/licenses/bsd-license.php
+      
+      THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+      WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>Udp4</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiRuntimeServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>Udp4Driver.c</Filename>\r
+    <Filename>Udp4Driver.h</Filename>\r
+    <Filename>Udp4Impl.c</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>Udp4Main.c</Filename>\r
+    <Filename>Udp4Impl.h</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>Udp4DriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c
new file mode 100644 (file)
index 0000000..dd7522e
--- /dev/null
@@ -0,0 +1,1951 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Udp4Impl.c\r
+\r
+Abstract:\r
+\r
+  The implementation of the Udp4 protocol.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Udp4Impl.h"\r
+\r
+UINT16  mUdp4RandomPort;\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4CheckTimeout (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+STATIC\r
+BOOLEAN\r
+Udp4FindInstanceByPort (\r
+  IN NET_LIST_ENTRY    *InstanceList,\r
+  IN EFI_IPv4_ADDRESS  *Address,\r
+  IN UINT16            Port\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Udp4DgramSent (\r
+  IN EFI_STATUS  Status,\r
+  IN VOID        *Context,\r
+  IN VOID        *Sender,\r
+  IN VOID        *NotifyData\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Udp4DgramRcvd (\r
+  IN EFI_STATUS            Status,\r
+  IN ICMP_ERROR            IcmpError,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN NET_BUF               *Packet,\r
+  IN VOID                  *Context\r
+  );\r
+\r
+STATIC\r
+EFI_STATUS\r
+Udp4CancelTokens (\r
+  IN NET_MAP       *Map,\r
+  IN NET_MAP_ITEM  *Item,\r
+  IN VOID          *Arg OPTIONAL\r
+  );\r
+\r
+STATIC\r
+BOOLEAN\r
+Udp4MatchDgram (\r
+  IN UDP4_INSTANCE_DATA     *Instance,\r
+  IN EFI_UDP4_SESSION_DATA  *Udp4Session\r
+  );\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4RecycleRxDataWrap (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+STATIC\r
+UDP4_RXDATA_WRAP *\r
+Udp4WrapRxData (\r
+  IN UDP4_INSTANCE_DATA     *Instance,\r
+  IN NET_BUF                *Packet,\r
+  IN EFI_UDP4_RECEIVE_DATA  *RxData\r
+  );\r
+\r
+STATIC\r
+UINTN\r
+Udp4EnqueueDgram (\r
+  IN UDP4_SERVICE_DATA      *Udp4Service,\r
+  IN NET_BUF                *Packet,\r
+  IN EFI_UDP4_RECEIVE_DATA  *RxData\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Udp4DeliverDgram (\r
+  IN UDP4_SERVICE_DATA  *Udp4Service\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Udp4Demultiplex (\r
+  IN UDP4_SERVICE_DATA     *Udp4Service,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN NET_BUF               *Packet\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Udp4IcmpHandler (\r
+  IN UDP4_SERVICE_DATA     *Udp4Service,\r
+  IN ICMP_ERROR            IcmpError,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN NET_BUF               *Packet\r
+  );\r
+\r
+STATIC\r
+VOID\r
+Udp4SendPortUnreach (\r
+  IN IP_IO                 *IpIo,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN VOID                  *Udp4Header\r
+  );\r
+\r
+\r
+/**\r
+  Create the Udp service context data.\r
+\r
+  @param  Udp4Service            Pointer to the UDP4_SERVICE_DATA.\r
+  @param  ImageHandle            The image handle of this udp4 driver.\r
+  @param  ControllerHandle       The controller handle this udp4 driver binds on.\r
+\r
+  @retval EFI_SUCCESS            The udp4 service context data is created and\r
+                                 initialized.\r
+  @retval EFI_OUT_OF_RESOURCES   Cannot allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4CreateService (\r
+  IN UDP4_SERVICE_DATA  *Udp4Service,\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_HANDLE         ControllerHandle\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  IP_IO_OPEN_DATA  OpenData;\r
+\r
+  Udp4Service->Signature        = UDP4_SERVICE_DATA_SIGNATURE;\r
+  Udp4Service->ServiceBinding   = mUdp4ServiceBinding;\r
+  Udp4Service->ImageHandle      = ImageHandle;\r
+  Udp4Service->ControllerHandle = ControllerHandle;\r
+  Udp4Service->ChildrenNumber   = 0;\r
+\r
+  NetListInit (&Udp4Service->ChildrenList);\r
+\r
+  //\r
+  // Create the IpIo for this service context.\r
+  //\r
+  Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle);\r
+  if (Udp4Service->IpIo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Set the OpenData used to open the IpIo.\r
+  //\r
+  OpenData.IpConfigData                 = mIpIoDefaultIpConfigData;\r
+  OpenData.IpConfigData.AcceptBroadcast = TRUE;\r
+  OpenData.RcvdContext                  = (VOID *) Udp4Service;\r
+  OpenData.SndContext                   = NULL;\r
+  OpenData.PktRcvdNotify                = Udp4DgramRcvd;\r
+  OpenData.PktSentNotify                = Udp4DgramSent;\r
+\r
+  //\r
+  // Configure and start the IpIo.\r
+  //\r
+  Status = IpIoOpen (Udp4Service->IpIo, &OpenData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto RELEASE_IPIO;\r
+  }\r
+\r
+  //\r
+  // Create the event for Udp timeout checking.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  NET_TPL_FAST_TIMER,\r
+                  Udp4CheckTimeout,\r
+                  Udp4Service,\r
+                  &Udp4Service->TimeoutEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto RELEASE_IPIO;\r
+  }\r
+\r
+  //\r
+  // Start the timeout timer event.\r
+  //\r
+  Status = gBS->SetTimer (\r
+                  Udp4Service->TimeoutEvent,\r
+                  TimerPeriodic,\r
+                  UDP4_TIMEOUT_INTERVAL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto RELEASE_ALL;\r
+  }\r
+\r
+  Udp4Service->MacString = NULL;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+RELEASE_ALL:\r
+\r
+  gBS->CloseEvent (Udp4Service->TimeoutEvent);\r
+\r
+RELEASE_IPIO:\r
+\r
+  IpIoDestroy (Udp4Service->IpIo);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clean the Udp service context data.\r
+\r
+  @param  Udp4Service            Pointer to the UDP4_SERVICE_DATA.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4CleanService (\r
+  IN UDP4_SERVICE_DATA  *Udp4Service\r
+  )\r
+{\r
+  //\r
+  // Cancel the TimeoutEvent timer.\r
+  //\r
+  gBS->SetTimer (Udp4Service->TimeoutEvent, TimerCancel, 0);\r
+\r
+  //\r
+  // Close the TimeoutEvent timer.\r
+  //\r
+  gBS->CloseEvent (Udp4Service->TimeoutEvent);\r
+\r
+  //\r
+  // Destroy the IpIo.\r
+  //\r
+  IpIoDestroy (Udp4Service->IpIo);\r
+}\r
+\r
+\r
+/**\r
+  This function checks and timeouts the I/O datagrams holding by the corresponding\r
+  service context.\r
+\r
+  @param  Event                  The event this function registered to.\r
+  @param  Conext                 The context data registered during the creation of\r
+                                 the Event.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4CheckTimeout (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  UDP4_SERVICE_DATA   *Udp4Service;\r
+  NET_LIST_ENTRY      *Entry;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  NET_LIST_ENTRY      *WrapEntry;\r
+  NET_LIST_ENTRY      *NextEntry;\r
+  UDP4_RXDATA_WRAP    *Wrap;\r
+\r
+  Udp4Service = (UDP4_SERVICE_DATA *) Context;\r
+  NET_CHECK_SIGNATURE (Udp4Service, UDP4_SERVICE_DATA_SIGNATURE);\r
+\r
+  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+    //\r
+    // Iterate all the instances belonging to this service context.\r
+    //\r
+    Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+    NET_CHECK_SIGNATURE (Instance, UDP4_INSTANCE_DATA_SIGNATURE);\r
+\r
+    if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {\r
+      //\r
+      // Skip this instance if it's not configured or no receive timeout.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {\r
+      //\r
+      // Iterate all the rxdatas belonging to this udp instance.\r
+      //\r
+      Wrap = NET_LIST_USER_STRUCT (Entry, UDP4_RXDATA_WRAP, Link);\r
+\r
+      if (Wrap->TimeoutTick <= UDP4_TIMEOUT_INTERVAL / 1000) {\r
+        //\r
+        // Remove this RxData if it timeouts.\r
+        //\r
+        Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);\r
+      } else {\r
+        Wrap->TimeoutTick -= UDP4_TIMEOUT_INTERVAL / 1000;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function intializes the new created udp instance.\r
+\r
+  @param  Udp4Service            Pointer to the UDP4_SERVICE_DATA.\r
+  @param  Instance               Pointer to the un-initialized UDP4_INSTANCE_DATA.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4InitInstance (\r
+  IN UDP4_SERVICE_DATA   *Udp4Service,\r
+  IN UDP4_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  //\r
+  // Set the signature.\r
+  //\r
+  Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE;\r
+\r
+  //\r
+  // Init the lists.\r
+  //\r
+  NetListInit (&Instance->Link);\r
+  NetListInit (&Instance->RcvdDgramQue);\r
+  NetListInit (&Instance->DeliveredDgramQue);\r
+\r
+  //\r
+  // Init the NET_MAPs.\r
+  //\r
+  NetMapInit (&Instance->TxTokens);\r
+  NetMapInit (&Instance->RxTokens);\r
+  NetMapInit (&Instance->McastIps);\r
+\r
+  //\r
+  // Save the pointer to the UDP4_SERVICE_DATA, and initialize other members.\r
+  //\r
+  Instance->Udp4Service = Udp4Service;\r
+  Instance->Udp4Proto   = mUdp4Protocol;\r
+  Instance->IcmpError   = EFI_SUCCESS;\r
+  Instance->Configured  = FALSE;\r
+  Instance->IsNoMapping = FALSE;\r
+  Instance->Destroyed   = FALSE;\r
+}\r
+\r
+\r
+/**\r
+  This function cleans the udp instance.\r
+\r
+  @param  Instance               Pointer to the UDP4_INSTANCE_DATA to clean.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4CleanInstance (\r
+  IN UDP4_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  NetMapClean (&Instance->McastIps);\r
+  NetMapClean (&Instance->RxTokens);\r
+  NetMapClean (&Instance->TxTokens);\r
+}\r
+\r
+\r
+/**\r
+  This function finds the udp instance by the specified <Address, Port> pair.\r
+\r
+  @param  InstanceList           Pointer to the head of the list linking the udp\r
+                                 instances.\r
+  @param  Address                Pointer to the specified IPv4 address.\r
+  @param  Port                   The udp port number.\r
+\r
+  @return Is the specified <Address, Port> pair found or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Udp4FindInstanceByPort (\r
+  IN NET_LIST_ENTRY    *InstanceList,\r
+  IN EFI_IPv4_ADDRESS  *Address,\r
+  IN UINT16            Port\r
+  )\r
+{\r
+  NET_LIST_ENTRY        *Entry;\r
+  UDP4_INSTANCE_DATA    *Instance;\r
+  EFI_UDP4_CONFIG_DATA  *ConfigData;\r
+\r
+  NET_LIST_FOR_EACH (Entry, InstanceList) {\r
+    //\r
+    // Iterate all the udp instances.\r
+    //\r
+    Instance   = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+    ConfigData = &Instance->ConfigData;\r
+\r
+    if (!Instance->Configured || ConfigData->AcceptAnyPort) {\r
+      //\r
+      // If the instance is not configured or the configdata of the instance indicates\r
+      // this instance accepts any port, skip it.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (EFI_IP_EQUAL (ConfigData->StationAddress, *Address) &&\r
+      (ConfigData->StationPort == Port)) {\r
+      //\r
+      // if both the address and the port are the same, return TRUE.\r
+      //\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // return FALSE when matching fails.\r
+  //\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  This function tries to bind the udp instance according to the configured port\r
+  allocation stragety.\r
+\r
+  @param  InstanceList           Pointer to the head of the list linking the udp\r
+                                 instances.\r
+  @param  ConfigData             Pointer to the ConfigData of the instance to be\r
+                                 bound.\r
+\r
+  @retval EFI_SUCCESS            The bound operation is completed successfully.\r
+  @retval EFI_ACCESS_DENIED      The <Address, Port> specified by the ConfigData is\r
+                                 already used by other instance.\r
+  @retval EFI_OUT_OF_RESOURCES   No available port resources.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4Bind (\r
+  IN NET_LIST_ENTRY        *InstanceList,\r
+  IN EFI_UDP4_CONFIG_DATA  *ConfigData\r
+  )\r
+{\r
+  EFI_IPv4_ADDRESS  *StationAddress;\r
+  UINT16            StartPort;\r
+\r
+  if (ConfigData->AcceptAnyPort) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  StationAddress = &ConfigData->StationAddress;\r
+\r
+  if (ConfigData->StationPort != 0) {\r
+\r
+    if (!ConfigData->AllowDuplicatePort &&\r
+      Udp4FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)) {\r
+      //\r
+      // Do not allow duplicate port and the port is already used by other instance.\r
+      //\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+  } else {\r
+    //\r
+    // select a random port for this instance;\r
+    //\r
+\r
+    if (ConfigData->AllowDuplicatePort) {\r
+      //\r
+      // Just pick up the random port if the instance allows duplicate port.\r
+      //\r
+      ConfigData->StationPort = mUdp4RandomPort;\r
+    } else {\r
+\r
+      StartPort = mUdp4RandomPort;\r
+\r
+      while (Udp4FindInstanceByPort(InstanceList, StationAddress, mUdp4RandomPort)) {\r
+\r
+        mUdp4RandomPort++;\r
+        if (mUdp4RandomPort == 0) {\r
+          mUdp4RandomPort = UDP4_PORT_KNOWN;\r
+        }\r
+\r
+        if (mUdp4RandomPort == StartPort) {\r
+          //\r
+          // No available port.\r
+          //\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+      }\r
+\r
+      ConfigData->StationPort = mUdp4RandomPort;\r
+    }\r
+\r
+    mUdp4RandomPort++;\r
+    if (mUdp4RandomPort == 0) {\r
+      mUdp4RandomPort = UDP4_PORT_KNOWN;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function is used to check whether the NewConfigData has any un-reconfigurable\r
+  parameters changed compared to the OldConfigData.\r
+\r
+  @param  OldConfigData          Pointer to the current ConfigData the udp instance\r
+                                 uses.\r
+  @param  NewConfigData          Pointer to the new ConfigData.\r
+\r
+  @return The instance is reconfigurable or not according to the NewConfigData.\r
+\r
+**/\r
+BOOLEAN\r
+Udp4IsReconfigurable (\r
+  IN EFI_UDP4_CONFIG_DATA  *OldConfigData,\r
+  IN EFI_UDP4_CONFIG_DATA  *NewConfigData\r
+  )\r
+{\r
+  if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) ||\r
+    (NewConfigData->AcceptBroadcast != OldConfigData->AcceptBroadcast) ||\r
+    (NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) ||\r
+    (NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort)) {\r
+    //\r
+    // The receiving filter parameters cannot be changed.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if ((!NewConfigData->AcceptAnyPort) &&\r
+    (NewConfigData->StationPort != OldConfigData->StationPort)) {\r
+    //\r
+    // The port is not changeable.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if (!NewConfigData->AcceptPromiscuous) {\r
+\r
+    if (NewConfigData->UseDefaultAddress != OldConfigData->UseDefaultAddress) {\r
+      //\r
+      // The NewConfigData differs to the old one on the UseDefaultAddress.\r
+      //\r
+      return FALSE;\r
+    }\r
+\r
+    if (!NewConfigData->UseDefaultAddress &&\r
+      (!EFI_IP_EQUAL (NewConfigData->StationAddress, OldConfigData->StationAddress) ||\r
+      !EFI_IP_EQUAL (NewConfigData->SubnetMask, OldConfigData->SubnetMask))) {\r
+      //\r
+      // If the instance doesn't use the default address, and the new address or\r
+      // new subnet mask is different from the old values.\r
+      //\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  if (!EFI_IP_EQUAL (NewConfigData->RemoteAddress, OldConfigData->RemoteAddress)) {\r
+    //\r
+    // The remoteaddress is not the same.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if ((EFI_IP4 (NewConfigData->RemoteAddress) != 0) &&\r
+    (NewConfigData->RemotePort != OldConfigData->RemotePort)) {\r
+    //\r
+    // The RemotePort differs if it's designated in the configdata.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // All checks pass, return TRUE.\r
+  //\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  This function builds the Ip4 configdata from the Udp4ConfigData.\r
+\r
+  @param  Udp4ConfigData         Pointer to the EFI_UDP4_CONFIG_DATA.\r
+  @param  Ip4ConfigData          Pointer to the EFI_IP4_CONFIG_DATA.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4BuildIp4ConfigData (\r
+  IN EFI_UDP4_CONFIG_DATA  *Udp4ConfigData,\r
+  IN EFI_IP4_CONFIG_DATA   *Ip4ConfigData\r
+  )\r
+{\r
+  *Ip4ConfigData                   = mIpIoDefaultIpConfigData;\r
+  Ip4ConfigData->DefaultProtocol   = EFI_IP_PROTO_UDP;\r
+  Ip4ConfigData->AcceptBroadcast   = Udp4ConfigData->AcceptBroadcast;\r
+  Ip4ConfigData->AcceptPromiscuous = Udp4ConfigData->AcceptPromiscuous;\r
+  Ip4ConfigData->UseDefaultAddress = Udp4ConfigData->UseDefaultAddress;\r
+  Ip4ConfigData->StationAddress    = Udp4ConfigData->StationAddress;\r
+  Ip4ConfigData->SubnetMask        = Udp4ConfigData->SubnetMask;\r
+\r
+  //\r
+  // use the -1 magic number to disable the receiving process of the ip instance.\r
+  //\r
+  Ip4ConfigData->ReceiveTimeout    = (UINT32) (-1);\r
+}\r
+\r
+\r
+/**\r
+  This function validates the TxToken, it returns the error code according to the spec.\r
+\r
+  @param  Instance               Pointer to the udp instance context data.\r
+  @param  TxToken                Pointer to the token to be checked.\r
+\r
+  @retval EFI_SUCCESS            The TxToken is valid.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE: This is\r
+                                 NULL. Token is NULL. Token.Event is NULL.\r
+                                 Token.Packet.TxData is NULL.\r
+                                 Token.Packet.TxData.FragmentCount is zero.\r
+                                 Token.Packet.TxData.DataLength is not equal to the\r
+                                 sum of fragment lengths. One or more of the\r
+                                 Token.Packet.TxData.FragmentTable[].\r
+                                 FragmentLength fields is zero. One or more of the\r
+                                 Token.Packet.TxData.FragmentTable[].\r
+                                 FragmentBuffer fields is NULL.\r
+                                 Token.Packet.TxData. GatewayAddress is not a\r
+                                 unicast IPv4 address if it is not NULL. One or\r
+                                 more IPv4 addresses in Token.Packet.TxData.\r
+                                 UdpSessionData are not valid unicast IPv4\r
+                                 addresses if the UdpSessionData is not NULL.\r
+  @retval EFI_BAD_BUFFER_SIZE    The data length is greater than the maximum UDP\r
+                                 packet size.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4ValidateTxToken (\r
+  IN UDP4_INSTANCE_DATA         *Instance,\r
+  IN EFI_UDP4_COMPLETION_TOKEN  *TxToken\r
+  )\r
+{\r
+  EFI_UDP4_TRANSMIT_DATA  *TxData;\r
+  UINT32                  Index;\r
+  UINT32                  TotalLen;\r
+  EFI_UDP4_CONFIG_DATA    *ConfigData;\r
+  EFI_UDP4_SESSION_DATA   *UdpSessionData;\r
+  IP4_ADDR                SourceAddress;\r
+\r
+  if (TxToken->Event == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TxData = TxToken->Packet.TxData;\r
+\r
+  if ((TxData == NULL) || (TxData->FragmentCount == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TotalLen = 0;\r
+  for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+\r
+    if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||\r
+      (TxData->FragmentTable[Index].FragmentLength == 0)) {\r
+      //\r
+      // if the FragmentBuffer is NULL or the FragmentLeng is zero.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    TotalLen += TxData->FragmentTable[Index].FragmentLength;\r
+  }\r
+\r
+  if (TotalLen != TxData->DataLength) {\r
+    //\r
+    // The TotalLen calculated by adding all the FragmentLeng doesn't equal to the\r
+    // DataLength.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TxData->GatewayAddress != NULL) &&\r
+    !Ip4IsUnicast(EFI_NTOHL (*(TxData->GatewayAddress)), 0)) {\r
+    //\r
+    // The specified GatewayAddress is not a unicast IPv4 address while it's not 0.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ConfigData     = &Instance->ConfigData;\r
+  UdpSessionData = TxData->UdpSessionData;\r
+\r
+  if (UdpSessionData != NULL) {\r
+\r
+    SourceAddress = EFI_NTOHL (UdpSessionData->SourceAddress);\r
+\r
+    if ((SourceAddress != 0) && !Ip4IsUnicast (SourceAddress, 0)) {\r
+      //\r
+      // Check whether SourceAddress is a valid IPv4 address in case it's not zero.\r
+      // The configured station address is used if SourceAddress is zero.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) {\r
+      //\r
+      // Ambiguous, no avalaible DestinationPort for this token.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (EFI_IP4 (UdpSessionData->DestinationAddress) == 0) {\r
+      //\r
+      // The DestinationAddress specified in the UdpSessionData is 0.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else if (EFI_IP4 (ConfigData->RemoteAddress) == 0) {\r
+    //\r
+    // the configured RemoteAddress is all zero, and the user doens't override the\r
+    // destination address.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (TxData->DataLength > UDP4_MAX_DATA_SIZE) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function checks whether the specified Token duplicates with the one in the Map.\r
+\r
+  @param  Map                    Pointer to the NET_MAP.\r
+  @param  Item                   Pointer to the NET_MAP_ITEM contain the pointer to\r
+                                 the Token.\r
+  @param  Context                Pointer to the Token to be checked.\r
+\r
+  @retval EFI_SUCCESS            The Token specified by Context differs from the\r
+                                 one in the Item.\r
+  @retval EFI_ACCESS_DENIED      The Token duplicates with the one in the Item.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4TokenExist (\r
+  IN NET_MAP       *Map,\r
+  IN NET_MAP_ITEM  *Item,\r
+  IN VOID          *Context\r
+  )\r
+{\r
+  EFI_UDP4_COMPLETION_TOKEN  *Token;\r
+  EFI_UDP4_COMPLETION_TOKEN  *TokenInItem;\r
+\r
+  Token       = (EFI_UDP4_COMPLETION_TOKEN*) Context;\r
+  TokenInItem = (EFI_UDP4_COMPLETION_TOKEN*) Item->Key;\r
+\r
+  if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
+    //\r
+    // The Token duplicates with the TokenInItem in case either the two pointers are the\r
+    // same or the Events of these two tokens are the same.\r
+    //\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function calculates the checksum for the Packet, utilizing the pre-calculated\r
+  pseudo HeadSum to reduce some overhead.\r
+\r
+  @param  Packet                 Pointer to the NET_BUF contains the udp datagram.\r
+  @param  HeadSum                Checksum of the pseudo header execpt the length\r
+                                 field.\r
+\r
+  @return The 16-bit checksum of this udp datagram.\r
+\r
+**/\r
+UINT16\r
+Udp4Checksum (\r
+  IN NET_BUF *Packet,\r
+  IN UINT16  HeadSum\r
+  )\r
+{\r
+  UINT16  Checksum;\r
+\r
+  Checksum  = NetbufChecksum (Packet);\r
+  Checksum  = NetAddChecksum (Checksum, HeadSum);\r
+\r
+  Checksum  = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize));\r
+\r
+  return ~Checksum;\r
+}\r
+\r
+\r
+/**\r
+  This function removes the specified Token from the TokenMap.\r
+\r
+  @param  TokenMap               Pointer to the NET_MAP containing the tokens.\r
+  @param  Token                  Pointer to the Token to be removed.\r
+\r
+  @retval EFI_SUCCESS            The specified Token is removed from the TokenMap.\r
+  @retval EFI_NOT_FOUND          The specified Token is not found in the TokenMap.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4RemoveToken (\r
+  IN NET_MAP                    *TokenMap,\r
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  NET_MAP_ITEM  *Item;\r
+\r
+  //\r
+  // Find the Token first.\r
+  //\r
+  Item = NetMapFindKey (TokenMap, (VOID *) Token);\r
+\r
+  if (Item != NULL) {\r
+    //\r
+    // Remove the token if it's found in the map.\r
+    //\r
+    NetMapRemoveItem (TokenMap, Item, NULL);\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  This function is the packet transmitting notify function registered to the IpIo\r
+  interface. It's called to signal the udp TxToken when IpIo layer completes the\r
+  transmitting of the udp datagram.\r
+\r
+  @param  Status                 The completion status of the output udp datagram.\r
+  @param  Context                Pointer to the context data.\r
+  @param  Sender                 Pointer to the Ip sender of the udp datagram.\r
+  @param  NotifyData             Pointer to the notify data.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4DgramSent (\r
+  IN EFI_STATUS  Status,\r
+  IN VOID        *Context,\r
+  IN VOID        *Sender,\r
+  IN VOID        *NotifyData\r
+  )\r
+{\r
+  UDP4_INSTANCE_DATA         *Instance;\r
+  EFI_UDP4_COMPLETION_TOKEN  *Token;\r
+\r
+  Instance = (UDP4_INSTANCE_DATA *) Context;\r
+  Token    = (EFI_UDP4_COMPLETION_TOKEN *) NotifyData;\r
+\r
+  if (Udp4RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) {\r
+    //\r
+    // The token may be cancelled. Only signal it if the remove operation succeeds.\r
+    //\r
+    Token->Status = Status;\r
+    gBS->SignalEvent (Token->Event);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function processes the received datagram passed up by the IpIo layer.\r
+\r
+  @param  Status                 The status of this udp datagram.\r
+  @param  IcmpError              The IcmpError code, only available when Status is\r
+                                 EFI_ICMP_ERROR.\r
+  @param  NetSession             Pointer to the EFI_NET_SESSION_DATA.\r
+  @param  Packet                 Pointer to the NET_BUF containing the received udp\r
+                                 datagram.\r
+  @param  Context                Pointer to the context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4DgramRcvd (\r
+  IN EFI_STATUS            Status,\r
+  IN ICMP_ERROR            IcmpError,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN NET_BUF               *Packet,\r
+  IN VOID                  *Context\r
+  )\r
+{\r
+  NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);\r
+\r
+  //\r
+  // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR.\r
+  //\r
+  if (Status == EFI_SUCCESS) {\r
+    //\r
+    // Demultiplex the received datagram.\r
+    //\r
+    Udp4Demultiplex ((UDP4_SERVICE_DATA *) Context, NetSession, Packet);\r
+  } else {\r
+    //\r
+    // Handle the ICMP_ERROR packet.\r
+    //\r
+    Udp4IcmpHandler ((UDP4_SERVICE_DATA *) Context, IcmpError, NetSession, Packet);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function removes the multicast group specified by Arg from the Map.\r
+\r
+  @param  Map                    Pointer to the NET_MAP.\r
+  @param  Item                   Pointer to the NET_MAP_ITEM.\r
+  @param  Arg                    Pointer to the Arg, it's the pointer to a\r
+                                 multicast IPv4 Address.\r
+\r
+  @retval EFI_SUCCESS            The multicast address is removed.\r
+  @retval EFI_ABORTED            The specified multicast address is removed and the\r
+                                 Arg is not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4LeaveGroup (\r
+  IN NET_MAP       *Map,\r
+  IN NET_MAP_ITEM  *Item,\r
+  IN VOID          *Arg OPTIONAL\r
+  )\r
+{\r
+  EFI_IPv4_ADDRESS  *McastIp;\r
+\r
+  McastIp = Arg;\r
+\r
+  if ((McastIp != NULL) && ((UINTN) EFI_IP4 (*McastIp) != (UINTN) (Item->Key))) {\r
+    //\r
+    // McastIp is not NULL and the multicast address contained in the Item\r
+    // is not the same as McastIp.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Remove this Item.\r
+  //\r
+  NetMapRemoveItem (Map, Item, NULL);\r
+\r
+  if (McastIp != NULL) {\r
+    //\r
+    // Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration.\r
+    //\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function cancle the token specified by Arg in the Map.\r
+\r
+  @param  Map                    Pointer to the NET_MAP.\r
+  @param  Item                   Pointer to the NET_MAP_ITEM.\r
+  @param  Arg                    Pointer to the token to be cancelled, if NULL, all\r
+                                 the tokens in this Map will be cancelled.\r
+\r
+  @retval EFI_SUCCESS            The token is cancelled if Arg is NULL or the token\r
+                                 is not the same as that in the Item if Arg is not\r
+                                 NULL.\r
+  @retval EFI_ABORTED            Arg is not NULL, and the token specified by Arg is\r
+                                 cancelled.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Udp4CancelTokens (\r
+  IN NET_MAP       *Map,\r
+  IN NET_MAP_ITEM  *Item,\r
+  IN VOID          *Arg OPTIONAL\r
+  )\r
+{\r
+  EFI_UDP4_COMPLETION_TOKEN  *TokenToCancel;\r
+  NET_BUF                    *Packet;\r
+  IP_IO                      *IpIo;\r
+\r
+  if ((Arg != NULL) && (Item->Key != Arg)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Item->Value != NULL) {\r
+    //\r
+    // If the token is a transmit token, the corresponding Packet is recorded in\r
+    // Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken\r
+    // will invoke Udp4DgramSent, the token will be signaled and this Item will\r
+    // be removed from the Map there.\r
+    //\r
+    Packet = (NET_BUF *) (Item->Value);\r
+    IpIo   = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0]));\r
+\r
+    IpIoCancelTxToken (IpIo, Packet);\r
+  } else {\r
+    //\r
+    // The token is a receive token. Abort it and remove it from the Map.\r
+    //\r
+    TokenToCancel = (EFI_UDP4_COMPLETION_TOKEN *) Item->Key;\r
+\r
+    TokenToCancel->Status = EFI_ABORTED;\r
+    gBS->SignalEvent (TokenToCancel->Event);\r
+\r
+    NetMapRemoveItem (Map, Item, NULL);\r
+  }\r
+\r
+  if (Arg != NULL) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function removes all the Wrap datas in the RcvdDgramQue.\r
+\r
+  @param  RcvdDgramQue           Pointer to the list containing all the Wrap datas.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4FlushRxData (\r
+  IN NET_LIST_ENTRY  *RcvdDgramQue\r
+  )\r
+{\r
+  UDP4_RXDATA_WRAP  *Wrap;\r
+  EFI_TPL           OldTpl;\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+  while (!NetListIsEmpty (RcvdDgramQue)) {\r
+    //\r
+    // Iterate all the Wraps in the RcvdDgramQue.\r
+    //\r
+    Wrap = NET_LIST_HEAD (RcvdDgramQue, UDP4_RXDATA_WRAP, Link);\r
+\r
+    //\r
+    // The Wrap will be removed from the RcvdDgramQue by this function call.\r
+    //\r
+    Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);\r
+  }\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+}\r
+\r
+\r
+\r
+/**\r
+\r
+  @param  Instance               Pointer to the udp instance context data.\r
+  @param  Token                  Pointer to the token to be canceled, if NULL, all\r
+                                 tokens in this instance will be cancelled.\r
+\r
+  @retval EFI_SUCCESS            The Token is cancelled.\r
+  @retval EFI_NOT_FOUND          The Token is not found.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4InstanceCancelToken (\r
+  IN UDP4_INSTANCE_DATA         *Instance,\r
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Cancle this token from the TxTokens map.\r
+  //\r
+  Status = NetMapIterate (&Instance->TxTokens, Udp4CancelTokens, Token);\r
+\r
+  if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
+    //\r
+    // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from\r
+    // the TxTokens, just return success.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Try to cancel this token from the RxTokens map in condition either the Token\r
+  // is NULL or the specified Token is not in TxTokens.\r
+  //\r
+  Status = NetMapIterate (&Instance->RxTokens, Udp4CancelTokens, Token);\r
+\r
+  if ((Token != NULL) && (Status == EFI_SUCCESS)) {\r
+    //\r
+    // If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the\r
+    // TxTokens nor the RxTokens, or say, it's not found.\r
+    //\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ASSERT ((Token != NULL) || ((0 == NetMapGetCount (&Instance->TxTokens))\r
+    && (0 == NetMapGetCount (&Instance->RxTokens))));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function matches the received udp datagram with the Instance.\r
+\r
+  @param  Instance               Pointer to the udp instance context data.\r
+  @param  Udp4Session            Pointer to the EFI_UDP4_SESSION_DATA abstracted\r
+                                 from the received udp datagram.\r
+\r
+  @return The udp datagram matches the receiving requirments of the Instance or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Udp4MatchDgram (\r
+  IN UDP4_INSTANCE_DATA     *Instance,\r
+  IN EFI_UDP4_SESSION_DATA  *Udp4Session\r
+  )\r
+{\r
+  EFI_UDP4_CONFIG_DATA  *ConfigData;\r
+  IP4_ADDR              Destination;\r
+\r
+  ConfigData = &Instance->ConfigData;\r
+\r
+  if (ConfigData->AcceptPromiscuous) {\r
+    //\r
+    // Always matches if this instance is in the promiscuous state.\r
+    //\r
+    return TRUE;\r
+  }\r
+\r
+  if ((!ConfigData->AcceptAnyPort && (Udp4Session->DestinationPort != ConfigData->StationPort)) ||\r
+    ((ConfigData->RemotePort != 0) && (Udp4Session->SourcePort != ConfigData->RemotePort))) {\r
+    //\r
+    // The local port or the remote port doesn't match.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if ((EFI_IP4 (ConfigData->RemoteAddress) != 0) &&\r
+    !EFI_IP_EQUAL (ConfigData->RemoteAddress, Udp4Session->SourceAddress)) {\r
+    //\r
+    // This datagram doesn't come from the instance's specified sender.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if ((EFI_IP4 (ConfigData->StationAddress) == 0) ||\r
+    EFI_IP_EQUAL (Udp4Session->DestinationAddress, ConfigData->StationAddress)) {\r
+    //\r
+    // The instance is configured to receive datagrams destinated to any station IP or\r
+    // the destination address of this datagram matches the configured station IP.\r
+    //\r
+    return TRUE;\r
+  }\r
+\r
+  Destination = EFI_IP4 (Udp4Session->DestinationAddress);\r
+\r
+  if (IP4_IS_LOCAL_BROADCAST (Destination) && ConfigData->AcceptBroadcast) {\r
+    //\r
+    // The instance is configured to receive broadcast and this is a broadcast packet.\r
+    //\r
+    return TRUE;\r
+  }\r
+\r
+  if (IP4_IS_MULTICAST (NTOHL (Destination)) &&\r
+    (NULL != NetMapFindKey (&Instance->McastIps, (VOID *) (UINTN) Destination))) {\r
+    //\r
+    // It's a multicast packet and the multicast address is accepted by this instance.\r
+    //\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  This function removes the Wrap specified by Context and release relevant resources.\r
+\r
+  @param  Event                  The Event this notify function registered to.\r
+  @param  Context                Pointer to the context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4RecycleRxDataWrap (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  UDP4_RXDATA_WRAP  *Wrap;\r
+\r
+  Wrap = (UDP4_RXDATA_WRAP *) Context;\r
+\r
+  //\r
+  // Remove the Wrap from the list it belongs to.\r
+  //\r
+  NetListRemoveEntry (&Wrap->Link);\r
+\r
+  //\r
+  // Free the Packet associated with this Wrap.\r
+  //\r
+  NetbufFree (Wrap->Packet);\r
+\r
+  //\r
+  // Close the event.\r
+  //\r
+  gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
+\r
+  NetFreePool (Wrap);\r
+}\r
+\r
+\r
+/**\r
+  This function wraps the Packet and the RxData.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+  @param  Packet                 Pointer to the buffer containing the received\r
+                                 datagram.\r
+  @param  RxData                 Pointer to the EFI_UDP4_RECEIVE_DATA of this\r
+                                 datagram.\r
+\r
+  @return Pointer to the structure wrapping the RxData and the Packet.\r
+\r
+**/\r
+STATIC\r
+UDP4_RXDATA_WRAP *\r
+Udp4WrapRxData (\r
+  IN UDP4_INSTANCE_DATA     *Instance,\r
+  IN NET_BUF                *Packet,\r
+  IN EFI_UDP4_RECEIVE_DATA  *RxData\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UDP4_RXDATA_WRAP      *Wrap;\r
+\r
+  //\r
+  // Allocate buffer for the Wrap.\r
+  //\r
+  Wrap = NetAllocatePool (sizeof (UDP4_RXDATA_WRAP) +\r
+         (Packet->BlockOpNum - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));\r
+  if (Wrap == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  NetListInit (&Wrap->Link);\r
+\r
+  Wrap->RxData = *RxData;\r
+\r
+  //\r
+  // Create the Recycle event.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  NET_TPL_RECYCLE,\r
+                  Udp4RecycleRxDataWrap,\r
+                  Wrap,\r
+                  &Wrap->RxData.RecycleSignal\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    NetFreePool (Wrap);\r
+    return NULL;\r
+  }\r
+\r
+  Wrap->Packet      = Packet;\r
+  Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;\r
+\r
+  return Wrap;\r
+}\r
+\r
+\r
+/**\r
+  This function enqueues the received datagram into the instances' receiving queues.\r
+\r
+  @param  Udp4Service            Pointer to the udp service context data.\r
+  @param  Packet                 Pointer to the buffer containing the received\r
+                                 datagram.\r
+  @param  RxData                 Pointer to the EFI_UDP4_RECEIVE_DATA of this\r
+                                 datagram.\r
+\r
+  @return The times this datagram is enqueued.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+Udp4EnqueueDgram (\r
+  IN UDP4_SERVICE_DATA      *Udp4Service,\r
+  IN NET_BUF                *Packet,\r
+  IN EFI_UDP4_RECEIVE_DATA  *RxData\r
+  )\r
+{\r
+  NET_LIST_ENTRY      *Entry;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  UDP4_RXDATA_WRAP    *Wrap;\r
+  UINTN               Enqueued;\r
+\r
+  Enqueued = 0;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+    //\r
+    // Iterate the instances.\r
+    //\r
+    Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+\r
+    if (!Instance->Configured) {\r
+      continue;\r
+    }\r
+\r
+    if (Udp4MatchDgram (Instance, &RxData->UdpSession)) {\r
+      //\r
+      // Wrap the RxData and put this Wrap into the instances RcvdDgramQue.\r
+      //\r
+      Wrap = Udp4WrapRxData (Instance, Packet, RxData);\r
+      if (Wrap == NULL) {\r
+        continue;\r
+      }\r
+\r
+      NET_GET_REF (Packet);\r
+\r
+      NetListInsertTail (&Instance->RcvdDgramQue, &Wrap->Link);\r
+\r
+      Enqueued++;\r
+    }\r
+  }\r
+\r
+  return Enqueued;\r
+}\r
+\r
+\r
+/**\r
+  This function delivers the received datagrams for the specified instance.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4InstanceDeliverDgram (\r
+  IN UDP4_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  UDP4_RXDATA_WRAP           *Wrap;\r
+  EFI_UDP4_COMPLETION_TOKEN  *Token;\r
+  NET_BUF                    *Dup;\r
+  EFI_UDP4_RECEIVE_DATA      *RxData;\r
+\r
+  if (!NetListIsEmpty (&Instance->RcvdDgramQue) &&\r
+    !NetMapIsEmpty (&Instance->RxTokens)) {\r
+\r
+    Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link);\r
+\r
+    if (NET_BUF_SHARED (Wrap->Packet)) {\r
+      //\r
+      // Duplicate the Packet if it is shared between instances.\r
+      //\r
+      Dup = NetbufDuplicate (Wrap->Packet, NULL, 0);\r
+      if (Dup == NULL) {\r
+        return;\r
+      }\r
+\r
+      NetbufFree (Wrap->Packet);\r
+\r
+      Wrap->Packet = Dup;\r
+    }\r
+\r
+    NetListRemoveHead (&Instance->RcvdDgramQue);\r
+\r
+    Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);\r
+\r
+    //\r
+    // Build the FragmentTable and set the FragmentCount in RxData.\r
+    //\r
+    RxData                = &Wrap->RxData;\r
+    RxData->FragmentCount = Wrap->Packet->BlockOpNum;\r
+\r
+    NetbufBuildExt (\r
+      Wrap->Packet,\r
+      (NET_FRAGMENT *) RxData->FragmentTable,\r
+      &RxData->FragmentCount\r
+      );\r
+\r
+    Token->Status        = EFI_SUCCESS;\r
+    Token->Packet.RxData = &Wrap->RxData;\r
+\r
+    gBS->SignalEvent (Token->Event);\r
+\r
+    NetListInsertTail (&Instance->DeliveredDgramQue, &Wrap->Link);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function delivers the datagrams enqueued in the instances.\r
+\r
+  @param  Udp4Service            Pointer to the udp service context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4DeliverDgram (\r
+  IN UDP4_SERVICE_DATA  *Udp4Service\r
+  )\r
+{\r
+  NET_LIST_ENTRY      *Entry;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+    //\r
+    // Iterate the instances.\r
+    //\r
+    Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+\r
+    if (!Instance->Configured) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Deliver the datagrams of this instance.\r
+    //\r
+    Udp4InstanceDeliverDgram (Instance);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function demultiplexes the received udp datagram to the apropriate instances.\r
+\r
+  @param  Udp4Service            Pointer to the udp service context data.\r
+  @param  NetSession             Pointer to the EFI_NET_SESSION_DATA abstrated from\r
+                                 the received datagram.\r
+  @param  Packet                 Pointer to the buffer containing the received udp\r
+                                 datagram.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4Demultiplex (\r
+  IN UDP4_SERVICE_DATA     *Udp4Service,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN NET_BUF               *Packet\r
+  )\r
+{\r
+  EFI_UDP4_HEADER        *Udp4Header;\r
+  UINT16                 HeadSum;\r
+  EFI_UDP4_RECEIVE_DATA  RxData;\r
+  EFI_UDP4_SESSION_DATA  *Udp4Session;\r
+  UINTN                  Enqueued;\r
+\r
+  //\r
+  // Get the datagram header from the packet buffer.\r
+  //\r
+  Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);\r
+\r
+  if (Udp4Header->Checksum != 0) {\r
+    //\r
+    // check the checksum.\r
+    //\r
+    HeadSum = NetPseudoHeadChecksum (\r
+                NetSession->Source,\r
+                NetSession->Dest,\r
+                EFI_IP_PROTO_UDP,\r
+                0\r
+                );\r
+\r
+    if (Udp4Checksum (Packet, HeadSum) != 0) {\r
+      //\r
+      // Wrong checksum.\r
+      //\r
+      return;\r
+    }\r
+  }\r
+\r
+  gRT->GetTime (&RxData.TimeStamp, NULL);\r
+\r
+  Udp4Session                               = &RxData.UdpSession;\r
+  EFI_IP4 (Udp4Session->SourceAddress)      = NetSession->Source;\r
+  EFI_IP4 (Udp4Session->DestinationAddress) = NetSession->Dest;\r
+  Udp4Session->SourcePort                   = NTOHS (Udp4Header->SrcPort);\r
+  Udp4Session->DestinationPort              = NTOHS (Udp4Header->DstPort);\r
+\r
+  //\r
+  // Trim the UDP header.\r
+  //\r
+  NetbufTrim (Packet, UDP4_HEADER_SIZE, TRUE);\r
+\r
+  RxData.DataLength = (UINT32) Packet->TotalSize;\r
+\r
+  //\r
+  // Try to enqueue this datagram into the instances.\r
+  //\r
+  Enqueued = Udp4EnqueueDgram (Udp4Service, Packet, &RxData);\r
+\r
+  if (Enqueued == 0) {\r
+    //\r
+    // Send the port unreachable ICMP packet before we free this NET_BUF\r
+    //\r
+    Udp4SendPortUnreach (Udp4Service->IpIo, NetSession, Udp4Header);\r
+  }\r
+\r
+  //\r
+  // Try to free the packet before deliver it.\r
+  //\r
+  NetbufFree (Packet);\r
+\r
+  if (Enqueued > 0) {\r
+    //\r
+    // Deliver the datagram.\r
+    //\r
+    Udp4DeliverDgram (Udp4Service);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function builds and sends out a icmp port unreachable message.\r
+\r
+  @param  IpIo                   Pointer to the IP_IO instance.\r
+  @param  NetSession             Pointer to the EFI_NET_SESSION_DATA of the packet\r
+                                 causes this icmp error message.\r
+  @param  Udp4Header             Pointer to the udp header of the datagram causes\r
+                                 this icmp error message.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4SendPortUnreach (\r
+  IN IP_IO                 *IpIo,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN VOID                  *Udp4Header\r
+  )\r
+{\r
+  NET_BUF              *Packet;\r
+  UINT32               Len;\r
+  IP4_ICMP_ERROR_HEAD  *IcmpErrHdr;\r
+  EFI_IP4_HEADER       *IpHdr;\r
+  UINT8                *Ptr;\r
+  IP_IO_OVERRIDE       Override;\r
+  IP_IO_IP_INFO        *IpSender;\r
+\r
+  IpSender = IpIoFindSender (&IpIo, NetSession->Dest);\r
+  if (IpSender == NULL) {\r
+    //\r
+    // No apropriate sender, since we cannot send out the ICMP message through\r
+    // the default zero station address IP instance, abort.\r
+    //\r
+    return;\r
+  }\r
+\r
+  IpHdr = NetSession->IpHdr;\r
+\r
+  //\r
+  // Calculate the requried length of the icmp error message.\r
+  //\r
+  Len = sizeof (IP4_ICMP_ERROR_HEAD) + (EFI_IP4_HEADER_LEN (IpHdr) -\r
+        sizeof (IP4_HEAD)) + ICMP_ERROR_PACKET_LENGTH;\r
+\r
+  //\r
+  // Allocate buffer for the icmp error message.\r
+  //\r
+  Packet = NetbufAlloc (Len);\r
+  if (Packet == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Allocate space for the IP4_ICMP_ERROR_HEAD.\r
+  //\r
+  IcmpErrHdr = (IP4_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE);\r
+\r
+  //\r
+  // Set the required fields for the icmp port unreachable message.\r
+  //\r
+  IcmpErrHdr->Head.Type     = ICMP_TYPE_UNREACH;\r
+  IcmpErrHdr->Head.Code     = ICMP_CODE_UNREACH_PORT;\r
+  IcmpErrHdr->Head.Checksum = 0;\r
+  IcmpErrHdr->Fourth        = 0;\r
+\r
+  //\r
+  // Copy the IP header of the datagram tragged the error.\r
+  //\r
+  NetCopyMem (&IcmpErrHdr->IpHead, IpHdr, EFI_IP4_HEADER_LEN (IpHdr));\r
+\r
+  //\r
+  // Copy the UDP header.\r
+  //\r
+  Ptr = (UINT8 *) &IcmpErrHdr->IpHead + EFI_IP4_HEADER_LEN (IpHdr);\r
+  NetCopyMem (Ptr, Udp4Header, ICMP_ERROR_PACKET_LENGTH);\r
+\r
+  //\r
+  // Calculate the checksum.\r
+  //\r
+  IcmpErrHdr->Head.Checksum = ~(NetbufChecksum (Packet));\r
+\r
+  //\r
+  // Fill the override data.\r
+  //\r
+  Override.DoNotFragment            = FALSE;\r
+  Override.TypeOfService            = 0;\r
+  Override.TimeToLive               = 255;\r
+  Override.Protocol                 = EFI_IP_PROTO_ICMP;\r
+  EFI_IP4 (Override.SourceAddress)  = NetSession->Dest;\r
+  EFI_IP4 (Override.GatewayAddress) = 0;\r
+\r
+  //\r
+  // Send out this icmp packet.\r
+  //\r
+  IpIoSend (IpIo, Packet, IpSender, NULL, NULL, NetSession->Source, &Override);\r
+\r
+  NetbufFree (Packet);\r
+}\r
+\r
+\r
+/**\r
+  This function handles the received Icmp Error message and demultiplexes it to the\r
+  instance.\r
+\r
+  @param  Udp4Service            Pointer to the udp service context data.\r
+  @param  IcmpError              The icmp error code.\r
+  @param  NetSession             Pointer to the EFI_NET_SESSION_DATA abstracted\r
+                                 from the received Icmp Error packet.\r
+  @param  Packet                 Pointer to the Icmp Error packet.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4IcmpHandler (\r
+  IN UDP4_SERVICE_DATA     *Udp4Service,\r
+  IN ICMP_ERROR            IcmpError,\r
+  IN EFI_NET_SESSION_DATA  *NetSession,\r
+  IN NET_BUF               *Packet\r
+  )\r
+{\r
+  EFI_UDP4_HEADER        *Udp4Header;\r
+  EFI_UDP4_SESSION_DATA  Udp4Session;\r
+  NET_LIST_ENTRY         *Entry;\r
+  UDP4_INSTANCE_DATA     *Instance;\r
+\r
+  Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);\r
+\r
+  EFI_IP4 (Udp4Session.SourceAddress)      = NetSession->Source;\r
+  EFI_IP4 (Udp4Session.DestinationAddress) = NetSession->Dest;\r
+  Udp4Session.SourcePort                   = NTOHS (Udp4Header->DstPort);\r
+  Udp4Session.DestinationPort              = NTOHS (Udp4Header->SrcPort);\r
+\r
+  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+    //\r
+    // Iterate all the instances.\r
+    //\r
+    Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+\r
+    if (!Instance->Configured ||\r
+      Instance->ConfigData.AcceptPromiscuous ||\r
+      Instance->ConfigData.AcceptAnyPort ||\r
+      (EFI_IP4 (Instance->ConfigData.StationAddress) == 0)) {\r
+      //\r
+      // Don't try to deliver the ICMP error to this instance if it is not configured,\r
+      // or it's configured to be promiscuous or accept any port or accept all the\r
+      // datagrams.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (Udp4MatchDgram (Instance, &Udp4Session)) {\r
+      //\r
+      // Translate the Icmp Error code according to the udp spec.\r
+      //\r
+      Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, NULL, NULL);\r
+\r
+      if (IcmpError > ICMP_ERR_UNREACH_PORT) {\r
+        Instance->IcmpError = EFI_ICMP_ERROR;\r
+      }\r
+\r
+      //\r
+      // Notify the instance with the received Icmp Error.\r
+      //\r
+      Udp4ReportIcmpError (Instance);\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  NetbufFree (Packet);\r
+}\r
+\r
+\r
+/**\r
+  This function reports the received ICMP error.\r
+\r
+  @param  Instance               Pointer to the udp instance context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4ReportIcmpError (\r
+  IN UDP4_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  EFI_UDP4_COMPLETION_TOKEN  *Token;\r
+\r
+  if (NetMapIsEmpty (&Instance->RxTokens)) {\r
+    //\r
+    // There are no receive tokens to deliver the ICMP error.\r
+    //\r
+    return;\r
+  }\r
+\r
+  if (EFI_ERROR (Instance->IcmpError)) {\r
+    //\r
+    // Try to get a RxToken from the RxTokens map.\r
+    //\r
+    Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);\r
+\r
+    if (Token != NULL) {\r
+      //\r
+      // Report the error through the Token.\r
+      //\r
+      Token->Status = Instance->IcmpError;\r
+      gBS->SignalEvent (Token->Event);\r
+\r
+      //\r
+      // Clear the IcmpError.\r
+      //\r
+      Instance->IcmpError = EFI_SUCCESS;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function is a dummy ext-free function for the NET_BUF created for the output\r
+  udp datagram.\r
+\r
+  @param  Context                Pointer to the context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4NetVectorExtFree (\r
+  VOID  *Context\r
+  )\r
+{\r
+}\r
+\r
+\r
+/**\r
+  Set the Udp4 variable data.\r
+\r
+  @param  Udp4Service            Udp4 service data.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to set the\r
+                                 variable.\r
+  @retval other                  Set variable failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4SetVariableData (\r
+  IN UDP4_SERVICE_DATA  *Udp4Service\r
+  )\r
+{\r
+  UINT32                  NumConfiguredInstance;\r
+  NET_LIST_ENTRY          *Entry;\r
+  UINTN                   VariableDataSize;\r
+  EFI_UDP4_VARIABLE_DATA  *Udp4VariableData;\r
+  EFI_UDP4_SERVICE_POINT  *Udp4ServicePoint;\r
+  UDP4_INSTANCE_DATA      *Udp4Instance;\r
+  CHAR16                  *NewMacString;\r
+  EFI_STATUS              Status;\r
+\r
+  NumConfiguredInstance = 0;\r
+\r
+  //\r
+  // Go through the children list to count the configured children.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+    Udp4Instance = NET_LIST_USER_STRUCT_S (\r
+                     Entry,\r
+                     UDP4_INSTANCE_DATA,\r
+                     Link,\r
+                     UDP4_INSTANCE_DATA_SIGNATURE\r
+                     );\r
+\r
+    if (Udp4Instance->Configured) {\r
+      NumConfiguredInstance++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Calculate the size of the Udp4VariableData. As there may be no Udp4 child,\r
+  // we should add extra buffer for the service points only if the number of configured\r
+  // children is more than 1.\r
+  //\r
+  VariableDataSize = sizeof (EFI_UDP4_VARIABLE_DATA);\r
+\r
+  if (NumConfiguredInstance > 1) {\r
+    VariableDataSize += sizeof (EFI_UDP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
+  }\r
+\r
+  Udp4VariableData = NetAllocatePool (VariableDataSize);\r
+  if (Udp4VariableData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Udp4VariableData->DriverHandle = Udp4Service->ImageHandle;\r
+  Udp4VariableData->ServiceCount = NumConfiguredInstance;\r
+\r
+  Udp4ServicePoint = &Udp4VariableData->Services[0];\r
+\r
+  //\r
+  // Go through the children list to fill the configured children's address pairs.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+    Udp4Instance = NET_LIST_USER_STRUCT_S (\r
+                     Entry,\r
+                     UDP4_INSTANCE_DATA,\r
+                     Link,\r
+                     UDP4_INSTANCE_DATA_SIGNATURE\r
+                     );\r
+\r
+    if (Udp4Instance->Configured) {\r
+      Udp4ServicePoint->InstanceHandle = Udp4Instance->ChildHandle;\r
+      Udp4ServicePoint->LocalAddress   = Udp4Instance->ConfigData.StationAddress;\r
+      Udp4ServicePoint->LocalPort      = Udp4Instance->ConfigData.StationPort;\r
+      Udp4ServicePoint->RemoteAddress  = Udp4Instance->ConfigData.RemoteAddress;\r
+      Udp4ServicePoint->RemotePort     = Udp4Instance->ConfigData.RemotePort;\r
+\r
+      Udp4ServicePoint++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get the mac string.\r
+  //\r
+  Status = NetLibGetMacString (\r
+             Udp4Service->ControllerHandle,\r
+             Udp4Service->ImageHandle,\r
+             &NewMacString\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (Udp4Service->MacString != NULL) {\r
+    //\r
+    // The variable is set already, we're going to update it.\r
+    //\r
+    if (StrCmp (Udp4Service->MacString, NewMacString) != 0) {\r
+      //\r
+      // The mac address is changed, delete the previous variable first.\r
+      //\r
+      gRT->SetVariable (\r
+             Udp4Service->MacString,\r
+             &gEfiUdp4ServiceBindingProtocolGuid,\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             NULL\r
+             );\r
+    }\r
+\r
+    NetFreePool (Udp4Service->MacString);\r
+  }\r
+\r
+  Udp4Service->MacString = NewMacString;\r
+\r
+  Status = gRT->SetVariable (\r
+                  Udp4Service->MacString,\r
+                  &gEfiUdp4ServiceBindingProtocolGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  VariableDataSize,\r
+                  (VOID *) Udp4VariableData\r
+                  );\r
+\r
+ON_ERROR:\r
+\r
+  NetFreePool (Udp4VariableData);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the variable and free the resource.\r
+\r
+  @param  Udp4Service            Udp4 service data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+Udp4ClearVariableData (\r
+  IN UDP4_SERVICE_DATA  *Udp4Service\r
+  )\r
+{\r
+  ASSERT (Udp4Service->MacString != NULL);\r
+\r
+  gRT->SetVariable (\r
+         Udp4Service->MacString,\r
+         &gEfiUdp4ServiceBindingProtocolGuid,\r
+         EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+         0,\r
+         NULL\r
+         );\r
+\r
+  NetFreePool (Udp4Service->MacString);\r
+  Udp4Service->MacString = NULL;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h
new file mode 100644 (file)
index 0000000..7825624
--- /dev/null
@@ -0,0 +1,299 @@
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  Udp4Impl.h
+
+Abstract:
+
+  EFI UDPv4 protocol implementation
+
+
+**/
+
+#ifndef _UDP4_IMPL_H_
+#define _UDP4_IMPL_H_
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IP4.h>\r
+#include <Protocol/Udp4.h>\r
+
+#include <Library/IpIoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "Udp4Driver.h"
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL    gUdp4ComponentName;
+extern EFI_SERVICE_BINDING_PROTOCOL   mUdp4ServiceBinding;
+extern EFI_UDP4_PROTOCOL              mUdp4Protocol;
+extern UINT16                         mUdp4RandomPort;
+
+#define ICMP_ERROR_PACKET_LENGTH  8
+
+#define UDP4_TIMEOUT_INTERVAL (50 * TICKS_PER_MS)  // 50 milliseconds
+
+#define UDP4_HEADER_SIZE      sizeof (EFI_UDP4_HEADER)
+#define UDP4_MAX_DATA_SIZE    65507
+
+#define UDP4_PORT_KNOWN       1024
+
+#define UDP4_SERVICE_DATA_SIGNATURE  EFI_SIGNATURE_32('U', 'd', 'p', '4')
+
+#define UDP4_SERVICE_DATA_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  UDP4_SERVICE_DATA, \
+  ServiceBinding, \
+  UDP4_SERVICE_DATA_SIGNATURE \
+  )
+
+typedef struct _UDP4_SERVICE_DATA_ {
+  UINT32                        Signature;
+  EFI_SERVICE_BINDING_PROTOCOL  ServiceBinding;
+  EFI_HANDLE                    ImageHandle;
+  EFI_HANDLE                    ControllerHandle;
+  NET_LIST_ENTRY                ChildrenList;
+  UINTN                         ChildrenNumber;
+  IP_IO                         *IpIo;
+
+  EFI_EVENT                     TimeoutEvent;
+
+  CHAR16                        *MacString;
+} UDP4_SERVICE_DATA;
+
+#define UDP4_INSTANCE_DATA_SIGNATURE  EFI_SIGNATURE_32('U', 'd', 'p', 'I')
+
+#define UDP4_INSTANCE_DATA_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  UDP4_INSTANCE_DATA, \
+  Udp4Proto, \
+  UDP4_INSTANCE_DATA_SIGNATURE \
+  )
+
+typedef struct _UDP4_INSTANCE_DATA_ {
+  UINT32                Signature;
+  NET_LIST_ENTRY        Link;
+
+  UDP4_SERVICE_DATA     *Udp4Service;
+  EFI_UDP4_PROTOCOL     Udp4Proto;
+  EFI_UDP4_CONFIG_DATA  ConfigData;
+  EFI_HANDLE            ChildHandle;
+  BOOLEAN               Configured;
+  BOOLEAN               IsNoMapping;
+
+  NET_MAP               TxTokens;
+  NET_MAP               RxTokens;
+
+  NET_MAP               McastIps;
+
+  NET_LIST_ENTRY        RcvdDgramQue;
+  NET_LIST_ENTRY        DeliveredDgramQue;
+
+  UINT16                HeadSum;
+
+  EFI_STATUS            IcmpError;
+
+  IP_IO_IP_INFO         *IpInfo;
+
+  BOOLEAN               Destroyed;
+} UDP4_INSTANCE_DATA;
+
+typedef struct _UDP4_RXDATA_WRAP_ {
+  NET_LIST_ENTRY         Link;
+  NET_BUF                *Packet;
+  UINT32                 TimeoutTick;
+  EFI_UDP4_RECEIVE_DATA  RxData;
+} UDP4_RXDATA_WRAP;
+
+EFI_STATUS
+EFIAPI
+Udp4GetModeData (
+  IN  EFI_UDP4_PROTOCOL                *This,
+  OUT EFI_UDP4_CONFIG_DATA             *Udp4ConfigData OPTIONAL,
+  OUT EFI_IP4_MODE_DATA                *Ip4ModeData    OPTIONAL,
+  OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,
+  OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Configure (
+  IN EFI_UDP4_PROTOCOL     *This,
+  IN EFI_UDP4_CONFIG_DATA  *UdpConfigData OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Groups (
+  IN EFI_UDP4_PROTOCOL  *This,
+  IN BOOLEAN            JoinFlag,
+  IN EFI_IPv4_ADDRESS   *MulticastAddress OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Routes (
+  IN EFI_UDP4_PROTOCOL  *This,
+  IN BOOLEAN            DeleteRoute,
+  IN EFI_IPv4_ADDRESS   *SubnetAddress,
+  IN EFI_IPv4_ADDRESS   *SubnetMask,
+  IN EFI_IPv4_ADDRESS   *GatewayAddress
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Transmit (
+  IN EFI_UDP4_PROTOCOL          *This,
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Receive (
+  IN EFI_UDP4_PROTOCOL          *This,
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Cancel (
+  IN EFI_UDP4_PROTOCOL          *This,
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Udp4Poll (
+  IN EFI_UDP4_PROTOCOL  *This
+  );
+
+EFI_STATUS
+Udp4CreateService (
+  IN UDP4_SERVICE_DATA  *Udp4Service,
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_HANDLE         ControllerHandle
+  );
+
+VOID
+Udp4CleanService (
+  IN UDP4_SERVICE_DATA  *Udp4Service
+  );
+
+VOID
+Udp4InitInstance (
+  IN UDP4_SERVICE_DATA   *Udp4Service,
+  IN UDP4_INSTANCE_DATA  *Instance
+  );
+
+VOID
+Udp4CleanInstance (
+  IN UDP4_INSTANCE_DATA  *Instance
+  );
+
+EFI_STATUS
+Udp4Bind (
+  IN NET_LIST_ENTRY        *InstanceList,
+  IN EFI_UDP4_CONFIG_DATA  *ConfigData
+  );
+
+BOOLEAN
+Udp4IsReconfigurable (
+  IN EFI_UDP4_CONFIG_DATA  *OldConfigData,
+  IN EFI_UDP4_CONFIG_DATA  *NewConfigData
+  );
+
+VOID
+Udp4BuildIp4ConfigData (
+  IN EFI_UDP4_CONFIG_DATA  *Udp4ConfigData,
+  IN EFI_IP4_CONFIG_DATA   *Ip4ConfigData
+  );
+
+EFI_STATUS
+Udp4ValidateTxToken (
+  IN UDP4_INSTANCE_DATA         *Instance,
+  IN EFI_UDP4_COMPLETION_TOKEN  *TxToken
+  );
+
+EFI_STATUS
+Udp4TokenExist (
+  IN NET_MAP       *Map,
+  IN NET_MAP_ITEM  *Item,
+  IN VOID          *Context
+  );
+
+UINT16
+Udp4Checksum (
+  IN NET_BUF *Packet,
+  IN UINT16  HeadSum
+  );
+
+EFI_STATUS
+Udp4RemoveToken (
+  IN NET_MAP                    *TokenMap,
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token
+  );
+
+EFI_STATUS
+Udp4LeaveGroup (
+  IN NET_MAP       *Map,
+  IN NET_MAP_ITEM  *Item,
+  IN VOID          *Arg OPTIONAL
+  );
+
+VOID
+Udp4FlushRxData (
+  IN NET_LIST_ENTRY  *RcvdDgramQue
+  );
+
+EFI_STATUS
+Udp4InstanceCancelToken (
+  IN UDP4_INSTANCE_DATA         *Instance,
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token OPTIONAL
+  );
+
+VOID
+Udp4InstanceDeliverDgram (
+  IN UDP4_INSTANCE_DATA  *Instance
+  );
+
+VOID
+Udp4ReportIcmpError (
+  IN UDP4_INSTANCE_DATA  *Instance
+  );
+
+VOID
+Udp4NetVectorExtFree (
+  VOID  *Context
+  );
+
+EFI_STATUS
+Udp4SetVariableData (
+  IN UDP4_SERVICE_DATA  *Udp4Service
+  );
+
+VOID
+Udp4ClearVariableData (
+  IN UDP4_SERVICE_DATA  *Udp4Service
+  );
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c
new file mode 100644 (file)
index 0000000..4f897cb
--- /dev/null
@@ -0,0 +1,869 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+  Udp4Main.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Udp4Impl.h"\r
+\r
+#include <Protocol/Ip4.h>\r
+\r
+EFI_UDP4_PROTOCOL  mUdp4Protocol = {\r
+  Udp4GetModeData,\r
+  Udp4Configure,\r
+  Udp4Groups,\r
+  Udp4Routes,\r
+  Udp4Transmit,\r
+  Udp4Receive,\r
+  Udp4Cancel,\r
+  Udp4Poll\r
+};\r
+\r
+\r
+/**\r
+  This function copies the current operational settings of this EFI UDPv4 Protocol\r
+  instance into user-supplied buffers. This function is used optionally to retrieve\r
+  the operational mode data of underlying networks or drivers.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  Udp4ConfigData         Pointer to the buffer to receive the current\r
+                                 configuration data.\r
+  @param  Ip4ModeData            Pointer to the EFI IPv4 Protocol mode data\r
+                                 structure.\r
+  @param  MnpConfigData          Pointer to the managed network configuration data\r
+                                 structure.\r
+  @param  SnpModeData            Pointer to the simple network mode data structure.\r
+\r
+  @retval EFI_SUCCESS            The mode data was read.\r
+  @retval EFI_NOT_STARTED        When Udp4ConfigData is queried, no configuration\r
+                                 data is  available because this instance has not\r
+                                 been started.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4GetModeData (\r
+  IN  EFI_UDP4_PROTOCOL                *This,\r
+  OUT EFI_UDP4_CONFIG_DATA             *Udp4ConfigData OPTIONAL,\r
+  OUT EFI_IP4_MODE_DATA                *Ip4ModeData    OPTIONAL,\r
+  OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,\r
+  OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL\r
+  )\r
+{\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_IP4_PROTOCOL    *Ip;\r
+  EFI_TPL             OldTpl;\r
+  EFI_STATUS          Status;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured && (Udp4ConfigData != NULL)) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (Udp4ConfigData != NULL) {\r
+    //\r
+    // Set the Udp4ConfigData.\r
+    //\r
+    *Udp4ConfigData = Instance->ConfigData;\r
+  }\r
+\r
+  Ip = Instance->IpInfo->Ip;\r
+\r
+  //\r
+  // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData.\r
+  //\r
+  Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData);\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is used to do the following:\r
+  Initialize and start this instance of the EFI UDPv4 Protocol.\r
+  Change the filtering rules and operational parameters.\r
+  Reset this instance of the EFI UDPv4 Protocol.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  UdpConfigData          Pointer to the buffer to receive the current mode\r
+                                 data.\r
+\r
+  @retval EFI_SUCCESS            The configuration settings were set, changed, or\r
+                                 reset successfully.\r
+  @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,\r
+                                 BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_INVALID_PARAMETER  One or more following conditions are TRUE: This is\r
+                                 NULL. UdpConfigData.StationAddress is not a valid\r
+                                 unicast IPv4 address. UdpConfigData.SubnetMask is\r
+                                 not a valid IPv4 address mask.\r
+                                 UdpConfigData.RemoteAddress is not a valid unicast\r
+                                 IPv4  address if it is not zero.\r
+  @retval EFI_ALREADY_STARTED    The EFI UDPv4 Protocol instance is already\r
+                                 started/configured and must be stopped/reset\r
+                                 before it can be reconfigured. Only TypeOfService,\r
+                                 TimeToLive, DoNotFragment, ReceiveTimeout, and\r
+                                 TransmitTimeout can be reconfigured without\r
+                                 stopping the current instance of the EFI UDPv4\r
+                                 Protocol.\r
+  @retval EFI_ACCESS_DENIED      UdpConfigData.AllowDuplicatePort is FALSE and\r
+                                 UdpConfigData.StationPort is already used by other\r
+                                 instance.\r
+  @retval EFI_OUT_OF_RESOURCES   The EFI UDPv4 Protocol driver cannot allocate\r
+                                 memory for this EFI UDPv4 Protocol instance.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred and\r
+                                 this instance was not opened.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Configure (\r
+  IN EFI_UDP4_PROTOCOL     *This,\r
+  IN EFI_UDP4_CONFIG_DATA  *UdpConfigData OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  UDP4_INSTANCE_DATA   *Instance;\r
+  UDP4_SERVICE_DATA    *Udp4Service;\r
+  EFI_TPL              OldTpl;\r
+  IP4_ADDR             StationAddress;\r
+  IP4_ADDR             SubnetMask;\r
+  IP4_ADDR             RemoteAddress;\r
+  EFI_IP4_CONFIG_DATA  Ip4ConfigData;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured && (UdpConfigData == NULL)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Udp4Service = Instance->Udp4Service;\r
+  Status      = EFI_SUCCESS;\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (UdpConfigData != NULL) {\r
+\r
+    StationAddress = EFI_NTOHL (UdpConfigData->StationAddress);\r
+    SubnetMask     = EFI_NTOHL (UdpConfigData->SubnetMask);\r
+    RemoteAddress  = EFI_NTOHL (UdpConfigData->RemoteAddress);\r
+\r
+    if (!UdpConfigData->UseDefaultAddress &&\r
+      (!IP4_IS_VALID_NETMASK (SubnetMask) ||\r
+      !((StationAddress == 0) || Ip4IsUnicast (StationAddress, SubnetMask)) ||\r
+      !((RemoteAddress  == 0) || Ip4IsUnicast (RemoteAddress, 0)))) {\r
+      //\r
+      // Don't use default address, and subnet mask is invalid or StationAddress is not\r
+      // a valid unicast IPv4 address or RemoteAddress is not a valid unicast IPv4 address\r
+      // if it is not 0.\r
+      //\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    if (Instance->Configured) {\r
+      //\r
+      // The instance is already configured, try to do the re-configuration.\r
+      //\r
+      if (!Udp4IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {\r
+        //\r
+        // If the new configuration data wants to change some unreconfigurable\r
+        // settings, return EFI_ALREADY_STARTED.\r
+        //\r
+        Status = EFI_ALREADY_STARTED;\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      //\r
+      // Save the reconfigurable parameters.\r
+      //\r
+      Instance->ConfigData.TypeOfService   = UdpConfigData->TypeOfService;\r
+      Instance->ConfigData.TimeToLive      = UdpConfigData->TimeToLive;\r
+      Instance->ConfigData.DoNotFragment   = UdpConfigData->DoNotFragment;\r
+      Instance->ConfigData.ReceiveTimeout  = UdpConfigData->ReceiveTimeout;\r
+      Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;\r
+    } else {\r
+      //\r
+      // Construct the Ip configuration data from the UdpConfigData.\r
+      //\r
+      Udp4BuildIp4ConfigData (UdpConfigData, &Ip4ConfigData);\r
+\r
+      //\r
+      // Configure the Ip instance wrapped in the IpInfo.\r
+      //\r
+      Status = IpIoConfigIp (Instance->IpInfo, &Ip4ConfigData);\r
+      if (EFI_ERROR (Status)) {\r
+        if (Status == EFI_NO_MAPPING) {\r
+          Instance->IsNoMapping = TRUE;\r
+        }\r
+\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Instance->IsNoMapping = FALSE;\r
+\r
+      //\r
+      // Save the configuration data.\r
+      //\r
+      Instance->ConfigData                = *UdpConfigData;\r
+      Instance->ConfigData.StationAddress = Ip4ConfigData.StationAddress;\r
+      Instance->ConfigData.SubnetMask     = Ip4ConfigData.SubnetMask;\r
+\r
+      //\r
+      // Try to allocate the required port resource.\r
+      //\r
+      Status = Udp4Bind (&Udp4Service->ChildrenList, &Instance->ConfigData);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Reset the ip instance if bind fails.\r
+        //\r
+        IpIoConfigIp (Instance->IpInfo, NULL);\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      //\r
+      // Pre calculate the checksum for the pseudo head, ignore the UDP length first.\r
+      //\r
+      Instance->HeadSum = NetPseudoHeadChecksum (\r
+                            EFI_IP4 (Instance->ConfigData.StationAddress),\r
+                            EFI_IP4 (Instance->ConfigData.RemoteAddress),\r
+                            EFI_IP_PROTO_UDP,\r
+                            0\r
+                            );\r
+\r
+      Instance->Configured = TRUE;\r
+    }\r
+  } else {\r
+    //\r
+    // UdpConfigData is NULL, reset the instance.\r
+    //\r
+    Instance->Configured  = FALSE;\r
+    Instance->IsNoMapping = FALSE;\r
+\r
+    //\r
+    // Reset the Ip instance wrapped in the IpInfo.\r
+    //\r
+    IpIoConfigIp (Instance->IpInfo, NULL);\r
+\r
+    //\r
+    // Cancel all the user tokens.\r
+    //\r
+    Udp4InstanceCancelToken (Instance, NULL);\r
+\r
+    //\r
+    // Remove the buffered RxData for this instance.\r
+    //\r
+    Udp4FlushRxData (&Instance->RcvdDgramQue);\r
+  }\r
+\r
+  Udp4SetVariableData (Instance->Udp4Service);\r
+\r
+ON_EXIT:\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is used to enable and disable the multicast group filtering.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  JoinFlag               Set to TRUE to join a multicast group. Set to\r
+                                 FALSE to leave one or all multicast groups.\r
+  @param  MulticastAddress       Pointer to multicast group address to join or\r
+                                 leave.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_NOT_STARTED        The EFI UDPv4 Protocol instance has not been\r
+                                 started.\r
+  @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,\r
+                                 BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_OUT_OF_RESOURCES   Could not allocate resources to join the group.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. JoinFlag is TRUE and\r
+                                 MulticastAddress is NULL. JoinFlag is TRUE and\r
+                                 *MulticastAddress is not a valid  multicast\r
+                                 address.\r
+  @retval EFI_ALREADY_STARTED    The group address is already in the group table\r
+                                 (when JoinFlag is TRUE).\r
+  @retval EFI_NOT_FOUND          The group address is not in the group table (when\r
+                                 JoinFlag is FALSE).\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Groups (\r
+  IN EFI_UDP4_PROTOCOL  *This,\r
+  IN BOOLEAN            JoinFlag,\r
+  IN EFI_IPv4_ADDRESS   *MulticastAddress OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_IP4_PROTOCOL    *Ip;\r
+  EFI_TPL             OldTpl;\r
+\r
+  if ((This == NULL) ||\r
+    (JoinFlag && (MulticastAddress == NULL)) ||\r
+    (JoinFlag && !IP4_IS_MULTICAST (EFI_NTOHL (*MulticastAddress)))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (Instance->IsNoMapping) {\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  Ip = Instance->IpInfo->Ip;\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // Invoke the Ip instance the Udp4 instance consumes to do the group operation.\r
+  //\r
+  Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Keep a local copy of the configured multicast IPs because IpIo receives\r
+  // datagrams from the 0 station address IP instance and then UDP delivers to\r
+  // the matched instance. This copy of multicast IPs is used to avoid receive\r
+  // the mutlicast datagrams destinated to multicast IPs the other instances configured.\r
+  //\r
+  if (JoinFlag) {\r
+\r
+    NetMapInsertTail (\r
+      &Instance->McastIps,\r
+      (VOID *) (UINTN) EFI_IP4 (*MulticastAddress),\r
+      NULL\r
+      );\r
+  } else {\r
+\r
+    NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress);\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function adds a route to or deletes a route from the routing table.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  DeleteRoute            Set to TRUE to delete this route from the routing\r
+                                 table. Set to FALSE to add this route to the\r
+                                 routing table.\r
+  @param  SubnetAddress          The destination network address that needs to be\r
+                                 routed.\r
+  @param  SubnetMask             The subnet mask of SubnetAddress.\r
+  @param  GatewayAddress         The gateway IP address for this route.\r
+\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+  @retval EFI_NOT_STARTED        The EFI UDPv4 Protocol instance has not been\r
+                                 started.\r
+  @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,\r
+                                 BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. SubnetAddress is NULL. SubnetMask is\r
+                                 NULL. GatewayAddress is NULL. SubnetAddress is not\r
+                                 a valid subnet address. SubnetMask is not a valid\r
+                                 subnet mask. GatewayAddress is not a valid unicast\r
+                                 IP address.\r
+  @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.\r
+  @retval EFI_NOT_FOUND          This route is not in the routing table.\r
+  @retval EFI_ACCESS_DENIED      The route is already defined in the routing table.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Routes (\r
+  IN EFI_UDP4_PROTOCOL  *This,\r
+  IN BOOLEAN            DeleteRoute,\r
+  IN EFI_IPv4_ADDRESS   *SubnetAddress,\r
+  IN EFI_IPv4_ADDRESS   *SubnetMask,\r
+  IN EFI_IPv4_ADDRESS   *GatewayAddress\r
+  )\r
+{\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_IP4_PROTOCOL    *Ip;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (Instance->IsNoMapping) {\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  Ip = Instance->IpInfo->Ip;\r
+\r
+  //\r
+  // Invoke the Ip instance the Udp4 instance consumes to do the actual operation.\r
+  //\r
+  return Ip->Routes (Ip, DeleteRoute, SubnetAddress, SubnetMask, GatewayAddress);\r
+}\r
+\r
+\r
+/**\r
+  This function places a sending request to this instance of the EFI UDPv4 Protocol,\r
+  alongside the transmit data that was filled by the user.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  Token                  Pointer to the completion token that will be\r
+                                 placed into the transmit queue.\r
+\r
+  @retval EFI_SUCCESS            The data has been queued for transmission.\r
+  @retval EFI_NOT_STARTED        This EFI UDPv4 Protocol instance has not been\r
+                                 started.\r
+  @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,\r
+                                 BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE: This is\r
+                                 NULL. Token is NULL. Token.Event is NULL.\r
+                                 Token.Packet.TxData is NULL.\r
+                                 Token.Packet.TxData.FragmentCount is zero.\r
+                                 Token.Packet.TxData.DataLength is not equal to the\r
+                                 sum of fragment lengths. One or more of the\r
+                                 Token.Packet.TxData.FragmentTable[].\r
+                                 FragmentLength fields is zero. One or more of the\r
+                                 Token.Packet.TxData.FragmentTable[].\r
+                                 FragmentBuffer fields is NULL.\r
+                                 Token.Packet.TxData. GatewayAddress is not a\r
+                                 unicast IPv4 address if it is not NULL. One or\r
+                                 more IPv4 addresses in Token.Packet.TxData.\r
+                                 UdpSessionData are not valid unicast IPv4\r
+                                 addresses if the UdpSessionData is not NULL.\r
+  @retval EFI_ACCESS_DENIED      The transmit completion token with the same\r
+                                 Token.Event is already in the transmit queue.\r
+  @retval EFI_NOT_READY          The completion token could not be queued because\r
+                                 the transmit queue is full.\r
+  @retval EFI_OUT_OF_RESOURCES   Could not queue the transmit data.\r
+  @retval EFI_NOT_FOUND          There is no route to the destination network or\r
+                                 address.\r
+  @retval EFI_BAD_BUFFER_SIZE    The data length is greater than the maximum UDP\r
+                                 packet size. Or the length of the IP header + UDP\r
+                                 header + data length is greater than MTU if\r
+                                 DoNotFragment is TRUE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Transmit (\r
+  IN EFI_UDP4_PROTOCOL          *This,\r
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UDP4_INSTANCE_DATA      *Instance;\r
+  EFI_TPL                 OldTpl;\r
+  NET_BUF                 *Packet;\r
+  EFI_UDP4_HEADER         *Udp4Header;\r
+  EFI_UDP4_CONFIG_DATA    *ConfigData;\r
+  IP4_ADDR                Destination;\r
+  EFI_UDP4_TRANSMIT_DATA  *TxData;\r
+  EFI_UDP4_SESSION_DATA   *UdpSessionData;\r
+  UDP4_SERVICE_DATA       *Udp4Service;\r
+  IP_IO_OVERRIDE          Override;\r
+  UINT16                  HeadSum;\r
+\r
+  if ((This == NULL) || (Token == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (Instance->IsNoMapping) {\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // Validate the Token, if the token is invalid return the error code.\r
+  //\r
+  Status = Udp4ValidateTxToken (Instance, Token);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)) ||\r
+    EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))) {\r
+    //\r
+    // Try to find a duplicate token in the two token maps, if found, return\r
+    // EFI_ACCESS_DENIED.\r
+    //\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  TxData = Token->Packet.TxData;\r
+\r
+  //\r
+  // Create a net buffer to hold the user buffer and the udp header.\r
+  //\r
+  Packet = NetbufFromExt (\r
+             (NET_FRAGMENT *)TxData->FragmentTable,\r
+             TxData->FragmentCount,\r
+             UDP4_HEADER_SIZE,\r
+             0,\r
+             Udp4NetVectorExtFree,\r
+             NULL\r
+             );\r
+  if (Packet == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Store the IpIo in ProtoData.\r
+  //\r
+  Udp4Service = Instance->Udp4Service;\r
+  *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp4Service->IpIo);\r
+\r
+  Udp4Header = (EFI_UDP4_HEADER *) NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE);\r
+  ConfigData = &Instance->ConfigData;\r
+\r
+  //\r
+  // Fill the udp header.\r
+  //\r
+  Udp4Header->SrcPort      = HTONS (ConfigData->StationPort);\r
+  Udp4Header->DstPort      = HTONS (ConfigData->RemotePort);\r
+  Udp4Header->Length       = HTONS (Packet->TotalSize);\r
+  Udp4Header->Checksum     = 0;\r
+\r
+  UdpSessionData = TxData->UdpSessionData;\r
+  Override.SourceAddress = ConfigData->StationAddress;\r
+\r
+  if (UdpSessionData != NULL) {\r
+    //\r
+    // Set the SourceAddress, SrcPort and Destination according to the specified\r
+    // UdpSessionData.\r
+    //\r
+    if (EFI_IP4 (UdpSessionData->SourceAddress) != 0) {\r
+      Override.SourceAddress = UdpSessionData->SourceAddress;\r
+    }\r
+\r
+    if (UdpSessionData->SourcePort != 0) {\r
+      Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);\r
+    }\r
+\r
+    Destination = EFI_IP4 (UdpSessionData->DestinationAddress);\r
+\r
+    if (UdpSessionData->DestinationPort != 0) {\r
+      Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);\r
+    }\r
+\r
+    //\r
+    // calculate the pseudo head checksum using the overridden parameters.\r
+    //\r
+    HeadSum = NetPseudoHeadChecksum (\r
+                EFI_IP4 (Override.SourceAddress),\r
+                Destination,\r
+                EFI_IP_PROTO_UDP,\r
+                0\r
+                );\r
+  } else {\r
+    //\r
+    // UdpSessionData is NULL, use the address and port information previously configured.\r
+    //\r
+    Destination = EFI_IP4 (ConfigData->RemoteAddress);\r
+    HeadSum     = Instance->HeadSum;\r
+  }\r
+\r
+  //\r
+  // calculate the checksum.\r
+  //\r
+  Udp4Header->Checksum = Udp4Checksum (Packet, HeadSum);\r
+  if (Udp4Header->Checksum == 0) {\r
+    //\r
+    // If the calculated checksum is 0, fill the Checksum field with all ones.\r
+    //\r
+    Udp4Header->Checksum = 0xffff;\r
+  }\r
+\r
+  //\r
+  // Fill the IpIo Override data.\r
+  //\r
+  EFI_IP4 (Override.GatewayAddress) = (TxData->GatewayAddress != NULL) ?\r
+                                      EFI_IP4 (*(TxData->GatewayAddress)) : 0;\r
+  Override.Protocol                 = EFI_IP_PROTO_UDP;\r
+  Override.TypeOfService            = ConfigData->TypeOfService;\r
+  Override.TimeToLive               = ConfigData->TimeToLive;\r
+  Override.DoNotFragment            = ConfigData->DoNotFragment;\r
+\r
+  //\r
+  // Save the token into the TxToken map.\r
+  //\r
+  Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_PACKET;\r
+  }\r
+\r
+  //\r
+  // Send out this datagram through IpIo.\r
+  //\r
+  Status = IpIoSend (\r
+             Udp4Service->IpIo,\r
+             Packet,\r
+             Instance->IpInfo,\r
+             Instance,\r
+             Token,\r
+             Destination,\r
+             &Override\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Remove this token from the TxTokens.\r
+    //\r
+    Udp4RemoveToken (&Instance->TxTokens, Token);\r
+  }\r
+\r
+FREE_PACKET:\r
+\r
+  NetbufFree (Packet);\r
+\r
+ON_EXIT:\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function places a completion token into the receive packet queue. This function\r
+  is always asynchronous.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  Token                  Pointer to a token that is associated with the\r
+                                 receive data descriptor.\r
+\r
+  @retval EFI_SUCCESS            The receive completion token is cached.\r
+  @retval EFI_NOT_STARTED        This EFI UDPv4 Protocol instance has not been\r
+                                 started.\r
+  @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,\r
+                                 BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. Token is NULL. Token.Event is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES   The receive completion token could not be queued\r
+                                 due to a lack of system resources (usually\r
+                                 memory).\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+                                 The EFI UDPv4 Protocol instance has been reset to\r
+                                 startup defaults.\r
+  @retval EFI_ACCESS_DENIED      A receive completion token with the same\r
+                                 Token.Event is already in the receive queue.\r
+  @retval EFI_NOT_READY          The receive request could not be queued because\r
+                                 the receive  queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Receive (\r
+  IN EFI_UDP4_PROTOCOL          *This,\r
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_TPL             OldTpl;\r
+\r
+  if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (Instance->IsNoMapping) {\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))||\r
+    EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token))) {\r
+    //\r
+    // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or\r
+    // RxTokens map.\r
+    //\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Token->Packet.RxData = NULL;\r
+\r
+  //\r
+  // Save the token into the RxTokens map.\r
+  //\r
+  Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  //\r
+  // If there is an icmp error, report it.\r
+  //\r
+  Udp4ReportIcmpError (Instance);\r
+\r
+  //\r
+  // Try to delivered the received datagrams.\r
+  //\r
+  Udp4InstanceDeliverDgram (Instance);\r
+\r
+ON_EXIT:\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is used to abort a pending transmit or receive request.\r
+\r
+  @param  This                   Pointer to the EFI_UDP4_PROTOCOL instance.\r
+  @param  Token                  Pointer to a token that has been issued by\r
+                                 EFI_UDP4_PROTOCOL.Transmit() or\r
+                                 EFI_UDP4_PROTOCOL.Receive().\r
+\r
+  @retval EFI_SUCCESS            The asynchronous I/O request is aborted and\r
+                                 Token.Event is  signaled. When Token is NULL, all\r
+                                 pending requests are aborted and their events are\r
+                                 signaled.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+  @retval EFI_NOT_STARTED        This instance has not been started.\r
+  @retval EFI_NO_MAPPING         When using the default address, configuration\r
+                                 (DHCP, BOOTP, RARP, etc.) is not finished yet.\r
+  @retval EFI_NOT_FOUND          When Token is not NULL, the asynchronous I/O\r
+                                 request is not found in the transmit or receive\r
+                                 queue. It is either completed or not issued by\r
+                                 Transmit() or Receive().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Cancel (\r
+  IN EFI_UDP4_PROTOCOL          *This,\r
+  IN EFI_UDP4_COMPLETION_TOKEN  *Token OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_TPL             OldTpl;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (Instance->IsNoMapping) {\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  //\r
+  // Cancle the tokens specified by Token for this instance.\r
+  //\r
+  Status = Udp4InstanceCancelToken (Instance, Token);\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function can be used by network drivers and applications to increase the rate that\r
+  data packets are moved between the communications device and the transmit/receive queues.\r
+  Argumens:\r
+  This - Pointer to the EFI_UDP4_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS            Incoming or outgoing data was processed.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+  @retval EFI_TIMEOUT            Data was dropped out of the transmit and/or\r
+                                 receive queue.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Poll (\r
+  IN EFI_UDP4_PROTOCOL  *This\r
+  )\r
+{\r
+  UDP4_INSTANCE_DATA  *Instance;\r
+  EFI_IP4_PROTOCOL    *Ip;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+  Ip       = Instance->IpInfo->Ip;\r
+\r
+  //\r
+  // Invode the Ip instance consumed by the udp instance to do the poll operation.\r
+  //\r
+  return Ip->Poll (Ip);\r
+}\r