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 15cfbf8..894e07b 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 215a2fb..6bc3431 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 9430d8a..f7aa52a 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 be9ff1b..3ae0a04 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 421eaa0..3b28698 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 b461ecc..4947db5 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
+&nb