]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmulatorPkg/Win/Host/WinPacketFilter.c
EmulatorPkg/WinHost: Enable network support.
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinPacketFilter.c
diff --git a/EmulatorPkg/Win/Host/WinPacketFilter.c b/EmulatorPkg/Win/Host/WinPacketFilter.c
new file mode 100644 (file)
index 0000000..0b751f9
--- /dev/null
@@ -0,0 +1,1135 @@
+/**@file\r
+ Windows Packet Filter implementation of the EMU_SNP_PROTOCOL that allows the\r
+ emulator to get on real networks.\r
+\r
+Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r
+Portions copyright (c) 2011, Apple Inc. All rights reserved.\r
+(C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include "WinHost.h"\r
+\r
+#define NETWORK_LIBRARY_NAME_U          L"SnpNt32Io.dll"\r
+#define NETWORK_LIBRARY_INITIALIZE      "SnpInitialize"\r
+#define NETWORK_LIBRARY_FINALIZE        "SnpFinalize"\r
+#define NETWORK_LIBRARY_SET_RCV_FILTER  "SnpSetReceiveFilter"\r
+#define NETWORK_LIBRARY_RECEIVE         "SnpReceive"\r
+#define NETWORK_LIBRARY_TRANSMIT        "SnpTransmit"\r
+\r
+#pragma pack(1)\r
+typedef struct _NT_NET_INTERFACE_INFO {\r
+  UINT32          InterfaceIndex;\r
+  EFI_MAC_ADDRESS MacAddr;\r
+} NT_NET_INTERFACE_INFO;\r
+#pragma pack()\r
+\r
+#define NET_ETHER_HEADER_SIZE         14\r
+#define MAX_INTERFACE_INFO_NUMBER     16\r
+#define SNP_MAX_TX_BUFFER_NUM         65536\r
+#define SNP_TX_BUFFER_INCREASEMENT    32\r
+#define DEFAULT_SELECTED_NIC_INDEX    0\r
+\r
+//\r
+//  Functions in Net Library\r
+//\r
+typedef\r
+INT32\r
+(*NT_NET_INITIALIZE) (\r
+  IN OUT  UINT32                *InterfaceCount,\r
+  IN OUT  NT_NET_INTERFACE_INFO * InterfaceInfoBuffer\r
+  );\r
+\r
+typedef\r
+INT32\r
+(*NT_NET_FINALIZE) (\r
+  VOID\r
+  );\r
+\r
+typedef\r
+INT32\r
+(*NT_NET_SET_RECEIVE_FILTER) (\r
+  IN  UINT32                        Index,\r
+  IN  UINT32                        EnableFilter,\r
+  IN  UINT32                        MCastFilterCnt,\r
+  IN  EFI_MAC_ADDRESS               * MCastFilter\r
+  );\r
+\r
+typedef\r
+INT32\r
+(*NT_NET_RECEIVE) (\r
+  IN      UINT32                        Index,\r
+  IN OUT  UINT32                        *BufferSize,\r
+  OUT     VOID                          *Buffer\r
+  );\r
+\r
+typedef\r
+INT32\r
+(*NT_NET_TRANSMIT) (\r
+  IN  UINT32                        Index,\r
+  IN  UINT32                        HeaderSize,\r
+  IN  UINT32                        BufferSize,\r
+  IN  VOID                          *Buffer,\r
+  IN  EFI_MAC_ADDRESS               * SrcAddr,\r
+  IN  EFI_MAC_ADDRESS               * DestAddr,\r
+  IN  UINT16                        *Protocol\r
+  );\r
+\r
+typedef struct _NT_NET_UTILITY_TABLE {\r
+  NT_NET_INITIALIZE         Initialize;\r
+  NT_NET_FINALIZE           Finalize;\r
+  NT_NET_SET_RECEIVE_FILTER SetReceiveFilter;\r
+  NT_NET_RECEIVE            Receive;\r
+  NT_NET_TRANSMIT           Transmit;\r
+} NT_NET_UTILITY_TABLE;\r
+\r
+//\r
+//  Instance data for each fake SNP instance\r
+//\r
+#define WIN_NT_INSTANCE_SIGNATURE SIGNATURE_32 ('N', 'T', 'I', 'S')\r
+\r
+typedef struct  {\r
+  UINT32                      Signature;\r
+\r
+  //\r
+  // Array of the recycled transmit buffer address.\r
+  //\r
+  UINT64                      *RecycledTxBuf;\r
+\r
+  //\r
+  // Current number of recycled buffer pointers in RecycledTxBuf.\r
+  //\r
+  UINT32                      RecycledTxBufCount;\r
+\r
+  //\r
+  // The maximum number of recycled buffer pointers in RecycledTxBuf.\r
+  //\r
+  UINT32                      MaxRecycledTxBuf;\r
+  EFI_SIMPLE_NETWORK_MODE     Mode;\r
+  NT_NET_INTERFACE_INFO       InterfaceInfo;\r
+} WIN_NT_INSTANCE_DATA;\r
+\r
+//\r
+//  Instance data for each SNP private instance\r
+//\r
+#define WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 's', 'n')\r
+\r
+typedef struct {\r
+  UINTN                       Signature;\r
+  EMU_IO_THUNK_PROTOCOL       *Thunk;\r
+  EMU_SNP_PROTOCOL            EmuSnp;\r
+  EFI_SIMPLE_NETWORK_MODE     *Mode;\r
+  HMODULE                     NetworkLibraryHandle;\r
+  NT_NET_UTILITY_TABLE        NtNetUtilityTable;\r
+  WIN_NT_INSTANCE_DATA        Instance;\r
+} WIN_NT_SNP_PRIVATE;\r
+\r
+#define WIN_NT_SNP_PRIVATE_DATA_FROM_THIS(a) \\r
+         CR(a, WIN_NT_SNP_PRIVATE, EmuSnp, WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE)\r
+\r
+\r
+/**\r
+  Register storage for SNP Mode.\r
+\r
+  @param  This Protocol instance pointer.\r
+  @param  Mode SimpleNetworkProtocol Mode structure passed into driver.\r
+\r
+  @retval EFI_SUCCESS           The network interface was started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpCreateMapping (\r
+  IN     EMU_SNP_PROTOCOL         *This,\r
+  IN     EFI_SIMPLE_NETWORK_MODE  *Mode\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  Private->Mode = Mode;\r
+\r
+  //\r
+  // Set the broadcast address.\r
+  //\r
+  CopyMem (&Mode->BroadcastAddress, &Private->Instance.Mode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS));\r
+  //\r
+  // Set the MAC address.\r
+  //\r
+  CopyMem (&Mode->CurrentAddress, &Private->Instance.Mode.CurrentAddress, sizeof (EFI_MAC_ADDRESS));\r
+  CopyMem (&Mode->PermanentAddress, &Private->Instance.Mode.PermanentAddress, sizeof (EFI_MAC_ADDRESS));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Changes the state of a network interface from "stopped" to "started".\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS           The network interface was started.\r
+  @retval EFI_ALREADY_STARTED   The network interface is already in the started state.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpStart (\r
+  IN EMU_SNP_PROTOCOL  *This\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  switch (Private->Mode->State) {\r
+    case EfiSimpleNetworkStopped:\r
+      break;\r
+\r
+    case EfiSimpleNetworkStarted:\r
+    case EfiSimpleNetworkInitialized:\r
+      return EFI_ALREADY_STARTED;\r
+      break;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  Private->Mode->State = EfiSimpleNetworkStarted;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Changes the state of a network interface from "started" to "stopped".\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS           The network interface was stopped.\r
+  @retval EFI_ALREADY_STARTED   The network interface is already in the stopped state.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpStop (\r
+  IN EMU_SNP_PROTOCOL  *This\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  switch ( Private->Mode->State ) {\r
+    case EfiSimpleNetworkStarted:\r
+      break;\r
+\r
+    case EfiSimpleNetworkStopped:\r
+      return EFI_NOT_STARTED;\r
+      break;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  Private->Mode->State = EfiSimpleNetworkStopped;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a network adapter and allocates the transmit and receive buffers\r
+  required by the network interface; optionally, also requests allocation\r
+  of additional transmit and receive buffers.\r
+\r
+  @param  This              The protocol instance pointer.\r
+  @param  ExtraRxBufferSize The size, in bytes, of the extra receive buffer space\r
+                            that the driver should allocate for the network interface.\r
+                            Some network interfaces will not be able to use the extra\r
+                            buffer, and the caller will not know if it is actually\r
+                            being used.\r
+  @param  ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space\r
+                            that the driver should allocate for the network interface.\r
+                            Some network interfaces will not be able to use the extra\r
+                            buffer, and the caller will not know if it is actually\r
+                            being used.\r
+\r
+  @retval EFI_SUCCESS           The network interface was initialized.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_OUT_OF_RESOURCES  There was not enough memory for the transmit and\r
+                                receive buffers.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpInitialize (\r
+  IN EMU_SNP_PROTOCOL                    *This,\r
+  IN UINTN                               ExtraRxBufferSize  OPTIONAL,\r
+  IN UINTN                               ExtraTxBufferSize  OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  switch ( Private->Mode->State ) {\r
+    case EfiSimpleNetworkStarted:\r
+      break;\r
+\r
+    case EfiSimpleNetworkStopped:\r
+      return EFI_NOT_STARTED;\r
+      break;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  Private->Mode->MCastFilterCount = 0;\r
+  Private->Mode->ReceiveFilterSetting = 0;\r
+  ZeroMem (Private->Mode->MCastFilter, sizeof (Private->Mode->MCastFilter));\r
+\r
+  Private->Mode->State = EfiSimpleNetworkInitialized;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a network adapter and re-initializes it with the parameters that were\r
+  provided in the previous call to Initialize().\r
+\r
+  @param  This                 The protocol instance pointer.\r
+  @param  ExtendedVerification Indicates that the driver may perform a more\r
+                               exhaustive verification operation of the device\r
+                               during reset.\r
+\r
+  @retval EFI_SUCCESS           The network interface was reset.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpReset (\r
+  IN EMU_SNP_PROTOCOL   *This,\r
+  IN BOOLEAN            ExtendedVerification\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  switch ( Private->Mode->State ) {\r
+    case EfiSimpleNetworkInitialized:\r
+      break;\r
+\r
+    case EfiSimpleNetworkStopped:\r
+      return EFI_NOT_STARTED;\r
+      break;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a network adapter and leaves it in a state that is safe for\r
+  another driver to initialize.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS           The network interface was shutdown.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpShutdown (\r
+  IN EMU_SNP_PROTOCOL  *This\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  switch ( Private->Mode->State ) {\r
+    case EfiSimpleNetworkInitialized:\r
+      break;\r
+\r
+    case EfiSimpleNetworkStopped:\r
+      return EFI_NOT_STARTED;\r
+      break;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  Private->Mode->State = EfiSimpleNetworkStarted;\r
+\r
+  Private->Mode->ReceiveFilterSetting = 0;\r
+  Private->Mode->MCastFilterCount = 0;\r
+  ZeroMem (Private->Mode->MCastFilter, sizeof (Private->Mode->MCastFilter));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Manages the multicast receive filters of a network interface.\r
+\r
+  @param  This             The protocol instance pointer.\r
+  @param  Enable           A bit mask of receive filters to enable on the network interface.\r
+  @param  Disable          A bit mask of receive filters to disable on the network interface.\r
+  @param  ResetMCastFilter Set to TRUE to reset the contents of the multicast receive\r
+                           filters on the network interface to their default values.\r
+  @param  McastFilterCnt   Number of multicast HW MAC addresses in the new\r
+                           MCastFilter list. This value must be less than or equal to\r
+                           the MCastFilterCnt field of EMU_SNP_MODE. This\r
+                           field is optional if ResetMCastFilter is TRUE.\r
+  @param  MCastFilter      A pointer to a list of new multicast receive filter HW MAC\r
+                           addresses. This list will replace any existing multicast\r
+                           HW MAC address list. This field is optional if\r
+                           ResetMCastFilter is TRUE.\r
+\r
+  @retval EFI_SUCCESS           The multicast receive filter list was updated.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpReceiveFilters (\r
+  IN EMU_SNP_PROTOCOL                             *This,\r
+  IN UINT32                                       Enable,\r
+  IN UINT32                                       Disable,\r
+  IN BOOLEAN                                      ResetMCastFilter,\r
+  IN UINTN                                        MCastFilterCnt     OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                              *MCastFilter OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+  INT32                 ReturnValue;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  ReturnValue = Private->NtNetUtilityTable.SetReceiveFilter (\r
+                                                Private->Instance.InterfaceInfo.InterfaceIndex,\r
+                                                Enable,\r
+                                                (UINT32)MCastFilterCnt,\r
+                                                MCastFilter\r
+                                                );\r
+\r
+  if (ReturnValue <= 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Modifies or resets the current station address, if supported.\r
+\r
+  @param  This  The protocol instance pointer.\r
+  @param  Reset Flag used to reset the station address to the network interfaces\r
+                permanent address.\r
+  @param  New   The new station address to be used for the network interface.\r
+\r
+  @retval EFI_SUCCESS           The network interfaces station address was updated.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpStationAddress (\r
+  IN EMU_SNP_PROTOCOL            *This,\r
+  IN BOOLEAN                     Reset,\r
+  IN EFI_MAC_ADDRESS             *New OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Resets or collects the statistics on a network interface.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  Reset           Set to TRUE to reset the statistics for the network interface.\r
+  @param  StatisticsSize  On input the size, in bytes, of StatisticsTable. On\r
+                          output the size, in bytes, of the resulting table of\r
+                          statistics.\r
+  @param  StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that\r
+                          contains the statistics.\r
+\r
+  @retval EFI_SUCCESS           The statistics were collected from the network interface.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer\r
+                                size needed to hold the statistics is returned in\r
+                                StatisticsSize.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpStatistics (\r
+  IN EMU_SNP_PROTOCOL                     *This,\r
+  IN BOOLEAN                              Reset,\r
+  IN OUT UINTN                            *StatisticsSize   OPTIONAL,\r
+  OUT EFI_NETWORK_STATISTICS              *StatisticsTable  OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Converts a multicast IP address to a multicast HW MAC address.\r
+\r
+  @param  This The protocol instance pointer.\r
+  @param  IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set\r
+               to FALSE if the multicast IP address is IPv4 [RFC 791].\r
+  @param  IP   The multicast IP address that is to be converted to a multicast\r
+               HW MAC address.\r
+  @param  MAC  The multicast HW MAC address that is to be generated from IP.\r
+\r
+  @retval EFI_SUCCESS           The multicast IP address was mapped to the multicast\r
+                                HW MAC address.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_BUFFER_TOO_SMALL  The Statistics buffer was too small. The current buffer\r
+                                size needed to hold the statistics is returned in\r
+                                StatisticsSize.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpMCastIpToMac (\r
+  IN EMU_SNP_PROTOCOL                     *This,\r
+  IN BOOLEAN                              IPv6,\r
+  IN EFI_IP_ADDRESS                       *IP,\r
+  OUT EFI_MAC_ADDRESS                     *MAC\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Performs read and write operations on the NVRAM device attached to a\r
+  network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  ReadWrite  TRUE for read operations, FALSE for write operations.\r
+  @param  Offset     Byte offset in the NVRAM device at which to start the read or\r
+                     write operation. This must be a multiple of NvRamAccessSize and\r
+                     less than NvRamSize.\r
+  @param  BufferSize The number of bytes to read or write from the NVRAM device.\r
+                     This must also be a multiple of NvramAccessSize.\r
+  @param  Buffer     A pointer to the data buffer.\r
+\r
+  @retval EFI_SUCCESS           The NVRAM access was performed.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpNvData (\r
+  IN EMU_SNP_PROTOCOL                     *This,\r
+  IN BOOLEAN                              ReadWrite,\r
+  IN UINTN                                Offset,\r
+  IN UINTN                                BufferSize,\r
+  IN OUT VOID                             *Buffer\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Reads the current interrupt status and recycled transmit buffer status from\r
+  a network interface.\r
+\r
+  @param  This            The protocol instance pointer.\r
+  @param  InterruptStatus A pointer to the bit mask of the currently active interrupts\r
+                          If this is NULL, the interrupt status will not be read from\r
+                          the device. If this is not NULL, the interrupt status will\r
+                          be read from the device. When the  interrupt status is read,\r
+                          it will also be cleared. Clearing the transmit  interrupt\r
+                          does not empty the recycled transmit buffer array.\r
+  @param  TxBuf           Recycled transmit buffer address. The network interface will\r
+                          not transmit if its internal recycled transmit buffer array\r
+                          is full. Reading the transmit buffer does not clear the\r
+                          transmit interrupt. If this is NULL, then the transmit buffer\r
+                          status will not be read. If there are no transmit buffers to\r
+                          recycle and TxBuf is not NULL, * TxBuf will be set to NULL.\r
+\r
+  @retval EFI_SUCCESS           The status of the network interface was retrieved.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpGetStatus (\r
+  IN EMU_SNP_PROTOCOL                     *This,\r
+  OUT UINT32                              *InterruptStatus OPTIONAL,\r
+  OUT VOID                                **TxBuf OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (TxBuf != NULL) {\r
+    if (Private->Instance.RecycledTxBufCount != 0) {\r
+      Private->Instance.RecycledTxBufCount --;\r
+      *((UINT8 **) TxBuf)    = (UINT8 *) (UINTN)Private->Instance.RecycledTxBuf[Private->Instance.RecycledTxBufCount];\r
+    } else {\r
+      *((UINT8 **) TxBuf)    = NULL;\r
+    }\r
+  }\r
+\r
+  if (InterruptStatus != NULL) {\r
+    *InterruptStatus = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Places a packet in the transmit queue of a network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header to be filled in by\r
+                     the Transmit() function. If HeaderSize is non-zero, then it\r
+                     must be equal to This->Mode->MediaHeaderSize and the DestAddr\r
+                     and Protocol parameters must not be NULL.\r
+  @param  BufferSize The size, in bytes, of the entire packet (media header and\r
+                     data) to be transmitted through the network interface.\r
+  @param  Buffer     A pointer to the packet (media header followed by data) to be\r
+                     transmitted. This parameter cannot be NULL. If HeaderSize is zero,\r
+                     then the media header in Buffer must already be filled in by the\r
+                     caller. If HeaderSize is non-zero, then the media header will be\r
+                     filled in by the Transmit() function.\r
+  @param  SrcAddr    The source HW MAC address. If HeaderSize is zero, then this parameter\r
+                     is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then\r
+                     This->Mode->CurrentAddress is used for the source HW MAC address.\r
+  @param  DestAddr   The destination HW MAC address. If HeaderSize is zero, then this\r
+                     parameter is ignored.\r
+  @param  Protocol   The type of header to build. If HeaderSize is zero, then this\r
+                     parameter is ignored. See RFC 1700, section "Ether Types", for\r
+                     examples.\r
+\r
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpTransmit (\r
+  IN EMU_SNP_PROTOCOL                     *This,\r
+  IN UINTN                                HeaderSize,\r
+  IN UINTN                                BufferSize,\r
+  IN VOID                                 *Buffer,\r
+  IN EFI_MAC_ADDRESS                      *SrcAddr  OPTIONAL,\r
+  IN EFI_MAC_ADDRESS                      *DestAddr OPTIONAL,\r
+  IN UINT16                               *Protocol OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+  INT32                 ReturnValue;\r
+  UINT64                *Tmp;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if ((HeaderSize != 0) && (SrcAddr == NULL)) {\r
+    SrcAddr = &Private->Instance.Mode.CurrentAddress;\r
+  }\r
+\r
+  ReturnValue = Private->NtNetUtilityTable.Transmit (\r
+                                                Private->Instance.InterfaceInfo.InterfaceIndex,\r
+                                                (UINT32)HeaderSize,\r
+                                                (UINT32)BufferSize,\r
+                                                Buffer,\r
+                                                SrcAddr,\r
+                                                DestAddr,\r
+                                                Protocol\r
+                                                );\r
+\r
+  if (ReturnValue < 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  } else {\r
+    if ((Private->Instance.MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) {\r
+      return EFI_NOT_READY;\r
+    }\r
+\r
+    if (Private->Instance.RecycledTxBufCount < Private->Instance.MaxRecycledTxBuf) {\r
+      Private->Instance.RecycledTxBuf[Private->Instance.RecycledTxBufCount] = (UINT64) Buffer;\r
+      Private->Instance.RecycledTxBufCount ++;\r
+    } else {\r
+      Tmp = malloc (sizeof (UINT64) * (Private->Instance.MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT));\r
+      if (Tmp == NULL) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      CopyMem (Tmp, Private->Instance.RecycledTxBuf, sizeof (UINT64) * Private->Instance.RecycledTxBufCount);\r
+      free (Private->Instance.RecycledTxBuf);\r
+      Private->Instance.RecycledTxBuf    =  Tmp;\r
+      Private->Instance.MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Receives a packet from a network interface.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  HeaderSize The size, in bytes, of the media header received on the network\r
+                     interface. If this parameter is NULL, then the media header size\r
+                     will not be returned.\r
+  @param  BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in\r
+                     bytes, of the packet that was received on the network interface.\r
+  @param  Buffer     A pointer to the data buffer to receive both the media header and\r
+                     the data.\r
+  @param  SrcAddr    The source HW MAC address. If this parameter is NULL, the\r
+                     HW MAC source address will not be extracted from the media\r
+                     header.\r
+  @param  DestAddr   The destination HW MAC address. If this parameter is NULL,\r
+                     the HW MAC destination address will not be extracted from the\r
+                     media header.\r
+  @param  Protocol   The media header type. If this parameter is NULL, then the\r
+                     protocol will not be extracted from the media header. See\r
+                     RFC 1700 section "Ether Types" for examples.\r
+\r
+  @retval  EFI_SUCCESS           The received data was stored in Buffer, and BufferSize has\r
+                                 been updated to the number of bytes received.\r
+  @retval  EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval  EFI_NOT_READY         The network interface is too busy to accept this transmit\r
+                                 request.\r
+  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval  EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.\r
+  @retval  EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval  EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpReceive (\r
+  IN EMU_SNP_PROTOCOL                     *This,\r
+  OUT UINTN                               *HeaderSize OPTIONAL,\r
+  IN OUT UINTN                            *BufferSize,\r
+  OUT VOID                                *Buffer,\r
+  OUT EFI_MAC_ADDRESS                     *SrcAddr    OPTIONAL,\r
+  OUT EFI_MAC_ADDRESS                     *DestAddr   OPTIONAL,\r
+  OUT UINT16                              *Protocol   OPTIONAL\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE    *Private;\r
+  INT32                 ReturnValue;\r
+  UINTN                 BufSize;\r
+\r
+  Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  BufSize     = *BufferSize;\r
+\r
+  ASSERT (Private->NtNetUtilityTable.Receive != NULL);\r
+\r
+  ReturnValue = Private->NtNetUtilityTable.Receive (\r
+                                                Private->Instance.InterfaceInfo.InterfaceIndex,\r
+                                                BufferSize,\r
+                                                Buffer\r
+                                                );\r
+\r
+  if (ReturnValue < 0) {\r
+    if (ReturnValue == -100) {\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  } else if (ReturnValue == 0) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  if (HeaderSize != NULL) {\r
+    *HeaderSize = 14;\r
+  }\r
+\r
+  if (SrcAddr != NULL) {\r
+    ZeroMem (SrcAddr, sizeof (EFI_MAC_ADDRESS));\r
+    CopyMem (SrcAddr, ((UINT8 *) Buffer) + 6, 6);\r
+  }\r
+\r
+  if (DestAddr != NULL) {\r
+    ZeroMem (DestAddr, sizeof (EFI_MAC_ADDRESS));\r
+    CopyMem (DestAddr, ((UINT8 *) Buffer), 6);\r
+  }\r
+\r
+  if (Protocol != NULL) {\r
+    *Protocol = NTOHS (*((UINT16 *) (((UINT8 *) Buffer) + 12)));\r
+  }\r
+\r
+  return (*BufferSize <= BufSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
+}\r
+\r
+/**\r
+  Initialize the snpnt32 driver instance.\r
+\r
+  @param  Instance              Pointer to the instance context data.\r
+  @param  NetInfo               Pointer to the interface info.\r
+\r
+  @retval EFI_SUCCESS           The driver instance is initialized.\r
+  @retval other                 Initialization errors.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtInitializeInstanceData (\r
+  IN OUT WIN_NT_INSTANCE_DATA  *Instance,\r
+  IN     NT_NET_INTERFACE_INFO *NetInfo\r
+  )\r
+{\r
+  if (Instance == NULL || NetInfo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (Instance, sizeof (WIN_NT_INSTANCE_DATA));\r
+\r
+  Instance->Signature = WIN_NT_INSTANCE_SIGNATURE;\r
+  Instance->RecycledTxBufCount = 0;\r
+  Instance->MaxRecycledTxBuf = 32;\r
+  Instance->Mode.State = EfiSimpleNetworkInitialized;\r
+  Instance->Mode.HwAddressSize = NET_ETHER_ADDR_LEN;\r
+  Instance->Mode.MediaHeaderSize = NET_ETHER_HEADER_SIZE;\r
+  Instance->Mode.MaxPacketSize = 1500;\r
+  Instance->Mode.MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;\r
+  Instance->Mode.IfType = NET_IFTYPE_ETHERNET;\r
+  Instance->Mode.MediaPresentSupported = TRUE;\r
+  Instance->Mode.MediaPresent = TRUE;\r
+\r
+  //\r
+  // Allocate the RecycledTxBuf.\r
+  //\r
+  Instance->RecycledTxBuf = malloc (sizeof (UINT64) * Instance->MaxRecycledTxBuf);\r
+  if (Instance->RecycledTxBuf == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  //  Set the interface information.\r
+  //\r
+  CopyMem (&Instance->InterfaceInfo, NetInfo, sizeof (Instance->InterfaceInfo));\r
+\r
+\r
+  //\r
+  //  Set broadcast address\r
+  //\r
+  SetMem (&Instance->Mode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);\r
+\r
+  //\r
+  //  Copy Current/PermanentAddress MAC address\r
+  //\r
+  CopyMem (&Instance->Mode.CurrentAddress, &Instance->InterfaceInfo.MacAddr, sizeof(Instance->Mode.CurrentAddress));\r
+  CopyMem (&Instance->Mode.PermanentAddress, &Instance->InterfaceInfo.MacAddr, sizeof(Instance->Mode.PermanentAddress));\r
+\r
+  //\r
+  //  Since the fake SNP is based on a real NIC, to avoid conflict with the host\r
+  //  NIC network stack, we use a different MAC address.\r
+  //  So just change the last byte of the MAC address for the real NIC.\r
+  //\r
+  Instance->Mode.CurrentAddress.Addr[NET_ETHER_ADDR_LEN - 1]++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize the net utility data.\r
+\r
+  @param  This                  Pointer to the private data.\r
+  @param  ActiveInstance        The active network interface.\r
+\r
+  @retval EFI_SUCCESS           The global data is initialized.\r
+  @retval EFI_NOT_FOUND         The required DLL is not found.\r
+  @retval EFI_DEVICE_ERROR      Error initialize network utility library.\r
+  @retval other                 Other errors.\r
+\r
+**/\r
+EFI_STATUS\r
+WintNtInitializeNetUtilityData (\r
+  IN OUT WIN_NT_SNP_PRIVATE *Private,\r
+  IN UINT8                   ActiveInstance\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  CHAR16                *DllFileNameU;\r
+  INT32                 ReturnValue;\r
+  BOOLEAN               NetUtilityLibInitDone;\r
+  NT_NET_INTERFACE_INFO NetInterfaceInfoBuffer[MAX_INTERFACE_INFO_NUMBER];\r
+  UINT32                InterfaceCount;\r
+  UINT8                 ActiveInterfaceIndex;\r
+\r
+  if (Private == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NetUtilityLibInitDone = FALSE;\r
+  InterfaceCount        = MAX_INTERFACE_INFO_NUMBER;\r
+  DllFileNameU          = NETWORK_LIBRARY_NAME_U;\r
+\r
+  //\r
+  //  Load network utility library\r
+  //\r
+  Private->NetworkLibraryHandle = LoadLibraryEx (DllFileNameU, NULL, 0);\r
+  if (NULL == Private->NetworkLibraryHandle) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Private->NtNetUtilityTable.Initialize = (NT_NET_INITIALIZE) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_INITIALIZE);\r
+  if (NULL == Private->NtNetUtilityTable.Initialize) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  Private->NtNetUtilityTable.Finalize = (NT_NET_FINALIZE) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_FINALIZE);\r
+  if (NULL == Private->NtNetUtilityTable.Finalize) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  Private->NtNetUtilityTable.SetReceiveFilter = (NT_NET_SET_RECEIVE_FILTER) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_SET_RCV_FILTER);\r
+  if (NULL == Private->NtNetUtilityTable.SetReceiveFilter) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  Private->NtNetUtilityTable.Receive = (NT_NET_RECEIVE) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_RECEIVE);\r
+  if (NULL == Private->NtNetUtilityTable.Receive) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  Private->NtNetUtilityTable.Transmit = (NT_NET_TRANSMIT) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_TRANSMIT);\r
+  if (NULL == Private->NtNetUtilityTable.Transmit) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  //\r
+  //  Initialize the network utility library\r
+  //  And enumerate the interfaces in emulator host\r
+  //\r
+  ReturnValue = Private->NtNetUtilityTable.Initialize (&InterfaceCount, &NetInterfaceInfoBuffer[0]);\r
+  if (ReturnValue <= 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  NetUtilityLibInitDone = TRUE;\r
+\r
+  if (InterfaceCount == 0) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ErrorReturn;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a, total %d interface(s) found\n", __FUNCTION__, InterfaceCount));\r
+  //\r
+  // Active interface index is set to first interface if given instance does\r
+  // not exist.\r
+  //\r
+  ActiveInterfaceIndex = (ActiveInstance >= InterfaceCount ? DEFAULT_SELECTED_NIC_INDEX : ActiveInstance);\r
+\r
+  //\r
+  // Initialize instance\r
+  //\r
+  Status = WinNtInitializeInstanceData (&Private->Instance, &NetInterfaceInfoBuffer[ActiveInterfaceIndex]);\r
+  if (EFI_ERROR (Status)) {\r
+      goto ErrorReturn;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ErrorReturn:\r
+\r
+  if (Private->Instance.RecycledTxBuf != NULL) {\r
+      free (Private->Instance.RecycledTxBuf);\r
+  }\r
+\r
+  if (NetUtilityLibInitDone) {\r
+    if (Private->NtNetUtilityTable.Finalize != NULL) {\r
+      Private->NtNetUtilityTable.Finalize ();\r
+      Private->NtNetUtilityTable.Finalize = NULL;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Release the net utility data.\r
+\r
+  @param  This                  Pointer to the private data.\r
+\r
+  @retval EFI_SUCCESS           The global data is released.\r
+  @retval other                 Other errors.\r
+\r
+**/\r
+EFI_STATUS\r
+WintNtReleaseNetUtilityData (\r
+  IN OUT WIN_NT_SNP_PRIVATE *Private\r
+  )\r
+{\r
+  if (Private == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Private->Instance.RecycledTxBuf != NULL) {\r
+      free (Private->Instance.RecycledTxBuf);\r
+  }\r
+\r
+  if (Private->NtNetUtilityTable.Finalize != NULL) {\r
+    Private->NtNetUtilityTable.Finalize ();\r
+  }\r
+\r
+  FreeLibrary (Private->NetworkLibraryHandle);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EMU_SNP_PROTOCOL mWinNtSnpProtocol = {\r
+  WinNtSnpCreateMapping,\r
+  WinNtSnpStart,\r
+  WinNtSnpStop,\r
+  WinNtSnpInitialize,\r
+  WinNtSnpReset,\r
+  WinNtSnpShutdown,\r
+  WinNtSnpReceiveFilters,\r
+  WinNtSnpStationAddress,\r
+  WinNtSnpStatistics,\r
+  WinNtSnpMCastIpToMac,\r
+  WinNtSnpNvData,\r
+  WinNtSnpGetStatus,\r
+  WinNtSnpTransmit,\r
+  WinNtSnpReceive\r
+};\r
+\r
+/**\r
+  Open SNP thunk protocol.\r
+\r
+  @param  This                  Pointer to the thunk protocol instance.\r
+\r
+  @retval EFI_SUCCESS           SNP thunk protocol is opened successfully.\r
+  @retval EFI_UNSUPPORTED       This is not SNP thunk protocol.\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.\r
+  @retval other                 Other errors.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpThunkOpen (\r
+  IN  EMU_IO_THUNK_PROTOCOL   *This\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE  *Private;\r
+  UINT8               HostInterfaceIndex;\r
+\r
+  HostInterfaceIndex = 0;\r
+\r
+  if (This->Private != NULL) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  if (!CompareGuid (This->Protocol, &gEmuSnpProtocolGuid)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Private = malloc (sizeof (WIN_NT_SNP_PRIVATE));\r
+  if (Private == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Signature = WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE;\r
+  Private->Thunk     = This;\r
+  CopyMem (&Private->EmuSnp, &mWinNtSnpProtocol, sizeof (mWinNtSnpProtocol));\r
+\r
+  This->Interface = &Private->EmuSnp;\r
+  This->Private   = Private;\r
+\r
+  if (This->ConfigString != NULL && This->ConfigString[0] != '\0') {\r
+    HostInterfaceIndex = (UINT8)StrDecimalToUintn (This->ConfigString);\r
+  }\r
+\r
+  return WintNtInitializeNetUtilityData (Private, HostInterfaceIndex);\r
+}\r
+\r
+/**\r
+  Close SNP thunk protocol.\r
+\r
+  @param  This                  Pointer to the thunk protocol instance.\r
+\r
+  @retval EFI_SUCCESS           SNP thunk protocol is closed successfully.\r
+  @retval EFI_UNSUPPORTED       This is not SNP thunk protocol.\r
+  @retval other                 Other errors.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtSnpThunkClose (\r
+  IN  EMU_IO_THUNK_PROTOCOL   *This\r
+  )\r
+{\r
+  WIN_NT_SNP_PRIVATE  *Private;\r
+\r
+  if (!CompareGuid (This->Protocol, &gEmuSnpProtocolGuid)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Private = This->Private;\r
+  WintNtReleaseNetUtilityData (Private);\r
+  free (Private);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EMU_IO_THUNK_PROTOCOL mWinNtSnpThunkIo = {\r
+  &gEmuSnpProtocolGuid,\r
+  NULL,\r
+  NULL,\r
+  0,\r
+  WinNtSnpThunkOpen,\r
+  WinNtSnpThunkClose,\r
+  NULL\r
+};\r