summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/SnpDxe
diff options
context:
space:
mode:
authorLiming Gao <liming.gao@intel.com>2019-05-15 20:02:18 +0800
committerLiming Gao <liming.gao@intel.com>2019-05-27 09:25:18 +0800
commit4542f8b8135f1f1ee5654e25139be9769e139ddd (patch)
tree6e05d7c624d89b3df27d0d3437815a2587f0640f /NetworkPkg/SnpDxe
parentc0fd7f734e2d33e22215899b40a47b843129541d (diff)
downloadedk2-4542f8b8135f1f1ee5654e25139be9769e139ddd.tar.gz
edk2-4542f8b8135f1f1ee5654e25139be9769e139ddd.tar.bz2
edk2-4542f8b8135f1f1ee5654e25139be9769e139ddd.zip
NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
Signed-off-by: Liming Gao <liming.gao@intel.com> Cc: Siyuan Fu <siyuan.fu@intel.com> Cc: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
Diffstat (limited to 'NetworkPkg/SnpDxe')
-rw-r--r--NetworkPkg/SnpDxe/Callback.c354
-rw-r--r--NetworkPkg/SnpDxe/ComponentName.c430
-rw-r--r--NetworkPkg/SnpDxe/Get_status.c257
-rw-r--r--NetworkPkg/SnpDxe/Initialize.c277
-rw-r--r--NetworkPkg/SnpDxe/Mcast_ip_to_mac.c173
-rw-r--r--NetworkPkg/SnpDxe/Nvdata.c217
-rw-r--r--NetworkPkg/SnpDxe/Receive.c251
-rw-r--r--NetworkPkg/SnpDxe/Receive_filters.c478
-rw-r--r--NetworkPkg/SnpDxe/Reset.c130
-rw-r--r--NetworkPkg/SnpDxe/Shutdown.c146
-rw-r--r--NetworkPkg/SnpDxe/Snp.c862
-rw-r--r--NetworkPkg/SnpDxe/Snp.h1033
-rw-r--r--NetworkPkg/SnpDxe/SnpDxe.inf77
-rw-r--r--NetworkPkg/SnpDxe/SnpDxe.uni17
-rw-r--r--NetworkPkg/SnpDxe/SnpDxeExtra.uni14
-rw-r--r--NetworkPkg/SnpDxe/Start.c162
-rw-r--r--NetworkPkg/SnpDxe/Station_address.c243
-rw-r--r--NetworkPkg/SnpDxe/Statistics.c224
-rw-r--r--NetworkPkg/SnpDxe/Stop.c120
-rw-r--r--NetworkPkg/SnpDxe/Transmit.c353
-rw-r--r--NetworkPkg/SnpDxe/WaitForPacket.c86
21 files changed, 5904 insertions, 0 deletions
diff --git a/NetworkPkg/SnpDxe/Callback.c b/NetworkPkg/SnpDxe/Callback.c
new file mode 100644
index 0000000000..6387dbdb35
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Callback.c
@@ -0,0 +1,354 @@
+/** @file
+ This file contains the callback routines for undi3.1.
+ the callback routines for Undi3.1 have an extra parameter UniqueId which
+ stores the interface context for the NIC that snp is trying to talk.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+/**
+ Acquire or release a lock of the exclusive access to a critical section of the
+ code/data.
+
+ This is a callback routine supplied to UNDI3.1 at undi_start time.
+ New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1
+ because undi3.1 uses the MemMap call to map the required address by itself!
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store Undi interface context (Undi does not read or write
+ this variable).
+ @param Enable Non-zero indicates acquire; Zero indicates release.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackBlock (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ )
+{
+ SNP_DRIVER *Snp;
+
+ Snp = (SNP_DRIVER *) (UINTN) UniqueId;
+ //
+ // tcpip was calling snp at tpl_notify and when we acquire a lock that was
+ // created at a lower level (TPL_CALLBACK) it gives an assert!
+ //
+ if (Enable != 0) {
+ EfiAcquireLock (&Snp->Lock);
+ } else {
+ EfiReleaseLock (&Snp->Lock);
+ }
+}
+
+/**
+ Delay MicroSeconds of micro seconds.
+
+ This is a callback routine supplied to UNDI at undi_start time.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store Undi interface context (Undi does not read or write
+ this variable).
+ @param MicroSeconds Number of micro seconds to pause, ususlly multiple of 10.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackDelay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ )
+{
+ if (MicroSeconds != 0) {
+ gBS->Stall ((UINTN) MicroSeconds);
+ }
+}
+
+/**
+ IO routine for UNDI3.1.
+
+ This is a callback routine supplied to UNDI at undi_start time.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this
+ to store Undi interface context (Undi does not read or
+ write this variable).
+ @param ReadOrWrite Indicates read or write, IO or Memory.
+ @param NumBytes Number of bytes to read or write.
+ @param MemOrPortAddr IO or memory address to read from or write to.
+ @param BufferPtr Memory location to read into or that contains the bytes
+ to write.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackMemio (
+ IN UINT64 UniqueId,
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddr,
+ IN OUT UINT64 BufferPtr
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ Snp = (SNP_DRIVER *) (UINTN) UniqueId;
+
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
+ switch (NumBytes) {
+ case 2:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
+ break;
+
+ case 4:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
+ break;
+
+ case 8:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
+ break;
+ }
+
+ switch (ReadOrWrite) {
+ case PXE_IO_READ:
+ Snp->PciIo->Io.Read (
+ Snp->PciIo,
+ Width,
+ Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
+ MemOrPortAddr,
+ 1, // count
+ (VOID *) (UINTN) BufferPtr
+ );
+ break;
+
+ case PXE_IO_WRITE:
+ Snp->PciIo->Io.Write (
+ Snp->PciIo,
+ Width,
+ Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
+ MemOrPortAddr,
+ 1, // count
+ (VOID *) (UINTN) BufferPtr
+ );
+ break;
+
+ case PXE_MEM_READ:
+ Snp->PciIo->Mem.Read (
+ Snp->PciIo,
+ Width,
+ Snp->MemoryBarIndex, // BAR 0, Memory base address
+ MemOrPortAddr,
+ 1, // count
+ (VOID *) (UINTN) BufferPtr
+ );
+ break;
+
+ case PXE_MEM_WRITE:
+ Snp->PciIo->Mem.Write (
+ Snp->PciIo,
+ Width,
+ Snp->MemoryBarIndex, // BAR 0, Memory base address
+ MemOrPortAddr,
+ 1, // count
+ (VOID *) (UINTN) BufferPtr
+ );
+ break;
+ }
+
+ return ;
+}
+
+/**
+ Map a CPU address to a device address.
+
+ This is a callback routine supplied to UNDI at undi_start time.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store Undi interface context (Undi does not read or write
+ this variable).
+ @param CpuAddr Virtual address to be mapped.
+ @param NumBytes Size of memory to be mapped.
+ @param Direction Direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways.
+ @param DeviceAddrPtr Pointer to return the mapped device address.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackMap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+{
+ EFI_PHYSICAL_ADDRESS *DevAddrPtr;
+ EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
+ UINTN BuffSize;
+ SNP_DRIVER *Snp;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ BuffSize = (UINTN) NumBytes;
+ Snp = (SNP_DRIVER *) (UINTN) UniqueId;
+ DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
+
+ if (CpuAddr == 0) {
+ *DevAddrPtr = 0;
+ return ;
+ }
+
+ switch (Direction) {
+ case TO_AND_FROM_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
+ break;
+
+ case FROM_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterWrite;
+ break;
+
+ case TO_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterRead;
+ break;
+
+ default:
+ *DevAddrPtr = 0;
+ //
+ // any non zero indicates error!
+ //
+ return ;
+ }
+ //
+ // find an unused map_list entry
+ //
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ if (Snp->MapList[Index].VirtualAddress == 0) {
+ break;
+ }
+ }
+
+ if (Index >= MAX_MAP_LENGTH) {
+ DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
+ *DevAddrPtr = 0;
+ return ;
+ }
+
+ Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;
+
+ Status = Snp->PciIo->Map (
+ Snp->PciIo,
+ DirectionFlag,
+ (VOID *) (UINTN) CpuAddr,
+ &BuffSize,
+ DevAddrPtr,
+ &(Snp->MapList[Index].MapCookie)
+ );
+ if (Status != EFI_SUCCESS) {
+ *DevAddrPtr = 0;
+ Snp->MapList[Index].VirtualAddress = 0;
+ }
+
+ return ;
+}
+
+/**
+ Unmap an address that was previously mapped using map callback.
+
+ This is a callback routine supplied to UNDI at undi_start time.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store. Undi interface context (Undi does not read or write
+ this variable).
+ @param CpuAddr Virtual address that was mapped.
+ @param NumBytes Size of memory mapped.
+ @param Direction Direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways.
+ @param DeviceAddr The mapped device address.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackUnmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr
+ )
+{
+ SNP_DRIVER *Snp;
+ UINT16 Index;
+
+ Snp = (SNP_DRIVER *) (UINTN) UniqueId;
+
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ if (Snp->MapList[Index].VirtualAddress == CpuAddr) {
+ break;
+ }
+ }
+
+ if (Index >= MAX_MAP_LENGTH) {
+ DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
+ return ;
+ }
+
+ Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);
+ Snp->MapList[Index].VirtualAddress = 0;
+ Snp->MapList[Index].MapCookie = NULL;
+ return ;
+}
+
+/**
+ Synchronize the virtual buffer contents with the mapped buffer contents.
+
+ This is a callback routine supplied to UNDI at undi_start time. The virtual
+ and mapped buffers need not correspond to the same physical memory (especially
+ if the virtual address is > 4GB). Depending on the direction for which the
+ buffer is mapped, undi will need to synchronize their contents whenever it
+ writes to/reads from the buffer using either the cpu address or the device
+ address.
+ EFI does not provide a sync call since virt=physical, we should just do the
+ synchronization ourselves here.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store Undi interface context (Undi does not read or write
+ this variable).
+ @param CpuAddr Virtual address that was mapped.
+ @param NumBytes Size of memory mapped.
+ @param Direction Direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways.
+ @param DeviceAddr The mapped device address.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackSync (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr
+ )
+{
+ if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
+ return ;
+
+ }
+
+ switch (Direction) {
+ case FROM_DEVICE:
+ CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
+ break;
+
+ case TO_DEVICE:
+ CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
+ break;
+ }
+
+ return ;
+}
diff --git a/NetworkPkg/SnpDxe/ComponentName.c b/NetworkPkg/SnpDxe/ComponentName.c
new file mode 100644
index 0000000000..2139e2a47f
--- /dev/null
+++ b/NetworkPkg/SnpDxe/ComponentName.c
@@ -0,0 +1,430 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SnpDxe driver.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Snp.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName = {
+ SimpleNetworkComponentNameGetDriverName,
+ SimpleNetworkComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSimpleNetworkComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SimpleNetworkComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SimpleNetworkComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Simple Network Protocol Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gSimpleNetworkControllerNameTable = NULL;
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSimpleNetworkDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSimpleNetworkComponentName)
+ );
+}
+
+/**
+ Update the component name for the Snp child handle.
+
+ @param Snp[in] A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL.
+
+
+ @retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully.
+ @retval EFI_INVALID_PARAMETER The input parameter is invalid.
+
+**/
+EFI_STATUS
+UpdateName (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 HandleName[80];
+ UINTN OffSet;
+ UINTN Index;
+
+ if (Snp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OffSet = 0;
+ OffSet += UnicodeSPrint (
+ HandleName,
+ sizeof (HandleName),
+ L"SNP (MAC="
+ );
+ for (Index = 0; Index < Snp->Mode->HwAddressSize; Index++) {
+ OffSet += UnicodeSPrint (
+ HandleName + OffSet,
+ sizeof (HandleName) - OffSet * sizeof (CHAR16),
+ L"%02X-",
+ Snp->Mode->CurrentAddress.Addr[Index]
+ );
+ }
+ ASSERT (OffSet > 0);
+ //
+ // Remove the last '-'
+ //
+ OffSet--;
+ OffSet += UnicodeSPrint (
+ HandleName + OffSet,
+ sizeof (HandleName) - OffSet * sizeof (CHAR16),
+ L")"
+ );
+ if (gSimpleNetworkControllerNameTable != NULL) {
+ FreeUnicodeStringTable (gSimpleNetworkControllerNameTable);
+ gSimpleNetworkControllerNameTable = NULL;
+ }
+
+ Status = AddUnicodeString2 (
+ "eng",
+ gSimpleNetworkComponentName.SupportedLanguages,
+ &gSimpleNetworkControllerNameTable,
+ HandleName,
+ TRUE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return AddUnicodeString2 (
+ "en",
+ gSimpleNetworkComponentName2.SupportedLanguages,
+ &gSimpleNetworkControllerNameTable,
+ HandleName,
+ FALSE
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+ Currently not implemented.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSimpleNetworkDriverBinding.DriverBindingHandle,
+ &gEfiSimpleNetworkProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Retrieve an instance of a produced protocol from ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **)&Snp,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Update the component name for this child handle.
+ //
+ Status = UpdateName (Snp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ gSimpleNetworkControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSimpleNetworkComponentName)
+ );
+}
diff --git a/NetworkPkg/SnpDxe/Get_status.c b/NetworkPkg/SnpDxe/Get_status.c
new file mode 100644
index 0000000000..be6608a0b3
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Get_status.c
@@ -0,0 +1,257 @@
+/** @file
+ Implementation of reading the current interrupt status and recycled transmit
+ buffer status from a network interface.
+
+Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+/**
+ Call undi to get the status of the interrupts, get the list of recycled transmit
+ buffers that completed transmitting. The recycled transmit buffer address will
+ be saved into Snp->RecycledTxBuf. This function will also update the MediaPresent
+ field of EFI_SIMPLE_NETWORK_MODE if UNDI support it.
+
+ @param[in] Snp Pointer to snp driver structure.
+ @param[out] InterruptStatusPtr A non null pointer to contain the interrupt
+ status.
+ @param[in] GetTransmittedBuf Set to TRUE to retrieve the recycled transmit
+ buffer address.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+
+**/
+EFI_STATUS
+PxeGetStatus (
+ IN SNP_DRIVER *Snp,
+ OUT UINT32 *InterruptStatusPtr,
+ IN BOOLEAN GetTransmittedBuf
+ )
+{
+ PXE_DB_GET_STATUS *Db;
+ UINT16 InterruptFlags;
+ UINT32 Index;
+ UINT64 *Tmp;
+
+ Tmp = NULL;
+ Db = Snp->Db;
+ Snp->Cdb.OpCode = PXE_OPCODE_GET_STATUS;
+
+ Snp->Cdb.OpFlags = 0;
+
+ if (GetTransmittedBuf) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;
+ ZeroMem (Db->TxBuffer, sizeof (Db->TxBuffer));
+ }
+
+ if (InterruptStatusPtr != NULL) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;
+ }
+
+ if (Snp->MediaStatusSupported) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_MEDIA_STATUS;
+ }
+
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_GET_STATUS);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nSnp->undi.get_status() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_NET,
+ "\nSnp->undi.get_status() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // report the values back..
+ //
+ if (InterruptStatusPtr != NULL) {
+ InterruptFlags = (UINT16) (Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);
+
+ *InterruptStatusPtr = 0;
+
+ if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) == PXE_STATFLAGS_GET_STATUS_RECEIVE) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ }
+
+ if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) == PXE_STATFLAGS_GET_STATUS_TRANSMIT) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+
+ if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) == PXE_STATFLAGS_GET_STATUS_COMMAND) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
+ }
+
+ if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) == PXE_STATFLAGS_GET_STATUS_SOFTWARE) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
+ }
+
+ }
+
+ if (GetTransmittedBuf) {
+ if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) == 0) {
+ //
+ // UNDI has written some transmitted buffer addresses into the DB. Store them into Snp->RecycledTxBuf.
+ //
+ for (Index = 0; Index < MAX_XMIT_BUFFERS; Index++) {
+ if (Db->TxBuffer[Index] != 0) {
+ if (Snp->RecycledTxBufCount == Snp->MaxRecycledTxBuf) {
+ //
+ // Snp->RecycledTxBuf is full, reallocate a new one.
+ //
+ if ((Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) {
+ return EFI_DEVICE_ERROR;
+ }
+ Tmp = AllocatePool (sizeof (UINT64) * (Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT));
+ if (Tmp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ CopyMem (Tmp, Snp->RecycledTxBuf, sizeof (UINT64) * Snp->RecycledTxBufCount);
+ FreePool (Snp->RecycledTxBuf);
+ Snp->RecycledTxBuf = Tmp;
+ Snp->MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT;
+ }
+ Snp->RecycledTxBuf[Snp->RecycledTxBufCount] = Db->TxBuffer[Index];
+ Snp->RecycledTxBufCount++;
+ }
+ }
+ }
+ }
+
+ //
+ // Update MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support
+ // returning media status from GET_STATUS command
+ //
+ if (Snp->MediaStatusSupported) {
+ Snp->Snp.Mode->MediaPresent =
+ (BOOLEAN) (((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA) != 0) ? FALSE : TRUE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from a
+ network interface.
+
+ This function gets the current interrupt and recycled transmit buffer status
+ from the network interface. The interrupt status is returned as a bit mask in
+ InterruptStatus. If InterruptStatus is NULL, the interrupt status will not be
+ read. If TxBuf is not NULL, a recycled transmit buffer address will be retrieved.
+ If a recycled transmit buffer address is returned in TxBuf, then the buffer has
+ been successfully transmitted, and the status for that buffer is cleared. If
+ the status of the network interface is successfully collected, EFI_SUCCESS
+ will be returned. If the driver has not been initialized, EFI_DEVICE_ERROR will
+ be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param InterruptStatus A pointer to the bit mask of the currently active
+ interrupts (see "Related Definitions"). If this is NULL,
+ the interrupt status will not be read from the device.
+ If this is not NULL, the interrupt status will be read
+ from the device. When the interrupt status is read, it
+ will also be cleared. Clearing the transmit interrupt does
+ not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface
+ will not transmit if its internal recycled transmit
+ buffer array is full. Reading the transmit buffer does
+ not clear the transmit interrupt. If this is NULL, then
+ the transmit buffer status will not be read. If there
+ are no transmit buffers to recycle and TxBuf is not NULL,
+ TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32GetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus, OPTIONAL
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterruptStatus == NULL && TxBuf == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (Snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (Snp->RecycledTxBufCount == 0 && TxBuf != NULL) {
+ Status = PxeGetStatus (Snp, InterruptStatus, TRUE);
+ } else {
+ Status = PxeGetStatus (Snp, InterruptStatus, FALSE);
+ }
+
+ if (TxBuf != NULL) {
+ //
+ // Get a recycled buf from Snp->RecycledTxBuf
+ //
+ if (Snp->RecycledTxBufCount == 0) {
+ *TxBuf = NULL;
+ } else {
+ Snp->RecycledTxBufCount--;
+ *TxBuf = (VOID *) (UINTN) Snp->RecycledTxBuf[Snp->RecycledTxBufCount];
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Initialize.c b/NetworkPkg/SnpDxe/Initialize.c
new file mode 100644
index 0000000000..4d33154241
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Initialize.c
@@ -0,0 +1,277 @@
+/** @file
+ Implementation of initializing a network adapter.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Snp.h"
+
+/**
+ Call UNDI to initialize the interface.
+
+ @param Snp Pointer to snp driver structure.
+ @param CableDetectFlag Do/don't detect the cable (depending on what
+ undi supports).
+
+ @retval EFI_SUCCESS UNDI is initialized successfully.
+ @retval EFI_DEVICE_ERROR UNDI could not be initialized.
+ @retval Other Other errors as indicated.
+
+**/
+EFI_STATUS
+PxeInit (
+ SNP_DRIVER *Snp,
+ UINT16 CableDetectFlag
+ )
+{
+ PXE_CPB_INITIALIZE *Cpb;
+ VOID *Addr;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ Cpb = Snp->Cpb;
+ if (Snp->TxRxBufferSize != 0) {
+ Status = Snp->PciIo->AllocateBuffer (
+ Snp->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (Snp->TxRxBufferSize),
+ &Addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nSnp->PxeInit() AllocateBuffer %xh (%r)\n",
+ Status,
+ Status)
+ );
+
+ return Status;
+ }
+
+ ASSERT (Addr);
+
+ Snp->TxRxBuffer = Addr;
+ }
+
+ Cpb->MemoryAddr = (UINT64)(UINTN) Snp->TxRxBuffer;
+
+ Cpb->MemoryLength = Snp->TxRxBufferSize;
+
+ //
+ // let UNDI decide/detect these values
+ //
+ Cpb->LinkSpeed = 0;
+ Cpb->TxBufCnt = 0;
+ Cpb->TxBufSize = 0;
+ Cpb->RxBufCnt = 0;
+ Cpb->RxBufSize = 0;
+
+ Cpb->DuplexMode = PXE_DUPLEX_DEFAULT;
+
+ Cpb->LoopBackMode = LOOPBACK_NORMAL;
+
+ Snp->Cdb.OpCode = PXE_OPCODE_INITIALIZE;
+ Snp->Cdb.OpFlags = CableDetectFlag;
+
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_INITIALIZE);
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_INITIALIZE);
+
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Snp->Cpb;
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nSnp->undi.initialize() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ //
+ // There are two fields need to be checked here:
+ // First is the upper two bits (14 & 15) in the CDB.StatFlags field. Until these bits change to report
+ // PXE_STATFLAGS_COMMAND_COMPLETE or PXE_STATFLAGS_COMMAND_FAILED, the command has not been executed by the UNDI.
+ // Second is the CDB.StatCode field. After command execution completes, either successfully or not,
+ // the CDB.StatCode field contains the result of the command execution.
+ //
+ if ((((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_COMPLETE) &&
+ (Snp->Cdb.StatCode == PXE_STATCODE_SUCCESS)) {
+ //
+ // If cable detect feature is enabled in CDB.OpFlags, check the CDB.StatFlags to see if there is an
+ // active connection to this network device. If the no media StatFlag is set, the UNDI and network
+ // device are still initialized.
+ //
+ if (CableDetectFlag == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
+ if(((Snp->Cdb.StatFlags) & PXE_STATFLAGS_INITIALIZED_NO_MEDIA) != PXE_STATFLAGS_INITIALIZED_NO_MEDIA) {
+ Snp->Mode.MediaPresent = TRUE;
+ } else {
+ Snp->Mode.MediaPresent = FALSE;
+ }
+ }
+
+ Snp->Mode.State = EfiSimpleNetworkInitialized;
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nSnp->undi.initialize() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ if (Snp->TxRxBuffer != NULL) {
+ Snp->PciIo->FreeBuffer (
+ Snp->PciIo,
+ SNP_MEM_PAGES (Snp->TxRxBufferSize),
+ (VOID *) Snp->TxRxBuffer
+ );
+ }
+
+ Snp->TxRxBuffer = NULL;
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation of
+ additional transmit and receive buffers.
+
+ This function allocates the transmit and receive buffers required by the network
+ interface. If this allocation fails, then EFI_OUT_OF_RESOURCES is returned.
+ If the allocation succeeds and the network interface is successfully initialized,
+ then EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the
+ extra buffer, and the caller will not know if it is
+ actually being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the
+ extra buffer, and the caller will not know if it is
+ actually being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
+ receive buffers.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED The increased buffer size feature is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS EfiStatus;
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (Snp == NULL) {
+ EfiStatus = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ EfiStatus = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ EfiStatus = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ EfiStatus = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ &SnpWaitForPacketNotify,
+ Snp,
+ &Snp->Snp.WaitForPacket
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ Snp->Snp.WaitForPacket = NULL;
+ EfiStatus = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ //
+ //
+ Snp->Mode.MCastFilterCount = 0;
+ Snp->Mode.ReceiveFilterSetting = 0;
+ ZeroMem (Snp->Mode.MCastFilter, sizeof Snp->Mode.MCastFilter);
+ CopyMem (
+ &Snp->Mode.CurrentAddress,
+ &Snp->Mode.PermanentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ //
+ // Compute tx/rx buffer sizes based on UNDI init info and parameters.
+ //
+ Snp->TxRxBufferSize = (UINT32) (Snp->InitInfo.MemoryRequired + ExtraRxBufferSize + ExtraTxBufferSize);
+
+ //
+ // If UNDI support cable detect for INITIALIZE command, try it first.
+ //
+ if (Snp->CableDetectSupported) {
+ if (PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {
+ goto ON_EXIT;
+ }
+ }
+
+ Snp->Mode.MediaPresent = FALSE;
+
+ EfiStatus = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
+
+ if (EFI_ERROR (EfiStatus)) {
+ gBS->CloseEvent (Snp->Snp.WaitForPacket);
+ goto ON_EXIT;
+ }
+
+ //
+ // Try to update the MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support it.
+ //
+ if (Snp->MediaStatusSupported) {
+ PxeGetStatus (Snp, NULL, FALSE);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return EfiStatus;
+}
diff --git a/NetworkPkg/SnpDxe/Mcast_ip_to_mac.c b/NetworkPkg/SnpDxe/Mcast_ip_to_mac.c
new file mode 100644
index 0000000000..9863c1f9ea
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Mcast_ip_to_mac.c
@@ -0,0 +1,173 @@
+/** @file
+ Implementation of converting an multicast IP address to multicast HW MAC
+ address.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+/**
+ Call undi to convert an multicast IP address to a MAC address.
+
+ @param Snp Pointer to snp driver structure.
+ @param IPv6 Flag to indicate if this is an ipv6 address.
+ @param IP Multicast IP address.
+ @param MAC Pointer to hold the return MAC address.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the
+ multicast HW MAC address.
+ @retval EFI_INVALID_PARAMETER Invalid UNDI command.
+ @retval EFI_UNSUPPORTED Command is not supported by UNDI.
+ @retval EFI_DEVICE_ERROR Fail to execute UNDI command.
+
+**/
+EFI_STATUS
+PxeIp2Mac (
+ IN SNP_DRIVER *Snp,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ IN OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ PXE_CPB_MCAST_IP_TO_MAC *Cpb;
+ PXE_DB_MCAST_IP_TO_MAC *Db;
+
+ Cpb = Snp->Cpb;
+ Db = Snp->Db;
+ Snp->Cdb.OpCode = PXE_OPCODE_MCAST_IP_TO_MAC;
+ Snp->Cdb.OpFlags = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC);
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_MCAST_IP_TO_MAC);
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_MCAST_IP_TO_MAC);
+
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ CopyMem (&Cpb->IP, IP, sizeof (PXE_IP_ADDR));
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nSnp->undi.mcast_ip_to_mac() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_INVALID_CPB:
+ return EFI_INVALID_PARAMETER;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_NET,
+ "\nSnp->undi.mcast_ip_to_mac() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+ return EFI_UNSUPPORTED;
+
+ default:
+ //
+ // UNDI command failed. Return EFI_DEVICE_ERROR
+ // to caller.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nSnp->undi.mcast_ip_to_mac() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (MAC, &Db->MAC, sizeof (PXE_MAC_ADDR));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Converts a multicast IP address to a multicast HW MAC address.
+
+ This function converts a multicast IP address to a multicast HW MAC address
+ for all packet transactions. If the mapping is accepted, then EFI_SUCCESS will
+ be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460].
+ Set to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param IP The multicast IP address that is to be converted to a multicast
+ HW MAC address.
+ @param MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the
+ multicast HW MAC address.
+ @retval EFI_NOT_STARTED The Simple Network Protocol interface has not
+ been started by calling Start().
+ @retval EFI_INVALID_PARAMETER IP is NULL.
+ @retval EFI_INVALID_PARAMETER MAC is NULL.
+ @retval EFI_INVALID_PARAMETER IP does not point to a valid IPv4 or IPv6
+ multicast address.
+ @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
+ been initialized by calling Initialize().
+ @retval EFI_UNSUPPORTED IPv6 is TRUE and the implementation does not
+ support IPv6 multicast to MAC address conversion.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32McastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IP == NULL || MAC == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = PxeIp2Mac (Snp, IPv6, IP, MAC);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Nvdata.c b/NetworkPkg/SnpDxe/Nvdata.c
new file mode 100644
index 0000000000..7010b63a54
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Nvdata.c
@@ -0,0 +1,217 @@
+/** @file
+ Implementation of reading and writing operations on the NVRAM device
+ attached to a network interface.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ This routine calls Undi to read the desired number of eeprom bytes.
+
+ @param Snp pointer to the snp driver structure
+ @param Offset eeprom register value relative to the base address
+ @param BufferSize number of bytes to read
+ @param Buffer pointer where to read into
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_INVALID_PARAMETER Invalid UNDI command.
+ @retval EFI_UNSUPPORTED Command is not supported by UNDI.
+ @retval EFI_DEVICE_ERROR Fail to execute UNDI command.
+
+**/
+EFI_STATUS
+PxeNvDataRead (
+ IN SNP_DRIVER *Snp,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ PXE_DB_NVDATA *Db;
+
+ Db = Snp->Db;
+ Snp->Cdb.OpCode = PXE_OPCODE_NVDATA;
+
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NVDATA_READ;
+
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_NVDATA);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata () "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.nvdata() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_UNSUPPORTED;
+
+ default:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.nvdata() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ ASSERT (Offset < sizeof (Db->Data));
+
+ CopyMem (Buffer, &Db->Data.Byte[Offset], BufferSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Performs read and write operations on the NVRAM device attached to a network
+ interface.
+
+ This function performs read and write operations on the NVRAM device attached
+ to a network interface. If ReadWrite is TRUE, a read operation is performed.
+ If ReadWrite is FALSE, a write operation is performed. Offset specifies the
+ byte offset at which to start either operation. Offset must be a multiple of
+ NvRamAccessSize , and it must have a value between zero and NvRamSize.
+ BufferSize specifies the length of the read or write operation. BufferSize must
+ also be a multiple of NvRamAccessSize, and Offset + BufferSize must not exceed
+ NvRamSize.
+ If any of the above conditions is not met, then EFI_INVALID_PARAMETER will be
+ returned.
+ If all the conditions are met and the operation is "read," the NVRAM device
+ attached to the network interface will be read into Buffer and EFI_SUCCESS
+ will be returned. If this is a write operation, the contents of Buffer will be
+ used to update the contents of the NVRAM device attached to the network
+ interface and EFI_SUCCESS will be returned.
+
+ It does the basic checking on the input parameters and retrieves snp structure
+ and then calls the read_nvdata() call which does the actual reading
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize
+ and less than NvRamSize. (See EFI_SIMPLE_NETWORK_MODE)
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ * The This parameter is NULL
+ * The This parameter does not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure
+ * The Offset parameter is not a multiple of
+ EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize
+ * The Offset parameter is not less than
+ EFI_SIMPLE_NETWORK_MODE.NvRamSize
+ * The BufferSize parameter is not a multiple of
+ EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize
+ * The Buffer parameter is NULL
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32NvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // Return error if non-volatile memory variables are not valid.
+ //
+ if (Snp->Mode.NvRamSize == 0 || Snp->Mode.NvRamAccessSize == 0) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+ //
+ // Check for invalid parameter combinations.
+ //
+ if ((BufferSize == 0) ||
+ (Buffer == NULL) ||
+ (Offset >= Snp->Mode.NvRamSize) ||
+ (Offset + BufferSize > Snp->Mode.NvRamSize) ||
+ (BufferSize % Snp->Mode.NvRamAccessSize != 0) ||
+ (Offset % Snp->Mode.NvRamAccessSize != 0)
+ ) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ //
+ // check the implementation flags of undi if we can write the nvdata!
+ //
+ if (!ReadWrite) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = PxeNvDataRead (Snp, Offset, BufferSize, Buffer);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Receive.c b/NetworkPkg/SnpDxe/Receive.c
new file mode 100644
index 0000000000..28cea0d2e9
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Receive.c
@@ -0,0 +1,251 @@
+/** @file
+ Implementation of receiving a packet from a network interface.
+
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Snp.h"
+
+/**
+ Call UNDI to receive a packet and fills in the data in the input pointers.
+
+ @param Snp Pointer to snp driver structure
+ @param Buffer Pointer to the memory for the received data
+ @param BufferSize Pointer to the length of the buffer on entry and contains
+ the length of the received data on return
+ @param HeaderSize Pointer to the header portion of the data received.
+ @param SrcAddr Pointer to contain the source ethernet address on return
+ @param DestAddr Pointer to contain the destination ethernet address on
+ return
+ @param Protocol Pointer to contain the protocol type from the ethernet
+ header on return
+
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and
+ BufferSize has been updated to the number of
+ bytes received.
+ @retval EFI_DEVICE_ERROR Fail to execute UNDI command.
+ @retval EFI_NOT_READY No packets have been received on the network
+ interface.
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the received
+ packets. BufferSize has been updated to the
+ required size.
+
+**/
+EFI_STATUS
+PxeReceive (
+ SNP_DRIVER *Snp,
+ VOID *Buffer,
+ UINTN *BufferSize,
+ UINTN *HeaderSize,
+ EFI_MAC_ADDRESS *SrcAddr,
+ EFI_MAC_ADDRESS *DestAddr,
+ UINT16 *Protocol
+ )
+{
+ PXE_CPB_RECEIVE *Cpb;
+ PXE_DB_RECEIVE *Db;
+ UINTN BuffSize;
+
+ Cpb = Snp->Cpb;
+ Db = Snp->Db;
+ BuffSize = *BufferSize;
+
+ Cpb->BufferAddr = (UINT64)(UINTN) Buffer;
+ Cpb->BufferLen = (UINT32) *BufferSize;
+
+ Cpb->reserved = 0;
+
+ Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_RECEIVE);
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
+
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_RECEIVE);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive () "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_NO_DATA:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.receive () %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_NOT_READY;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ *BufferSize = Db->FrameLen;
+
+ if (HeaderSize != NULL) {
+ *HeaderSize = Db->MediaHeaderLen;
+ }
+
+ if (SrcAddr != NULL) {
+ CopyMem (SrcAddr, &Db->SrcAddr, Snp->Mode.HwAddressSize);
+ }
+
+ if (DestAddr != NULL) {
+ CopyMem (DestAddr, &Db->DestAddr, Snp->Mode.HwAddressSize);
+ }
+
+ if (Protocol != NULL) {
+ //
+ // We need to do the byte swapping
+ //
+ *Protocol = (UINT16) PXE_SWAP_UINT16 (Db->Protocol);
+ }
+
+ //
+ // We have received a packet from network interface, which implies that the
+ // network cable should be present. While, some UNDI driver may not report
+ // correct media status during Snp->Initialize(). So, we need ensure
+ // MediaPresent in SNP mode data is set to correct value.
+ //
+ if (Snp->Mode.MediaPresentSupported && !Snp->Mode.MediaPresent) {
+ Snp->Mode.MediaPresent = TRUE;
+ }
+
+ return (*BufferSize <= BuffSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+}
+
+/**
+ Receives a packet from a network interface.
+
+ This function retrieves one packet from the receive queue of a network interface.
+ If there are no packets on the receive queue, then EFI_NOT_READY will be
+ returned. If there is a packet on the receive queue, and the size of the packet
+ is smaller than BufferSize, then the contents of the packet will be placed in
+ Buffer, and BufferSize will be updated with the actual size of the packet.
+ In addition, if SrcAddr, DestAddr, and Protocol are not NULL, then these values
+ will be extracted from the media header and returned. EFI_SUCCESS will be
+ returned if a packet was successfully received.
+ If BufferSize is smaller than the received packet, then the size of the receive
+ packet will be placed in BufferSize and EFI_BUFFER_TOO_SMALL will be returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media
+ header and the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the HW
+ MAC source address will not be extracted from the media header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from
+ the media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and
+ BufferSize has been updated to the number of
+ bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY No packets have been received on the network interface.
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the received packets.
+ BufferSize has been updated to the required size.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ * The This parameter is NULL
+ * The This parameter does not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ * The BufferSize parameter is NULL
+ * The Buffer parameter is NULL
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if ((BufferSize == NULL) || (Buffer == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (Snp->Mode.ReceiveFilterSetting == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = PxeReceive (
+ Snp,
+ Buffer,
+ BufferSize,
+ HeaderSize,
+ SrcAddr,
+ DestAddr,
+ Protocol
+ );
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Receive_filters.c b/NetworkPkg/SnpDxe/Receive_filters.c
new file mode 100644
index 0000000000..494d2709b6
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Receive_filters.c
@@ -0,0 +1,478 @@
+/** @file
+ Implementation of managing the multicast receive filters of a network
+ interface.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#include "Snp.h"
+
+/**
+ Call undi to enable the receive filters.
+
+ @param Snp Pointer to snp driver structure.
+ @param EnableFlags Bit mask for enabling the receive filters.
+ @param MCastAddressCount Multicast address count for a new multicast address
+ list.
+ @param MCastAddressList List of new multicast addresses.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_INVALID_PARAMETER Invalid UNDI command.
+ @retval EFI_UNSUPPORTED Command is not supported by UNDI.
+ @retval EFI_DEVICE_ERROR Fail to execute UNDI command.
+
+**/
+EFI_STATUS
+PxeRecvFilterEnable (
+ SNP_DRIVER *Snp,
+ UINT32 EnableFlags,
+ UINTN MCastAddressCount,
+ EFI_MAC_ADDRESS *MCastAddressList
+ )
+{
+ Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ }
+
+ if (MCastAddressCount != 0) {
+ Snp->Cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN)Snp->Cpb;
+ CopyMem (Snp->Cpb, MCastAddressList, Snp->Cdb.CPBsize);
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_INVALID_CDB:
+ case PXE_STATCODE_INVALID_CPB:
+ case PXE_STATCODE_INVALID_PARAMETER:
+ return EFI_INVALID_PARAMETER;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Call undi to disable the receive filters.
+
+ @param Snp Pointer to snp driver structure
+ @param DisableFlags Bit mask for disabling the receive filters
+ @param ResetMCastList Boolean flag to reset/delete the multicast filter
+ list.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_DEVICE_ERROR Fail to execute UNDI command.
+
+**/
+EFI_STATUS
+PxeRecvFilterDisable (
+ SNP_DRIVER *Snp,
+ UINT32 DisableFlags,
+ BOOLEAN ResetMCastList
+ )
+{
+ Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ Snp->Cdb.OpFlags = (UINT16) ((DisableFlags != 0) ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
+
+ if (ResetMCastList) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Call undi to read the receive filters.
+
+ @param Snp Pointer to snp driver structure.
+
+ @retval EFI_SUCCESS The receive filter was read.
+ @retval EFI_DEVICE_ERROR Fail to execute UNDI command.
+
+**/
+EFI_STATUS
+PxeRecvFilterRead (
+ SNP_DRIVER *Snp
+ )
+{
+ Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = (UINT16) (Snp->Mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ if (Snp->Cdb.DBsize == 0) {
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) NULL;
+ } else {
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
+ ZeroMem (Snp->Db, Snp->Cdb.DBsize);
+ }
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Convert UNDI32 StatFlags to EFI SNP filter flags.
+ //
+ Snp->Mode.ReceiveFilterSetting = 0;
+
+ if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
+ Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+ }
+
+ if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
+ Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+ }
+
+ if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
+ Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ }
+
+ if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
+ Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ }
+
+ if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+ }
+
+ CopyMem (Snp->Mode.MCastFilter, Snp->Db, Snp->Cdb.DBsize);
+
+ //
+ // Count number of active entries in multicast filter list.
+ //
+ {
+ EFI_MAC_ADDRESS ZeroMacAddr;
+
+ SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
+
+ for (Snp->Mode.MCastFilterCount = 0;
+ Snp->Mode.MCastFilterCount < Snp->Mode.MaxMCastFilterCount;
+ Snp->Mode.MCastFilterCount++
+ ) {
+ if (CompareMem (
+ &Snp->Mode.MCastFilter[Snp->Mode.MCastFilterCount],
+ &ZeroMacAddr,
+ sizeof ZeroMacAddr
+ ) == 0) {
+ break;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Manages the multicast receive filters of a network interface.
+
+ This function is used enable and disable the hardware and software receive
+ filters for the underlying network device.
+ The receive filter change is broken down into three steps:
+ * The filter mask bits that are set (ON) in the Enable parameter are added to
+ the current receive filter settings.
+ * The filter mask bits that are set (ON) in the Disable parameter are subtracted
+ from the updated receive filter settings.
+ * If the resulting receive filter setting is not supported by the hardware a
+ more liberal setting is selected.
+ If the same bits are set in the Enable and Disable parameters, then the bits
+ in the Disable parameter takes precedence.
+ If the ResetMCastFilter parameter is TRUE, then the multicast address list
+ filter is disabled (irregardless of what other multicast bits are set in the
+ Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set
+ to zero. The Snp->Mode->MCastFilter contents are undefined.
+ After enabling or disabling receive filter settings, software should verify
+ the new settings by checking the Snp->Mode->ReceiveFilterSettings,
+ Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields.
+ Note: Some network drivers and/or devices will automatically promote receive
+ filter settings if the requested setting can not be honored. For example, if
+ a request for four multicast addresses is made and the underlying hardware
+ only supports two multicast addresses the driver might set the promiscuous
+ or promiscuous multicast receive filters instead. The receiving software is
+ responsible for discarding any extra packets that get through the hardware
+ receive filters.
+ Note: Note: To disable all receive filter hardware, the network driver must
+ be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to
+ Snp->Mode->ReceiveFilterSettings will make it so no more packets are
+ returned by the Receive() function, but the receive hardware may still be
+ moving packets into system memory before inspecting and discarding them.
+ Unexpected system errors, reboots and hangs can occur if an OS is loaded
+ and the network devices are not Shutdown() and Stopped().
+ If ResetMCastFilter is TRUE, then the multicast receive filter list on the
+ network interface will be reset to the default multicast receive filter list.
+ If ResetMCastFilter is FALSE, and this network interface allows the multicast
+ receive filter list to be modified, then the MCastFilterCnt and MCastFilter
+ are used to update the current multicast receive filter list. The modified
+ receive filter list settings can be found in the MCastFilter field of
+ EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast
+ receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+ If the receive filter mask and multicast receive filter list have been
+ successfully updated on the network interface, EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param Enable A bit mask of receive filters to enable on the network
+ interface.
+ @param Disable A bit mask of receive filters to disable on the network
+ interface. For backward compatibility with EFI 1.1
+ platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit
+ must be set when the ResetMCastFilter parameter is TRUE.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast
+ receive filters on the network interface to their
+ default values.
+ @param MCastFilterCnt Number of multicast HW MAC addresses in the new MCastFilter
+ list. This value must be less than or equal to the
+ MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE.
+ This field is optional if ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter HW
+ MAC addresses. This list will replace any existing
+ multicast HW MAC address list. This field is optional
+ if ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ * This is NULL
+ * There are bits set in Enable that are not set
+ in Snp->Mode->ReceiveFilterMask
+ * There are bits set in Disable that are not set
+ in Snp->Mode->ReceiveFilterMask
+ * Multicast is being enabled (the
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is
+ set in Enable, it is not set in Disable, and
+ ResetMCastFilter is FALSE) and MCastFilterCount
+ is zero
+ * Multicast is being enabled and MCastFilterCount
+ is greater than Snp->Mode->MaxMCastFilterCount
+ * Multicast is being enabled and MCastFilter is NULL
+ * Multicast is being enabled and one or more of
+ the addresses in the MCastFilter list are not
+ valid multicast MAC addresses
+ @retval EFI_DEVICE_ERROR One or more of the following conditions is TRUE:
+ * The network interface has been started but has
+ not been initialized
+ * An unexpected error was returned by the
+ underlying network driver or device
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32ReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt, OPTIONAL
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // check if we are asked to enable or disable something that the UNDI
+ // does not even support!
+ //
+ if (((Enable &~Snp->Mode.ReceiveFilterMask) != 0) ||
+ ((Disable &~Snp->Mode.ReceiveFilterMask) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (ResetMCastFilter) {
+
+ Disable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & Snp->Mode.ReceiveFilterMask;
+ MCastFilterCnt = 0;
+ MCastFilter = NULL;
+ } else {
+ if (MCastFilterCnt != 0) {
+ if ((MCastFilterCnt > Snp->Mode.MaxMCastFilterCount) ||
+ (MCastFilter == NULL)) {
+
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ }
+ }
+
+ if (Enable == 0 && Disable == 0 && !ResetMCastFilter && MCastFilterCnt == 0) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if ((Enable != 0) || (MCastFilterCnt != 0)) {
+ Status = PxeRecvFilterEnable (
+ Snp,
+ Enable,
+ MCastFilterCnt,
+ MCastFilter
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ if ((Disable != 0) || ResetMCastFilter) {
+ Status = PxeRecvFilterDisable (Snp, Disable, ResetMCastFilter);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ Status = PxeRecvFilterRead (Snp);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Reset.c b/NetworkPkg/SnpDxe/Reset.c
new file mode 100644
index 0000000000..3069bfde66
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Reset.c
@@ -0,0 +1,130 @@
+/** @file
+ Implementation of resetting a network adapter.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Call UNDI to reset the NIC.
+
+ @param Snp Pointer to the snp driver structure.
+
+ @return EFI_SUCCESSFUL The NIC was reset.
+ @retval EFI_DEVICE_ERROR The NIC cannot be reset.
+
+**/
+EFI_STATUS
+PxeReset (
+ SNP_DRIVER *Snp
+ )
+{
+ Snp->Cdb.OpCode = PXE_OPCODE_RESET;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.reset() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi32.reset() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ //
+ // UNDI could not be reset. Return UNDI error.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets a network adapter and reinitializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ This function resets a network adapter and reinitializes it with the parameters
+ that were provided in the previous call to Initialize(). The transmit and
+ receive queues are emptied and all pending interrupts are cleared.
+ Receive filters, the station address, the statistics, and the multicast-IP-to-HW
+ MAC addresses are not reset by this call. If the network interface was
+ successfully reset, then EFI_SUCCESS will be returned. If the driver has not
+ been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Resolve Warning 4 unreferenced parameter problem
+ //
+ ExtendedVerification = 0;
+ DEBUG ((EFI_D_WARN, "ExtendedVerification = %d is not implemented!\n", ExtendedVerification));
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = PxeReset (Snp);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Shutdown.c b/NetworkPkg/SnpDxe/Shutdown.c
new file mode 100644
index 0000000000..aad0fe8493
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Shutdown.c
@@ -0,0 +1,146 @@
+/** @file
+ Implementation of shuting down a network adapter.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Call UNDI to shut down the interface.
+
+ @param Snp Pointer to snp driver structure.
+
+ @retval EFI_SUCCESS UNDI is shut down successfully.
+ @retval EFI_DEVICE_ERROR UNDI could not be shut down.
+
+**/
+EFI_STATUS
+PxeShutdown (
+ IN SNP_DRIVER *Snp
+ )
+{
+ Snp->Cdb.OpCode = PXE_OPCODE_SHUTDOWN;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI could not be shutdown. Return UNDI error.
+ //
+ DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Free allocated memory.
+ //
+ if (Snp->TxRxBuffer != NULL) {
+ Snp->PciIo->FreeBuffer (
+ Snp->PciIo,
+ SNP_MEM_PAGES (Snp->TxRxBufferSize),
+ (VOID *) Snp->TxRxBuffer
+ );
+ }
+
+ Snp->TxRxBuffer = NULL;
+ Snp->TxRxBufferSize = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for another
+ driver to initialize.
+
+ This function releases the memory buffers assigned in the Initialize() call.
+ Pending transmits and receives are lost, and interrupts are cleared and disabled.
+ After this call, only the Initialize() and Stop() calls may be used. If the
+ network interface was successfully shutdown, then EFI_SUCCESS will be returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Get pointer to SNP driver instance for *This.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = PxeShutdown (Snp);
+
+ Snp->Mode.State = EfiSimpleNetworkStarted;
+ Snp->Mode.ReceiveFilterSetting = 0;
+
+ Snp->Mode.MCastFilterCount = 0;
+ Snp->Mode.ReceiveFilterSetting = 0;
+ ZeroMem (Snp->Mode.MCastFilter, sizeof Snp->Mode.MCastFilter);
+ CopyMem (
+ &Snp->Mode.CurrentAddress,
+ &Snp->Mode.PermanentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ gBS->CloseEvent (Snp->Snp.WaitForPacket);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Snp.c b/NetworkPkg/SnpDxe/Snp.c
new file mode 100644
index 0000000000..a23af05078
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Snp.c
@@ -0,0 +1,862 @@
+/** @file
+ Implementation of driver entry point and driver binding protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+/**
+ One notified function to stop UNDI device when gBS->ExitBootServices() called.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+VOID
+EFIAPI
+SnpNotifyExitBootServices (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ SNP_DRIVER *Snp;
+
+ Snp = (SNP_DRIVER *)Context;
+
+ //
+ // Shutdown and stop UNDI driver
+ //
+ PxeShutdown (Snp);
+ PxeStop (Snp);
+}
+
+/**
+ Send command to UNDI. It does nothing currently.
+
+ @param Cdb command to be sent to UNDI.
+
+ @retval EFI_INVALID_PARAMETER The command is 0.
+ @retval EFI_UNSUPPORTED Default return status because it's not
+ supported currently.
+
+**/
+EFI_STATUS
+EFIAPI
+IssueHwUndiCommand (
+ UINT64 Cdb
+ )
+{
+ DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));
+
+ if (Cdb == 0) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // %%TBD - For now, nothing is done.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Compute 8-bit checksum of a buffer.
+
+ @param Buffer Pointer to buffer.
+ @param Length Length of buffer in bytes.
+
+ @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len
+ is zero.
+
+**/
+UINT8
+Calc8BitCksum (
+ VOID *Buffer,
+ UINTN Length
+ )
+{
+ UINT8 *Ptr;
+ UINT8 Cksum;
+
+ Ptr = Buffer;
+ Cksum = 0;
+
+ if (Ptr == NULL || Length == 0) {
+ return 0;
+ }
+
+ while (Length-- != 0) {
+ Cksum = (UINT8) (Cksum + *Ptr++);
+ }
+
+ return Cksum;
+}
+
+/**
+ Test to see if this driver supports ControllerHandle. This service
+ is called by the EFI boot service ConnectController(). In
+ order to make drivers as small as possible, there are a few calling
+ restrictions for this service. ConnectController() must
+ follow these calling restrictions. If any other agent wishes to call
+ Supported() it must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
+ PXE_UNDI *Pxe;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &NiiProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ALREADY_STARTED) {
+ DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));
+ }
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));
+
+ //
+ // check the version, we don't want to connect to the undi16
+ //
+ if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ //
+ // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
+ //
+ if ((NiiProtocol->Id & 0x0F) != 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);
+
+ //
+ // Verify !PXE revisions.
+ //
+ if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
+ DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (Pxe->hw.Rev < PXE_ROMID_REV) {
+ DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
+
+ DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+
+ } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
+ DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ //
+ // Do S/W UNDI specific checks.
+ //
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
+ if (Pxe->sw.EntryPoint < Pxe->sw.Len) {
+ DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (Pxe->sw.BusCnt == 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ Status = EFI_SUCCESS;
+ DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle. This service is called by the
+ EFI boot service ConnectController(). In order to make
+ drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these
+ calling restrictions. If any other agent wishes to call Start() it
+ must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_DEVICE_ERROR This driver could not be started due to a device error
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
+ EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;
+ EFI_STATUS Status;
+ PXE_UNDI *Pxe;
+ SNP_DRIVER *Snp;
+ VOID *Address;
+ EFI_HANDLE Handle;
+ UINT8 BarIndex;
+ PXE_STATFLAGS InitStatFlags;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
+ BOOLEAN FoundIoBar;
+ BOOLEAN FoundMemoryBar;
+
+ DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &NiiDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateDevicePath (
+ &gEfiPciIoProtocolGuid,
+ &NiiDevicePath,
+ &Handle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the NII interface.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &Nii,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));
+
+ Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);
+
+ if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
+ goto NiiError;
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
+ //
+ // We can get any packets.
+ //
+ } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
+ //
+ // We need to be able to get broadcast packets for DHCP.
+ // If we do not have promiscuous support, we must at least have
+ // broadcast support or we cannot do DHCP!
+ //
+ } else {
+ DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
+ goto NiiError;
+ }
+ //
+ // OK, we like this UNDI, and we know snp is not already there on this handle
+ // Allocate and initialize a new simple network protocol structure.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ &Address,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
+ goto NiiError;
+ }
+
+ Snp = (SNP_DRIVER *) (UINTN) Address;
+
+ ZeroMem (Snp, sizeof (SNP_DRIVER));
+
+ Snp->PciIo = PciIo;
+ Snp->Signature = SNP_DRIVER_SIGNATURE;
+
+ EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);
+
+ Snp->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+ Snp->Snp.Start = SnpUndi32Start;
+ Snp->Snp.Stop = SnpUndi32Stop;
+ Snp->Snp.Initialize = SnpUndi32Initialize;
+ Snp->Snp.Reset = SnpUndi32Reset;
+ Snp->Snp.Shutdown = SnpUndi32Shutdown;
+ Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;
+ Snp->Snp.StationAddress = SnpUndi32StationAddress;
+ Snp->Snp.Statistics = SnpUndi32Statistics;
+ Snp->Snp.MCastIpToMac = SnpUndi32McastIpToMac;
+ Snp->Snp.NvData = SnpUndi32NvData;
+ Snp->Snp.GetStatus = SnpUndi32GetStatus;
+ Snp->Snp.Transmit = SnpUndi32Transmit;
+ Snp->Snp.Receive = SnpUndi32Receive;
+ Snp->Snp.WaitForPacket = NULL;
+
+ Snp->Snp.Mode = &Snp->Mode;
+
+ Snp->TxRxBufferSize = 0;
+ Snp->TxRxBuffer = NULL;
+
+ Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASEMENT);
+ if (Snp->RecycledTxBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_DeleteSNP;
+ }
+ Snp->MaxRecycledTxBuf = SNP_TX_BUFFER_INCREASEMENT;
+ Snp->RecycledTxBufCount = 0;
+
+ if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) {
+ Snp->IfNum = Nii->IfNum;
+
+ } else {
+ Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF);
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
+ Snp->IsSwUndi = FALSE;
+ Snp->IssueUndi32Command = &IssueHwUndiCommand;
+ } else {
+ Snp->IsSwUndi = TRUE;
+
+ if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
+ Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;
+ } else {
+ Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);
+ }
+ }
+ //
+ // Allocate a global CPB and DB buffer for this UNDI interface.
+ // we do this because:
+ //
+ // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
+ // within 2GB limit, create them here and map them so that when undi calls
+ // v2p callback to check if the physical address is < 2gb, we will pass.
+ //
+ // -This is not a requirement for 3.1 or later UNDIs but the code looks
+ // simpler if we use the same cpb, db variables for both old and new undi
+ // interfaces from all the SNP interface calls (we don't map the buffers
+ // for the newer undi interfaces though)
+ // .
+ // -it is OK to allocate one global set of CPB, DB pair for each UNDI
+ // interface as EFI does not multi-task and so SNP will not be re-entered!
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (4096),
+ &Address,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
+ goto Error_DeleteSNP;
+ }
+
+ Snp->Cpb = (VOID *) (UINTN) Address;
+ Snp->Db = (VOID *) ((UINTN) Address + 2048);
+
+ //
+ // Find the correct BAR to do IO.
+ //
+ // Enumerate through the PCI BARs for the device to determine which one is
+ // the IO BAR. Save the index of the BAR into the adapter info structure.
+ // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped
+ //
+ Snp->MemoryBarIndex = 0;
+ Snp->IoBarIndex = 1;
+ FoundMemoryBar = FALSE;
+ FoundIoBar = FALSE;
+ for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
+ Status = PciIo->GetBarAttributes (
+ PciIo,
+ BarIndex,
+ NULL,
+ (VOID**) &BarDesc
+ );
+ if (Status == EFI_UNSUPPORTED) {
+ continue;
+ } else if (EFI_ERROR (Status)) {
+ goto Error_DeleteSNP;
+ }
+
+ if ((!FoundMemoryBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {
+ Snp->MemoryBarIndex = BarIndex;
+ FoundMemoryBar = TRUE;
+ } else if ((!FoundIoBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {
+ Snp->IoBarIndex = BarIndex;
+ FoundIoBar = TRUE;
+ }
+
+ FreePool (BarDesc);
+
+ if (FoundMemoryBar && FoundIoBar) {
+ break;
+ }
+ }
+
+ Status = PxeStart (Snp);
+
+ if (Status != EFI_SUCCESS) {
+ goto Error_DeleteSNP;
+ }
+
+ Snp->Cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;
+
+ Snp->Cdb.DBsize = (UINT16) sizeof (Snp->InitInfo);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) (&Snp->InitInfo);
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ //
+ // Save the INIT Stat Code...
+ //
+ InitStatFlags = Snp->Cdb.StatFlags;
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nSnp->undi.init_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
+ PxeStop (Snp);
+ goto Error_DeleteSNP;
+ }
+
+ //
+ // Initialize simple network protocol mode structure
+ //
+ Snp->Mode.State = EfiSimpleNetworkStopped;
+ Snp->Mode.HwAddressSize = Snp->InitInfo.HWaddrLen;
+ Snp->Mode.MediaHeaderSize = Snp->InitInfo.MediaHeaderLen;
+ Snp->Mode.MaxPacketSize = Snp->InitInfo.FrameDataLen;
+ Snp->Mode.NvRamAccessSize = Snp->InitInfo.NvWidth;
+ Snp->Mode.NvRamSize = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;
+ Snp->Mode.IfType = Snp->InitInfo.IFtype;
+ Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;
+ Snp->Mode.MCastFilterCount = 0;
+
+ switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
+ case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
+ Snp->CableDetectSupported = TRUE;
+ break;
+
+ case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
+ default:
+ Snp->CableDetectSupported = FALSE;
+ }
+
+ switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {
+ case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:
+ Snp->MediaStatusSupported = TRUE;
+ break;
+
+ case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:
+ default:
+ Snp->MediaStatusSupported = FALSE;
+ }
+
+ if (Snp->CableDetectSupported || Snp->MediaStatusSupported) {
+ Snp->Mode.MediaPresentSupported = TRUE;
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
+ Snp->Mode.MacAddressChangeable = TRUE;
+ } else {
+ Snp->Mode.MacAddressChangeable = FALSE;
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
+ Snp->Mode.MultipleTxSupported = TRUE;
+ } else {
+ Snp->Mode.MultipleTxSupported = FALSE;
+ }
+
+ Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
+ Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
+ Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
+ Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
+ Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+
+ }
+
+ if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
+ Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+ }
+
+ Snp->Mode.ReceiveFilterSetting = 0;
+
+ //
+ // need to get the station address to save in the mode structure. we need to
+ // initialize the UNDI first for this.
+ //
+ Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
+ Status = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
+
+ if (EFI_ERROR (Status)) {
+ PxeStop (Snp);
+ goto Error_DeleteSNP;
+ }
+
+ Status = PxeGetStnAddr (Snp);
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
+ PxeShutdown (Snp);
+ PxeStop (Snp);
+ goto Error_DeleteSNP;
+ }
+
+ Snp->Mode.MediaPresent = FALSE;
+
+ //
+ // We should not leave UNDI started and initialized here. this DriverStart()
+ // routine must only find and attach the SNP interface to UNDI layer that it
+ // finds on the given handle!
+ // The UNDI layer will be started when upper layers call Snp->start.
+ // How ever, this DriverStart() must fill up the snp mode structure which
+ // contains the MAC address of the NIC. For this reason we started and
+ // initialized UNDI here, now we are done, do a shutdown and stop of the
+ // UNDI interface!
+ //
+ PxeShutdown (Snp);
+ PxeStop (Snp);
+
+ //
+ // Create EXIT_BOOT_SERIVES Event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SnpNotifyExitBootServices,
+ Snp,
+ &gEfiEventExitBootServicesGuid,
+ &Snp->ExitBootServicesEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_DeleteSNP;
+ }
+
+ //
+ // add SNP to the undi handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(Snp->Snp)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PciIo->FreeBuffer (
+ PciIo,
+ SNP_MEM_PAGES (4096),
+ Snp->Cpb
+ );
+
+Error_DeleteSNP:
+
+ if (Snp->RecycledTxBuf != NULL) {
+ FreePool (Snp->RecycledTxBuf);
+ }
+
+ PciIo->FreeBuffer (
+ PciIo,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ Snp
+ );
+NiiError:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // If we got here that means we are in error state.
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. This service is called by the
+ EFI boot service DisconnectController(). In order to
+ make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController()
+ must follow these calling restrictions. If any other agent wishes
+ to call Stop() it must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
+ SNP_DRIVER *Snp;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &SnpProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ &Snp->Snp
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close EXIT_BOOT_SERIVES Event
+ //
+ gBS->CloseEvent (Snp->ExitBootServicesEvent);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ PxeShutdown (Snp);
+ PxeStop (Snp);
+
+ FreePool (Snp->RecycledTxBuf);
+
+ PciIo = Snp->PciIo;
+ PciIo->FreeBuffer (
+ PciIo,
+ SNP_MEM_PAGES (4096),
+ Snp->Cpb
+ );
+
+ PciIo->FreeBuffer (
+ PciIo,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ Snp
+ );
+
+ return Status;
+}
+
+//
+// Simple Network Protocol Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {
+ SimpleNetworkDriverSupported,
+ SimpleNetworkDriverStart,
+ SimpleNetworkDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ The SNP driver entry point.
+
+ @param ImageHandle The driver image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS Initialization routine has found UNDI hardware,
+ loaded it's ROM, and installed a notify event for
+ the Network Indentifier Interface Protocol
+ successfully.
+ @retval Other Return value from HandleProtocol for
+ DeviceIoProtocol or LoadedImageProtocol
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSimpleNetworkDriverBinding,
+ ImageHandle,
+ &gSimpleNetworkComponentName,
+ &gSimpleNetworkComponentName2
+ );
+}
diff --git a/NetworkPkg/SnpDxe/Snp.h b/NetworkPkg/SnpDxe/Snp.h
new file mode 100644
index 0000000000..e6b6293039
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Snp.h
@@ -0,0 +1,1033 @@
+/** @file
+ Declaration of strctures and functions for SnpDxe driver.
+
+Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _SNP_H_
+#define _SNP_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/NetworkInterfaceIdentifier.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+
+#define FOUR_GIGABYTES (UINT64) 0x100000000ULL
+
+
+#define SNP_DRIVER_SIGNATURE SIGNATURE_32 ('s', 'n', 'd', 's')
+#define MAX_MAP_LENGTH 100
+
+#define PCI_BAR_IO_MASK 0x00000003
+#define PCI_BAR_IO_MODE 0x00000001
+
+#define PCI_BAR_MEM_MASK 0x0000000F
+#define PCI_BAR_MEM_MODE 0x00000000
+#define PCI_BAR_MEM_64BIT 0x00000004
+
+#define SNP_TX_BUFFER_INCREASEMENT MAX_XMIT_BUFFERS
+#define SNP_MAX_TX_BUFFER_NUM 65536
+
+typedef
+EFI_STATUS
+(EFIAPI *ISSUE_UNDI32_COMMAND) (
+ UINT64 Cdb
+ );
+
+typedef struct {
+ UINT32 Signature;
+ EFI_LOCK Lock;
+
+ EFI_SIMPLE_NETWORK_PROTOCOL Snp;
+ EFI_SIMPLE_NETWORK_MODE Mode;
+
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Local instance data needed by SNP driver
+ //
+ // Pointer to S/W UNDI API entry point
+ // This will be NULL for H/W UNDI
+ //
+ ISSUE_UNDI32_COMMAND IssueUndi32Command;
+
+ BOOLEAN IsSwUndi;
+
+ //
+ // undi interface number, if one undi manages more nics
+ //
+ PXE_IFNUM IfNum;
+
+ //
+ // Allocated tx/rx buffer that was passed to UNDI Initialize.
+ //
+ UINT32 TxRxBufferSize;
+ VOID *TxRxBuffer;
+ //
+ // mappable buffers for receive and fill header for undi3.0
+ // these will be used if the user buffers are above 4GB limit (instead of
+ // mapping the user buffers)
+ //
+ UINT8 *ReceiveBufffer;
+ VOID *ReceiveBufferUnmap;
+ UINT8 *FillHeaderBuffer;
+ VOID *FillHeaderBufferUnmap;
+
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 IoBarIndex;
+ UINT8 MemoryBarIndex;
+
+ //
+ // Buffers for command descriptor block, command parameter block
+ // and data block.
+ //
+ PXE_CDB Cdb;
+ VOID *Cpb;
+ VOID *CpbUnmap;
+ VOID *Db;
+
+ //
+ // UNDI structure, we need to remember the init info for a long time!
+ //
+ PXE_DB_GET_INIT_INFO InitInfo;
+
+ VOID *SnpDriverUnmap;
+ //
+ // when ever we map an address, we must remember it's address and the un-map
+ // cookie so that we can unmap later
+ //
+ struct MAP_LIST {
+ EFI_PHYSICAL_ADDRESS VirtualAddress;
+ VOID *MapCookie;
+ } MapList[MAX_MAP_LENGTH];
+
+ EFI_EVENT ExitBootServicesEvent;
+
+ //
+ // Whether UNDI support reporting media status from GET_STATUS command,
+ // i.e. PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED or
+ // PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED
+ //
+ BOOLEAN MediaStatusSupported;
+
+ //
+ // Whether UNDI support cable detect for INITIALIZE command,
+ // i.e. PXE_STATFLAGS_CABLE_DETECT_SUPPORTED or
+ // PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED
+ //
+ BOOLEAN CableDetectSupported;
+
+ //
+ // Array of the recycled transmit buffer address from UNDI.
+ //
+ UINT64 *RecycledTxBuf;
+ //
+ // The maximum number of recycled buffer pointers in RecycledTxBuf.
+ //
+ UINT32 MaxRecycledTxBuf;
+ //
+ // Current number of recycled buffer pointers in RecycledTxBuf.
+ //
+ UINT32 RecycledTxBufCount;
+} SNP_DRIVER;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, Snp, SNP_DRIVER_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSimpleNetworkComponentName2;
+
+/**
+ this routine calls undi to start the interface and changes the snp state.
+
+ @param Snp pointer to snp driver structure
+
+ @retval EFI_DEVICE_ERROR UNDI could not be started
+ @retval EFI_SUCCESS UNDI is started successfully
+
+**/
+EFI_STATUS
+PxeStart (
+ IN SNP_DRIVER *Snp
+ );
+
+/**
+ this routine calls undi to stop the interface and changes the snp state.
+
+ @param Snp pointer to snp driver structure
+
+ @retval EFI_INVALID_PARAMETER invalid parameter
+ @retval EFI_NOT_STARTED SNP is not started
+ @retval EFI_DEVICE_ERROR SNP is not initialized
+ @retval EFI_UNSUPPORTED operation unsupported
+
+**/
+EFI_STATUS
+PxeStop (
+ SNP_DRIVER *Snp
+ );
+
+/**
+ this routine calls undi to initialize the interface.
+
+ @param Snp pointer to snp driver structure
+ @param CableDetectFlag Do/don't detect the cable (depending on what undi supports)
+
+ @retval EFI_SUCCESS UNDI is initialized successfully
+ @retval EFI_DEVICE_ERROR UNDI could not be initialized
+ @retval Other other errors
+
+**/
+EFI_STATUS
+PxeInit (
+ SNP_DRIVER *Snp,
+ UINT16 CableDetectFlag
+ );
+
+/**
+ this routine calls undi to shut down the interface.
+
+ @param Snp pointer to snp driver structure
+
+ @retval EFI_SUCCESS UNDI is shut down successfully
+ @retval EFI_DEVICE_ERROR UNDI could not be shut down
+
+**/
+EFI_STATUS
+PxeShutdown (
+ IN SNP_DRIVER *Snp
+ );
+
+/**
+ this routine calls undi to read the MAC address of the NIC and updates the
+ mode structure with the address.
+
+ @param Snp pointer to snp driver structure.
+
+ @retval EFI_SUCCESS the MAC address of the NIC is read successfully.
+ @retval EFI_DEVICE_ERROR failed to read the MAC address of the NIC.
+
+**/
+EFI_STATUS
+PxeGetStnAddr (
+ SNP_DRIVER *Snp
+ );
+
+/**
+ Call undi to get the status of the interrupts, get the list of recycled transmit
+ buffers that completed transmitting. The recycled transmit buffer address will
+ be saved into Snp->RecycledTxBuf. This function will also update the MediaPresent
+ field of EFI_SIMPLE_NETWORK_MODE if UNDI support it.
+
+ @param[in] Snp Pointer to snp driver structure.
+ @param[out] InterruptStatusPtr A non null pointer to contain the interrupt
+ status.
+ @param[in] GetTransmittedBuf Set to TRUE to retrieve the recycled transmit
+ buffer address.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+
+**/
+EFI_STATUS
+PxeGetStatus (
+ IN SNP_DRIVER *Snp,
+ OUT UINT32 *InterruptStatusPtr,
+ IN BOOLEAN GetTransmittedBuf
+ );
+
+/**
+ This is a callback routine supplied to UNDI3.1 at undi_start time.
+ UNDI call this routine when it wants to have exclusive access to a critical
+ section of the code/data.
+ New callbacks for 3.1:
+ there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses
+ the MemMap call to map the required address by itself!
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store Undi interface context (Undi does not read or write
+ this variable)
+ @param Enable non-zero indicates acquire
+ zero indicates release
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackBlock (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ );
+
+/**
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with the number of micro seconds when it wants to
+ pause.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
+ store Undi interface context (Undi does not read or write
+ this variable)
+ @param MicroSeconds number of micro seconds to pause, ususlly multiple of 10.
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackDelay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ );
+
+/**
+ This is a callback routine supplied to UNDI at undi_start time.
+ This is the IO routine for UNDI3.1 to start CPB.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this
+ to store Undi interface context (Undi does not read or
+ write this variable)
+ @param ReadOrWrite indicates read or write, IO or Memory.
+ @param NumBytes number of bytes to read or write.
+ @param MemOrPortAddr IO or memory address to read from or write to.
+ @param BufferPtr memory location to read into or that contains the bytes
+ to write.
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackMemio (
+ IN UINT64 UniqueId,
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddr,
+ IN OUT UINT64 BufferPtr
+ );
+
+/**
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it has to map a CPU address to a device
+ address.
+
+ @param UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ @param CpuAddr - Virtual address to be mapped!
+ @param NumBytes - size of memory to be mapped
+ @param Direction - direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ @param DeviceAddrPtr - pointer to return the mapped device address
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackMap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ );
+
+/**
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants to unmap an address that was previously
+ mapped using map callback.
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to store.
+ Undi interface context (Undi does not read or write this variable)
+ @param CpuAddr Virtual address that was mapped!
+ @param NumBytes size of memory mapped
+ @param Direction direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ @param DeviceAddr the mapped device address
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackUnmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr
+ );
+
+/**
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants synchronize the virtual buffer contents
+ with the mapped buffer contents. The virtual and mapped buffers need not
+ correspond to the same physical memory (especially if the virtual address is
+ > 4GB). Depending on the direction for which the buffer is mapped, undi will
+ need to synchronize their contents whenever it writes to/reads from the buffer
+ using either the cpu address or the device address.
+
+ EFI does not provide a sync call, since virt=physical, we sould just do
+ the synchronization ourself here!
+
+ @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ @param CpuAddr Virtual address that was mapped!
+ @param NumBytes size of memory mapped.
+ @param Direction direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways.
+ @param DeviceAddr the mapped device address.
+
+**/
+VOID
+EFIAPI
+SnpUndi32CallbackSync (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr
+ );
+
+/**
+ Changes the state of a network interface from "stopped" to "started".
+
+ This function starts a network interface. If the network interface successfully
+ starts, then EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started state.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Changes the state of a network interface from "started" to "stopped".
+
+ This function stops a network interface. This call is only valid if the network
+ interface is in the started state. If the network interface was successfully
+ stopped, then EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation of
+ additional transmit and receive buffers.
+
+ This function allocates the transmit and receive buffers required by the network
+ interface. If this allocation fails, then EFI_OUT_OF_RESOURCES is returned.
+ If the allocation succeeds and the network interface is successfully initialized,
+ then EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the
+ extra buffer, and the caller will not know if it is
+ actually being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the
+ extra buffer, and the caller will not know if it is
+ actually being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
+ receive buffers.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED The increased buffer size feature is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ );
+
+/**
+ Resets a network adapter and reinitializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ This function resets a network adapter and reinitializes it with the parameters
+ that were provided in the previous call to Initialize(). The transmit and
+ receive queues are emptied and all pending interrupts are cleared.
+ Receive filters, the station address, the statistics, and the multicast-IP-to-HW
+ MAC addresses are not reset by this call. If the network interface was
+ successfully reset, then EFI_SUCCESS will be returned. If the driver has not
+ been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for another
+ driver to initialize.
+
+ This function releases the memory buffers assigned in the Initialize() call.
+ Pending transmits and receives are lost, and interrupts are cleared and disabled.
+ After this call, only the Initialize() and Stop() calls may be used. If the
+ network interface was successfully shutdown, then EFI_SUCCESS will be returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Manages the multicast receive filters of a network interface.
+
+ This function is used enable and disable the hardware and software receive
+ filters for the underlying network device.
+ The receive filter change is broken down into three steps:
+ * The filter mask bits that are set (ON) in the Enable parameter are added to
+ the current receive filter settings.
+ * The filter mask bits that are set (ON) in the Disable parameter are subtracted
+ from the updated receive filter settings.
+ * If the resulting receive filter setting is not supported by the hardware a
+ more liberal setting is selected.
+ If the same bits are set in the Enable and Disable parameters, then the bits
+ in the Disable parameter takes precedence.
+ If the ResetMCastFilter parameter is TRUE, then the multicast address list
+ filter is disabled (irregardless of what other multicast bits are set in the
+ Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set
+ to zero. The Snp->Mode->MCastFilter contents are undefined.
+ After enabling or disabling receive filter settings, software should verify
+ the new settings by checking the Snp->Mode->ReceiveFilterSettings,
+ Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields.
+ Note: Some network drivers and/or devices will automatically promote receive
+ filter settings if the requested setting can not be honored. For example, if
+ a request for four multicast addresses is made and the underlying hardware
+ only supports two multicast addresses the driver might set the promiscuous
+ or promiscuous multicast receive filters instead. The receiving software is
+ responsible for discarding any extra packets that get through the hardware
+ receive filters.
+ Note: Note: To disable all receive filter hardware, the network driver must
+ be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to
+ Snp->Mode->ReceiveFilterSettings will make it so no more packets are
+ returned by the Receive() function, but the receive hardware may still be
+ moving packets into system memory before inspecting and discarding them.
+ Unexpected system errors, reboots and hangs can occur if an OS is loaded
+ and the network devices are not Shutdown() and Stopped().
+ If ResetMCastFilter is TRUE, then the multicast receive filter list on the
+ network interface will be reset to the default multicast receive filter list.
+ If ResetMCastFilter is FALSE, and this network interface allows the multicast
+ receive filter list to be modified, then the MCastFilterCnt and MCastFilter
+ are used to update the current multicast receive filter list. The modified
+ receive filter list settings can be found in the MCastFilter field of
+ EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast
+ receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+ If the receive filter mask and multicast receive filter list have been
+ successfully updated on the network interface, EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param Enable A bit mask of receive filters to enable on the network
+ interface.
+ @param Disable A bit mask of receive filters to disable on the network
+ interface. For backward compatibility with EFI 1.1
+ platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit
+ must be set when the ResetMCastFilter parameter is TRUE.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast
+ receive filters on the network interface to their
+ default values.
+ @param MCastFilterCnt Number of multicast HW MAC addresses in the new MCastFilter
+ list. This value must be less than or equal to the
+ MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE.
+ This field is optional if ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter HW
+ MAC addresses. This list will replace any existing
+ multicast HW MAC address list. This field is optional
+ if ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ * This is NULL
+ * There are bits set in Enable that are not set
+ in Snp->Mode->ReceiveFilterMask
+ * There are bits set in Disable that are not set
+ in Snp->Mode->ReceiveFilterMask
+ * Multicast is being enabled (the
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is
+ set in Enable, it is not set in Disable, and
+ ResetMCastFilter is FALSE) and MCastFilterCount
+ is zero
+ * Multicast is being enabled and MCastFilterCount
+ is greater than Snp->Mode->MaxMCastFilterCount
+ * Multicast is being enabled and MCastFilter is NULL
+ * Multicast is being enabled and one or more of
+ the addresses in the MCastFilter list are not
+ valid multicast MAC addresses
+ @retval EFI_DEVICE_ERROR One or more of the following conditions is TRUE:
+ * The network interface has been started but has
+ not been initialized
+ * An unexpected error was returned by the
+ underlying network driver or device
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32ReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt, OPTIONAL
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ );
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ This function modifies or resets the current station address of a network
+ interface, if supported. If Reset is TRUE, then the current station address is
+ set to the network interface's permanent address. If Reset is FALSE, and the
+ network interface allows its station address to be modified, then the current
+ station address is changed to the address specified by New. If the network
+ interface does not allow its station address to be modified, then
+ EFI_INVALID_PARAMETER will be returned. If the station address is successfully
+ updated on the network interface, EFI_SUCCESS will be returned. If the driver
+ has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param Reset Flag used to reset the station address to the network interface's
+ permanent address.
+ @param New New station address to be used for the network interface.
+
+
+ @retval EFI_SUCCESS The network interface's station address was updated.
+ @retval EFI_NOT_STARTED The Simple Network Protocol interface has not been
+ started by calling Start().
+ @retval EFI_INVALID_PARAMETER The New station address was not accepted by the NIC.
+ @retval EFI_INVALID_PARAMETER Reset is FALSE and New is NULL.
+ @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
+ been initialized by calling Initialize().
+ @retval EFI_DEVICE_ERROR An error occurred attempting to set the new
+ station address.
+ @retval EFI_UNSUPPORTED The NIC does not support changing the network
+ interface's station address.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32StationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ );
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ This function resets or collects the statistics on a network interface. If the
+ size of the statistics table specified by StatisticsSize is not big enough for
+ all the statistics that are collected by the network interface, then a partial
+ buffer of statistics is returned in StatisticsTable, StatisticsSize is set to
+ the size required to collect all the available statistics, and
+ EFI_BUFFER_TOO_SMALL is returned.
+ If StatisticsSize is big enough for all the statistics, then StatisticsTable
+ will be filled, StatisticsSize will be set to the size of the returned
+ StatisticsTable structure, and EFI_SUCCESS is returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+ If Reset is FALSE, and both StatisticsSize and StatisticsTable are NULL, then
+ no operations will be performed, and EFI_SUCCESS will be returned.
+ If Reset is TRUE, then all of the supported statistics counters on this network
+ interface will be reset to zero.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On output
+ the size, in bytes, of the resulting table of statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics. Type EFI_NETWORK_STATISTICS is
+ defined in "Related Definitions" below.
+
+ @retval EFI_SUCCESS The requested operation succeeded.
+ @retval EFI_NOT_STARTED The Simple Network Protocol interface has not been
+ started by calling Start().
+ @retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is
+ NULL. The current buffer size that is needed to
+ hold all the statistics is returned in StatisticsSize.
+ @retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is
+ not NULL. The current buffer size that is needed
+ to hold all the statistics is returned in
+ StatisticsSize. A partial set of statistics is
+ returned in StatisticsTable.
+ @retval EFI_INVALID_PARAMETER StatisticsSize is NULL and StatisticsTable is not
+ NULL.
+ @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
+ been initialized by calling Initialize().
+ @retval EFI_DEVICE_ERROR An error was encountered collecting statistics
+ from the NIC.
+ @retval EFI_UNSUPPORTED The NIC does not support collecting statistics
+ from the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize, OPTIONAL
+ IN OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ );
+
+/**
+ Converts a multicast IP address to a multicast HW MAC address.
+
+ This function converts a multicast IP address to a multicast HW MAC address
+ for all packet transactions. If the mapping is accepted, then EFI_SUCCESS will
+ be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460].
+ Set to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param IP The multicast IP address that is to be converted to a multicast
+ HW MAC address.
+ @param MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the
+ multicast HW MAC address.
+ @retval EFI_NOT_STARTED The Simple Network Protocol interface has not
+ been started by calling Start().
+ @retval EFI_INVALID_PARAMETER IP is NULL.
+ @retval EFI_INVALID_PARAMETER MAC is NULL.
+ @retval EFI_INVALID_PARAMETER IP does not point to a valid IPv4 or IPv6
+ multicast address.
+ @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
+ been initialized by calling Initialize().
+ @retval EFI_UNSUPPORTED IPv6 is TRUE and the implementation does not
+ support IPv6 multicast to MAC address conversion.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32McastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ );
+
+/**
+ Performs read and write operations on the NVRAM device attached to a network
+ interface.
+
+ This function performs read and write operations on the NVRAM device attached
+ to a network interface. If ReadWrite is TRUE, a read operation is performed.
+ If ReadWrite is FALSE, a write operation is performed. Offset specifies the
+ byte offset at which to start either operation. Offset must be a multiple of
+ NvRamAccessSize , and it must have a value between zero and NvRamSize.
+ BufferSize specifies the length of the read or write operation. BufferSize must
+ also be a multiple of NvRamAccessSize, and Offset + BufferSize must not exceed
+ NvRamSize.
+ If any of the above conditions is not met, then EFI_INVALID_PARAMETER will be
+ returned.
+ If all the conditions are met and the operation is "read," the NVRAM device
+ attached to the network interface will be read into Buffer and EFI_SUCCESS
+ will be returned. If this is a write operation, the contents of Buffer will be
+ used to update the contents of the NVRAM device attached to the network
+ interface and EFI_SUCCESS will be returned.
+
+ It does the basic checking on the input parameters and retrieves snp structure
+ and then calls the read_nvdata() call which does the actual reading
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize
+ and less than NvRamSize. (See EFI_SIMPLE_NETWORK_MODE)
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ * The This parameter is NULL
+ * The This parameter does not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure
+ * The Offset parameter is not a multiple of
+ EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize
+ * The Offset parameter is not less than
+ EFI_SIMPLE_NETWORK_MODE.NvRamSize
+ * The BufferSize parameter is not a multiple of
+ EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize
+ * The Buffer parameter is NULL
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32NvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from a
+ network interface.
+
+ This function gets the current interrupt and recycled transmit buffer status
+ from the network interface. The interrupt status is returned as a bit mask in
+ InterruptStatus. If InterruptStatus is NULL, the interrupt status will not be
+ read. If TxBuf is not NULL, a recycled transmit buffer address will be retrieved.
+ If a recycled transmit buffer address is returned in TxBuf, then the buffer has
+ been successfully transmitted, and the status for that buffer is cleared. If
+ the status of the network interface is successfully collected, EFI_SUCCESS
+ will be returned. If the driver has not been initialized, EFI_DEVICE_ERROR will
+ be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param InterruptStatus A pointer to the bit mask of the currently active
+ interrupts (see "Related Definitions"). If this is NULL,
+ the interrupt status will not be read from the device.
+ If this is not NULL, the interrupt status will be read
+ from the device. When the interrupt status is read, it
+ will also be cleared. Clearing the transmit interrupt does
+ not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface
+ will not transmit if its internal recycled transmit
+ buffer array is full. Reading the transmit buffer does
+ not clear the transmit interrupt. If this is NULL, then
+ the transmit buffer status will not be read. If there
+ are no transmit buffers to recycle and TxBuf is not NULL,
+ TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32GetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus, OPTIONAL
+ OUT VOID **TxBuf OPTIONAL
+ );
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ This function places the packet specified by Header and Buffer on the transmit
+ queue. If HeaderSize is nonzero and HeaderSize is not equal to
+ This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If
+ BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL
+ will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be
+ returned. If HeaderSize is nonzero and DestAddr or Protocol is NULL, then
+ EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network
+ interface is busy, then EFI_NOT_READY will be returned. If this packet can be
+ accepted by the transmit engine of the network interface, the packet contents
+ specified by Buffer will be placed on the transmit queue of the network
+ interface, and EFI_SUCCESS will be returned. GetStatus() can be used to
+ determine when the packet has actually been transmitted. The contents of the
+ Buffer must not be modified until the packet has actually been transmitted.
+ The Transmit() function performs nonblocking I/O. A caller who wants to perform
+ blocking I/O, should call Transmit(), and then GetStatus() until the
+ transmitted buffer shows up in the recycled transmit buffer.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by the
+ Transmit() function. If HeaderSize is nonzero, then it must
+ be equal to This->Mode->MediaHeaderSize and the DestAddr and
+ Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is
+ zero, then the media header in Buffer must already be filled
+ in by the caller. If HeaderSize is nonzero, then the media
+ header will be filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored. If HeaderSize is nonzero and SrcAddr
+ is NULL, then This->Mode->CurrentAddress is used for the
+ source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then
+ this parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types,"
+ for examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this
+ transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported
+ value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr, OPTIONAL
+ IN EFI_MAC_ADDRESS *DestAddr, OPTIONAL
+ IN UINT16 *Protocol OPTIONAL
+ );
+
+/**
+ Receives a packet from a network interface.
+
+ This function retrieves one packet from the receive queue of a network interface.
+ If there are no packets on the receive queue, then EFI_NOT_READY will be
+ returned. If there is a packet on the receive queue, and the size of the packet
+ is smaller than BufferSize, then the contents of the packet will be placed in
+ Buffer, and BufferSize will be updated with the actual size of the packet.
+ In addition, if SrcAddr, DestAddr, and Protocol are not NULL, then these values
+ will be extracted from the media header and returned. EFI_SUCCESS will be
+ returned if a packet was successfully received.
+ If BufferSize is smaller than the received packet, then the size of the receive
+ packet will be placed in BufferSize and EFI_BUFFER_TOO_SMALL will be returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media
+ header and the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the HW
+ MAC source address will not be extracted from the media header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from
+ the media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and
+ BufferSize has been updated to the number of
+ bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY No packets have been received on the network interface.
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the received packets.
+ BufferSize has been updated to the required size.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ * The This parameter is NULL
+ * The This parameter does not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ * The BufferSize parameter is NULL
+ * The Buffer parameter is NULL
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ );
+
+/**
+ Nofication call back function for WaitForPacket event.
+
+ @param Event EFI Event.
+ @param SnpPtr Pointer to SNP_DRIVER structure.
+
+**/
+VOID
+EFIAPI
+SnpWaitForPacketNotify (
+ EFI_EVENT Event,
+ VOID *SnpPtr
+ );
+
+#define SNP_MEM_PAGES(x) (((x) - 1) / 4096 + 1)
+
+
+#endif /* _SNP_H_ */
diff --git a/NetworkPkg/SnpDxe/SnpDxe.inf b/NetworkPkg/SnpDxe/SnpDxe.inf
new file mode 100644
index 0000000000..eab97d2e9e
--- /dev/null
+++ b/NetworkPkg/SnpDxe/SnpDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# This module produces EFI SNP Protocol.
+#
+# This module produces Simple Network Protocol upon EFI Network Interface
+# Identifier Protocol, to provide a packet level interface to a network adapter.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SnpDxe
+ MODULE_UNI_FILE = SnpDxe.uni
+ FILE_GUID = A2f436EA-A127-4EF8-957C-8048606FF670
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSnpNiiDriver
+ UNLOAD_IMAGE = NetLibDefaultUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = mSimpleNetworkDriverBinding
+# COMPONENT_NAME = gSimpleNetworkComponentName
+# COMPONENT_NAME2 = gSimpleNetworkComponentName2
+#
+
+[Sources]
+ Receive.c
+ Snp.h
+ Nvdata.c
+ Get_status.c
+ Start.c
+ Snp.c
+ Stop.c
+ Statistics.c
+ Reset.c
+ Shutdown.c
+ Mcast_ip_to_mac.c
+ Transmit.c
+ WaitForPacket.c
+ Receive_filters.c
+ Initialize.c
+ ComponentName.c
+ Callback.c
+ Station_address.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ NetLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
+
+[Protocols]
+ gEfiSimpleNetworkProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SnpDxeExtra.uni
diff --git a/NetworkPkg/SnpDxe/SnpDxe.uni b/NetworkPkg/SnpDxe/SnpDxe.uni
new file mode 100644
index 0000000000..f37bb17fe0
--- /dev/null
+++ b/NetworkPkg/SnpDxe/SnpDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// This module produces EFI SNP Protocol.
+//
+// This module produces Simple Network Protocol upon EFI Network Interface
+// Identifier Protocol, to provide a packet level interface to a network adapter.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces EFI SNP Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces Simple Network Protocol upon EFI Network Interface Identifier Protocol to provide a packet level interface to a network adapter."
+
diff --git a/NetworkPkg/SnpDxe/SnpDxeExtra.uni b/NetworkPkg/SnpDxe/SnpDxeExtra.uni
new file mode 100644
index 0000000000..5cf6e9d18e
--- /dev/null
+++ b/NetworkPkg/SnpDxe/SnpDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SnpDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SNP DXE Driver"
+
+
diff --git a/NetworkPkg/SnpDxe/Start.c b/NetworkPkg/SnpDxe/Start.c
new file mode 100644
index 0000000000..033ca22f66
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Start.c
@@ -0,0 +1,162 @@
+/** @file
+ Implementation of starting a network adapter.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Call UNDI to start the interface and changes the snp state.
+
+ @param Snp pointer to snp driver structure.
+
+ @retval EFI_SUCCESS UNDI is started successfully.
+ @retval EFI_DEVICE_ERROR UNDI could not be started.
+
+**/
+EFI_STATUS
+PxeStart (
+ IN SNP_DRIVER *Snp
+ )
+{
+ PXE_CPB_START_31 *Cpb31;
+
+ Cpb31 = Snp->Cpb;
+ //
+ // Initialize UNDI Start CDB for H/W UNDI
+ //
+ Snp->Cdb.OpCode = PXE_OPCODE_START;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Make changes to H/W UNDI Start CDB if this is
+ // a S/W UNDI.
+ //
+ if (Snp->IsSwUndi) {
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_START_31);
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb31;
+
+ Cpb31->Delay = (UINT64)(UINTN) &SnpUndi32CallbackDelay;
+ Cpb31->Block = (UINT64)(UINTN) &SnpUndi32CallbackBlock;
+
+ //
+ // Virtual == Physical. This can be set to zero.
+ //
+ Cpb31->Virt2Phys = (UINT64)(UINTN) 0;
+ Cpb31->Mem_IO = (UINT64)(UINTN) &SnpUndi32CallbackMemio;
+
+ Cpb31->Map_Mem = (UINT64)(UINTN) &SnpUndi32CallbackMap;
+ Cpb31->UnMap_Mem = (UINT64)(UINTN) &SnpUndi32CallbackUnmap;
+ Cpb31->Sync_Mem = (UINT64)(UINTN) &SnpUndi32CallbackSync;
+
+ Cpb31->Unique_ID = (UINT64)(UINTN) Snp;
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.start() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI could not be started. Return UNDI error.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.start() %xh:%xh\n",
+ Snp->Cdb.StatCode,
+ Snp->Cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set simple network state to Started and return success.
+ //
+ Snp->Mode.State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Change the state of a network interface from "stopped" to "started."
+
+ This function starts a network interface. If the network interface successfully
+ starts, then EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started state.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ Status = EFI_ALREADY_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = PxeStart (Snp);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ //
+ // clear the map_list in SNP structure
+ //
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ Snp->MapList[Index].VirtualAddress = 0;
+ Snp->MapList[Index].MapCookie = 0;
+ }
+
+ Snp->Mode.MCastFilterCount = 0;
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Station_address.c b/NetworkPkg/SnpDxe/Station_address.c
new file mode 100644
index 0000000000..a5c87d4799
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Station_address.c
@@ -0,0 +1,243 @@
+/** @file
+ Implementation of reading the MAC address of a network adapter.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Call UNDI to read the MAC address of the NIC and update the mode structure
+ with the address.
+
+ @param Snp Pointer to snp driver structure.
+
+ @retval EFI_SUCCESS The MAC address of the NIC is read successfully.
+ @retval EFI_DEVICE_ERROR Failed to read the MAC address of the NIC.
+
+**/
+EFI_STATUS
+PxeGetStnAddr (
+ SNP_DRIVER *Snp
+ )
+{
+ PXE_DB_STATION_ADDRESS *Db;
+
+ Db = Snp->Db;
+ Snp->Cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;
+
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_STATION_ADDRESS);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.station_addr() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set new station address in SNP->Mode structure and return success.
+ //
+ CopyMem (
+ &(Snp->Mode.CurrentAddress),
+ &Db->StationAddr,
+ Snp->Mode.HwAddressSize
+ );
+
+ CopyMem (
+ &Snp->Mode.BroadcastAddress,
+ &Db->BroadcastAddr,
+ Snp->Mode.HwAddressSize
+ );
+
+ CopyMem (
+ &Snp->Mode.PermanentAddress,
+ &Db->PermanentAddr,
+ Snp->Mode.HwAddressSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Call UNDI to set a new MAC address for the NIC.
+
+ @param Snp Pointer to Snp driver structure.
+ @param NewMacAddr Pointer to a MAC address to be set for the NIC, if this is
+ NULL then this routine resets the mac address to the NIC's
+ original address.
+
+
+**/
+EFI_STATUS
+PxeSetStnAddr (
+ SNP_DRIVER *Snp,
+ EFI_MAC_ADDRESS *NewMacAddr
+ )
+{
+ PXE_CPB_STATION_ADDRESS *Cpb;
+ PXE_DB_STATION_ADDRESS *Db;
+
+ Cpb = Snp->Cpb;
+ Db = Snp->Db;
+ Snp->Cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
+
+ if (NewMacAddr == NULL) {
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_RESET;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ } else {
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_WRITE;
+ //
+ // Supplying a new address in the CPB will make undi change the mac address to the new one.
+ //
+ CopyMem (&Cpb->StationAddr, NewMacAddr, Snp->Mode.HwAddressSize);
+
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_STATION_ADDRESS);
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
+ }
+
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_STATION_ADDRESS);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.station_addr() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // read the changed address and save it in SNP->Mode structure
+ //
+ PxeGetStnAddr (Snp);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ This function modifies or resets the current station address of a network
+ interface, if supported. If Reset is TRUE, then the current station address is
+ set to the network interface's permanent address. If Reset is FALSE, and the
+ network interface allows its station address to be modified, then the current
+ station address is changed to the address specified by New. If the network
+ interface does not allow its station address to be modified, then
+ EFI_INVALID_PARAMETER will be returned. If the station address is successfully
+ updated on the network interface, EFI_SUCCESS will be returned. If the driver
+ has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param Reset Flag used to reset the station address to the network interface's
+ permanent address.
+ @param New New station address to be used for the network interface.
+
+
+ @retval EFI_SUCCESS The network interface's station address was updated.
+ @retval EFI_NOT_STARTED The Simple Network Protocol interface has not been
+ started by calling Start().
+ @retval EFI_INVALID_PARAMETER The New station address was not accepted by the NIC.
+ @retval EFI_INVALID_PARAMETER Reset is FALSE and New is NULL.
+ @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
+ been initialized by calling Initialize().
+ @retval EFI_DEVICE_ERROR An error occurred attempting to set the new
+ station address.
+ @retval EFI_UNSUPPORTED The NIC does not support changing the network
+ interface's station address.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32StationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Check for invalid parameter combinations.
+ //
+ if ((This == NULL) ||
+ (!Reset && (New == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (Reset) {
+ Status = PxeSetStnAddr (Snp, NULL);
+ } else {
+ Status = PxeSetStnAddr (Snp, New);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Statistics.c b/NetworkPkg/SnpDxe/Statistics.c
new file mode 100644
index 0000000000..480e261780
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Statistics.c
@@ -0,0 +1,224 @@
+/** @file
+ Implementation of collecting the statistics on a network interface.
+
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Snp.h"
+
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ This function resets or collects the statistics on a network interface. If the
+ size of the statistics table specified by StatisticsSize is not big enough for
+ all the statistics that are collected by the network interface, then a partial
+ buffer of statistics is returned in StatisticsTable, StatisticsSize is set to
+ the size required to collect all the available statistics, and
+ EFI_BUFFER_TOO_SMALL is returned.
+ If StatisticsSize is big enough for all the statistics, then StatisticsTable
+ will be filled, StatisticsSize will be set to the size of the returned
+ StatisticsTable structure, and EFI_SUCCESS is returned.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+ If Reset is FALSE, and both StatisticsSize and StatisticsTable are NULL, then
+ no operations will be performed, and EFI_SUCCESS will be returned.
+ If Reset is TRUE, then all of the supported statistics counters on this network
+ interface will be reset to zero.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On output
+ the size, in bytes, of the resulting table of statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics. Type EFI_NETWORK_STATISTICS is
+ defined in "Related Definitions" below.
+
+ @retval EFI_SUCCESS The requested operation succeeded.
+ @retval EFI_NOT_STARTED The Simple Network Protocol interface has not been
+ started by calling Start().
+ @retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is
+ NULL. The current buffer size that is needed to
+ hold all the statistics is returned in StatisticsSize.
+ @retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is
+ not NULL. The current buffer size that is needed
+ to hold all the statistics is returned in
+ StatisticsSize. A partial set of statistics is
+ returned in StatisticsTable.
+ @retval EFI_INVALID_PARAMETER StatisticsSize is NULL and StatisticsTable is not
+ NULL.
+ @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
+ been initialized by calling Initialize().
+ @retval EFI_DEVICE_ERROR An error was encountered collecting statistics
+ from the NIC.
+ @retval EFI_UNSUPPORTED The NIC does not support collecting statistics
+ from the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize, OPTIONAL
+ IN OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ )
+{
+ SNP_DRIVER *Snp;
+ PXE_DB_STATISTICS *Db;
+ UINT64 *Stp;
+ UINT64 Mask;
+ UINTN Size;
+ UINTN Index;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *This.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // if we are not resetting the counters, we have to have a valid stat table
+ // with >0 size. if no reset, no table and no size, return success.
+ //
+ if (!Reset && StatisticsSize == NULL) {
+ Status = (StatisticsTable != NULL) ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+ //
+ // Initialize UNDI Statistics CDB
+ //
+ Snp->Cdb.OpCode = PXE_OPCODE_STATISTICS;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ if (Reset) {
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_STATISTICS_RESET;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Db = Snp->Db;
+ } else {
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_STATISTICS_READ;
+ Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_STATISTICS);
+ Snp->Cdb.DBaddr = (UINT64)(UINTN) (Db = Snp->Db);
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.statistics() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.statistics() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.statistics() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (Reset) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (StatisticsTable == NULL) {
+ *StatisticsSize = sizeof (EFI_NETWORK_STATISTICS);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto ON_EXIT;
+ }
+ //
+ // Convert the UNDI statistics information to SNP statistics
+ // information.
+ //
+ ZeroMem (StatisticsTable, *StatisticsSize);
+ Stp = (UINT64 *) StatisticsTable;
+ Size = 0;
+
+ for (Index = 0, Mask = 1; Index < 64; Index++, Mask = LShiftU64 (Mask, 1), Stp++) {
+ //
+ // There must be room for a full UINT64. Partial
+ // numbers will not be stored.
+ //
+ if ((Index + 1) * sizeof (UINT64) > *StatisticsSize) {
+ break;
+ }
+
+ if ((Db->Supported & Mask) != 0) {
+ *Stp = Db->Data[Index];
+ Size = Index + 1;
+ } else {
+ SetMem (Stp, sizeof (UINT64), 0xFF);
+ }
+ }
+ //
+ // Compute size up to last supported statistic.
+ //
+ while (++Index < 64) {
+ if ((Db->Supported & (Mask = LShiftU64 (Mask, 1))) != 0) {
+ Size = Index;
+ }
+ }
+
+ Size *= sizeof (UINT64);
+
+ if (*StatisticsSize >= Size) {
+ *StatisticsSize = Size;
+ Status = EFI_SUCCESS;
+ } else {
+ *StatisticsSize = Size;
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Stop.c b/NetworkPkg/SnpDxe/Stop.c
new file mode 100644
index 0000000000..f1c1bd847c
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Stop.c
@@ -0,0 +1,120 @@
+/** @file
+ Implementation of stopping a network interface.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Call UNDI to stop the interface and changes the snp state.
+
+ @param Snp Pointer to snp driver structure
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_DEVICE_ERROR SNP is not initialized.
+
+**/
+EFI_STATUS
+PxeStop (
+ SNP_DRIVER *Snp
+ )
+{
+ Snp->Cdb.OpCode = PXE_OPCODE_STOP;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.stop() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
+
+ if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi.stop() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set simple network state to Started and return success.
+ //
+ Snp->Mode.State = EfiSimpleNetworkStopped;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Changes the state of a network interface from "started" to "stopped."
+
+ This function stops a network interface. This call is only valid if the network
+ interface is in the started state. If the network interface was successfully
+ stopped, then EFI_SUCCESS will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
+ instance.
+
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a
+ valid EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = PxeStop (Snp);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/Transmit.c b/NetworkPkg/SnpDxe/Transmit.c
new file mode 100644
index 0000000000..44fdd71f41
--- /dev/null
+++ b/NetworkPkg/SnpDxe/Transmit.c
@@ -0,0 +1,353 @@
+/** @file
+ Implementation of transmitting a packet.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Call UNDI to create the meadia header for the given data buffer.
+
+ @param Snp Pointer to SNP driver structure.
+ @param MacHeaderPtr Address where the media header will be filled in.
+ @param HeaderSize Size of the memory at MacHeaderPtr.
+ @param Buffer Data buffer pointer.
+ @param BufferSize Size of data in the Buffer
+ @param DestAddr Address of the destination mac address buffer.
+ @param SrcAddr Address of the source mac address buffer.
+ @param ProtocolPtr Address of the protocol type.
+
+ @retval EFI_SUCCESS Successfully completed the undi call.
+ @retval Other Error return from undi call.
+
+**/
+EFI_STATUS
+PxeFillHeader (
+ SNP_DRIVER *Snp,
+ VOID *MacHeaderPtr,
+ UINTN HeaderSize,
+ VOID *Buffer,
+ UINTN BufferSize,
+ EFI_MAC_ADDRESS *DestAddr,
+ EFI_MAC_ADDRESS *SrcAddr,
+ UINT16 *ProtocolPtr
+ )
+{
+ PXE_CPB_FILL_HEADER_FRAGMENTED *Cpb;
+
+ Cpb = Snp->Cpb;
+ if (SrcAddr != NULL) {
+ CopyMem (
+ (VOID *) Cpb->SrcAddr,
+ (VOID *) SrcAddr,
+ Snp->Mode.HwAddressSize
+ );
+ } else {
+ CopyMem (
+ (VOID *) Cpb->SrcAddr,
+ (VOID *) &(Snp->Mode.CurrentAddress),
+ Snp->Mode.HwAddressSize
+ );
+ }
+
+ CopyMem (
+ (VOID *) Cpb->DestAddr,
+ (VOID *) DestAddr,
+ Snp->Mode.HwAddressSize
+ );
+
+ //
+ // we need to do the byte swapping
+ //
+ Cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);
+
+ Cpb->PacketLen = (UINT32) (BufferSize);
+ Cpb->MediaHeaderLen = (UINT16) HeaderSize;
+
+ Cpb->FragCnt = 2;
+ Cpb->reserved = 0;
+
+ Cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;
+ Cpb->FragDesc[0].FragLen = (UINT32) HeaderSize;
+ Cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) Buffer;
+ Cpb->FragDesc[1].FragLen = (UINT32) BufferSize;
+
+ Cpb->FragDesc[0].reserved = Cpb->FragDesc[1].reserved = 0;
+
+ Snp->Cdb.OpCode = PXE_OPCODE_FILL_HEADER;
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;
+
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nSnp->undi.fill_header() "));
+
+ (*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);
+
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ return EFI_SUCCESS;
+
+ case PXE_STATCODE_INVALID_PARAMETER:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nSnp->undi.fill_header() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nSnp->undi.fill_header() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+
+/**
+ This routine calls undi to transmit the given data buffer
+
+ @param Snp pointer to SNP driver structure
+ @param Buffer data buffer pointer
+ @param BufferSize Size of data in the Buffer
+
+ @retval EFI_SUCCESS if successfully completed the undi call
+ @retval Other error return from undi call.
+
+**/
+EFI_STATUS
+PxeTransmit (
+ SNP_DRIVER *Snp,
+ VOID *Buffer,
+ UINTN BufferSize
+ )
+{
+ PXE_CPB_TRANSMIT *Cpb;
+ EFI_STATUS Status;
+
+ Cpb = Snp->Cpb;
+ Cpb->FrameAddr = (UINT64) (UINTN) Buffer;
+ Cpb->DataLen = (UINT32) BufferSize;
+
+ Cpb->MediaheaderLen = 0;
+ Cpb->reserved = 0;
+
+ Snp->Cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;
+
+ Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_TRANSMIT);
+ Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
+
+ Snp->Cdb.OpCode = PXE_OPCODE_TRANSMIT;
+ Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
+
+ Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ Snp->Cdb.IFnum = Snp->IfNum;
+ Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nSnp->undi.transmit() "));
+ DEBUG ((EFI_D_NET, "\nSnp->Cdb.OpCode == %x", Snp->Cdb.OpCode));
+ DEBUG ((EFI_D_NET, "\nSnp->Cdb.CPBaddr == %LX", Snp->Cdb.CPBaddr));
+ DEBUG ((EFI_D_NET, "\nSnp->Cdb.DBaddr == %LX", Snp->Cdb.DBaddr));
+ DEBUG ((EFI_D_NET, "\nCpb->FrameAddr == %LX\n", Cpb->FrameAddr));
+
+ (*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);
+
+ DEBUG ((EFI_D_NET, "\nexit Snp->undi.transmit() "));
+
+ //
+ // we will unmap the buffers in get_status call, not here
+ //
+ switch (Snp->Cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ return EFI_SUCCESS;
+
+ case PXE_STATCODE_BUFFER_FULL:
+ case PXE_STATCODE_QUEUE_FULL:
+ case PXE_STATCODE_BUSY:
+ Status = EFI_NOT_READY;
+ DEBUG (
+ (EFI_D_NET,
+ "\nSnp->undi.transmit() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+ break;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nSnp->undi.transmit() %xh:%xh\n",
+ Snp->Cdb.StatFlags,
+ Snp->Cdb.StatCode)
+ );
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ This function places the packet specified by Header and Buffer on the transmit
+ queue. If HeaderSize is nonzero and HeaderSize is not equal to
+ This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If
+ BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL
+ will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be
+ returned. If HeaderSize is nonzero and DestAddr or Protocol is NULL, then
+ EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network
+ interface is busy, then EFI_NOT_READY will be returned. If this packet can be
+ accepted by the transmit engine of the network interface, the packet contents
+ specified by Buffer will be placed on the transmit queue of the network
+ interface, and EFI_SUCCESS will be returned. GetStatus() can be used to
+ determine when the packet has actually been transmitted. The contents of the
+ Buffer must not be modified until the packet has actually been transmitted.
+ The Transmit() function performs nonblocking I/O. A caller who wants to perform
+ blocking I/O, should call Transmit(), and then GetStatus() until the
+ transmitted buffer shows up in the recycled transmit buffer.
+ If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
+
+ @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by the
+ Transmit() function. If HeaderSize is nonzero, then it must
+ be equal to This->Mode->MediaHeaderSize and the DestAddr and
+ Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is
+ zero, then the media header in Buffer must already be filled
+ in by the caller. If HeaderSize is nonzero, then the media
+ header will be filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored. If HeaderSize is nonzero and SrcAddr
+ is NULL, then This->Mode->CurrentAddress is used for the
+ source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then
+ this parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types,"
+ for examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this
+ transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported
+ value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+SnpUndi32Transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr, OPTIONAL
+ IN EFI_MAC_ADDRESS *DestAddr, OPTIONAL
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (Snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (Snp->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (BufferSize < Snp->Mode.MediaHeaderSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto ON_EXIT;
+ }
+
+ //
+ // if the HeaderSize is non-zero, we need to fill up the header and for that
+ // we need the destination address and the protocol
+ //
+ if (HeaderSize != 0) {
+ if (HeaderSize != Snp->Mode.MediaHeaderSize || DestAddr == 0 || Protocol == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Status = PxeFillHeader (
+ Snp,
+ Buffer,
+ HeaderSize,
+ (UINT8 *) Buffer + HeaderSize,
+ BufferSize - HeaderSize,
+ DestAddr,
+ SrcAddr,
+ Protocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ Status = PxeTransmit (Snp, Buffer, BufferSize);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/NetworkPkg/SnpDxe/WaitForPacket.c b/NetworkPkg/SnpDxe/WaitForPacket.c
new file mode 100644
index 0000000000..866a1e8c0e
--- /dev/null
+++ b/NetworkPkg/SnpDxe/WaitForPacket.c
@@ -0,0 +1,86 @@
+/** @file
+ Event handler to check for available packet.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ Nofication call back function for WaitForPacket event.
+
+ @param Event EFI Event.
+ @param SnpPtr Pointer to SNP_DRIVER structure.
+
+**/
+VOID
+EFIAPI
+SnpWaitForPacketNotify (
+ EFI_EVENT Event,
+ VOID *SnpPtr
+ )
+{
+ PXE_DB_GET_STATUS PxeDbGetStatus;
+
+ //
+ // Do nothing if either parameter is a NULL pointer.
+ //
+ if (Event == NULL || SnpPtr == NULL) {
+ return ;
+ }
+ //
+ // Do nothing if the SNP interface is not initialized.
+ //
+ switch (((SNP_DRIVER *) SnpPtr)->Mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ case EfiSimpleNetworkStarted:
+ default:
+ return ;
+ }
+ //
+ // Fill in CDB for UNDI GetStatus().
+ //
+ ((SNP_DRIVER *) SnpPtr)->Cdb.OpCode = PXE_OPCODE_GET_STATUS;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.OpFlags = 0;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.DBsize = (UINT16) (sizeof (UINT32) * 2);
+ ((SNP_DRIVER *) SnpPtr)->Cdb.DBaddr = (UINT64)(UINTN) (((SNP_DRIVER *) SnpPtr)->Db);
+ ((SNP_DRIVER *) SnpPtr)->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.IFnum = ((SNP_DRIVER *) SnpPtr)->IfNum;
+ ((SNP_DRIVER *) SnpPtr)->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Clear contents of DB buffer.
+ //
+ ZeroMem (((SNP_DRIVER *) SnpPtr)->Db, sizeof (UINT32) * 2);
+
+ //
+ // Issue UNDI command and check result.
+ //
+ (*((SNP_DRIVER *) SnpPtr)->IssueUndi32Command) ((UINT64)(UINTN) &((SNP_DRIVER *) SnpPtr)->Cdb);
+
+ if (((SNP_DRIVER *) SnpPtr)->Cdb.StatCode != EFI_SUCCESS) {
+ return ;
+ }
+ //
+ // We might have a packet. Check the receive length and signal
+ // the event if the length is not zero.
+ //
+ CopyMem (
+ &PxeDbGetStatus,
+ ((SNP_DRIVER *) SnpPtr)->Db,
+ sizeof (UINT32) * 2
+ );
+
+ if (PxeDbGetStatus.RxFrameLen != 0) {
+ gBS->SignalEvent (Event);
+ }
+}