From 4542f8b8135f1f1ee5654e25139be9769e139ddd Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Wed, 15 May 2019 20:02:18 +0800 Subject: NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg Signed-off-by: Liming Gao Cc: Siyuan Fu Cc: Jiaxin Wu Reviewed-by: Jiaxin Wu Reviewed-by: Siyuan Fu --- NetworkPkg/SnpDxe/Callback.c | 354 ++++++++++++ NetworkPkg/SnpDxe/ComponentName.c | 430 +++++++++++++++ NetworkPkg/SnpDxe/Get_status.c | 257 +++++++++ NetworkPkg/SnpDxe/Initialize.c | 277 ++++++++++ NetworkPkg/SnpDxe/Mcast_ip_to_mac.c | 173 ++++++ NetworkPkg/SnpDxe/Nvdata.c | 217 ++++++++ NetworkPkg/SnpDxe/Receive.c | 251 +++++++++ NetworkPkg/SnpDxe/Receive_filters.c | 478 ++++++++++++++++ NetworkPkg/SnpDxe/Reset.c | 130 +++++ NetworkPkg/SnpDxe/Shutdown.c | 146 +++++ NetworkPkg/SnpDxe/Snp.c | 862 +++++++++++++++++++++++++++++ NetworkPkg/SnpDxe/Snp.h | 1033 +++++++++++++++++++++++++++++++++++ NetworkPkg/SnpDxe/SnpDxe.inf | 77 +++ NetworkPkg/SnpDxe/SnpDxe.uni | 17 + NetworkPkg/SnpDxe/SnpDxeExtra.uni | 14 + NetworkPkg/SnpDxe/Start.c | 162 ++++++ NetworkPkg/SnpDxe/Station_address.c | 243 ++++++++ NetworkPkg/SnpDxe/Statistics.c | 224 ++++++++ NetworkPkg/SnpDxe/Stop.c | 120 ++++ NetworkPkg/SnpDxe/Transmit.c | 353 ++++++++++++ NetworkPkg/SnpDxe/WaitForPacket.c | 86 +++ 21 files changed, 5904 insertions(+) create mode 100644 NetworkPkg/SnpDxe/Callback.c create mode 100644 NetworkPkg/SnpDxe/ComponentName.c create mode 100644 NetworkPkg/SnpDxe/Get_status.c create mode 100644 NetworkPkg/SnpDxe/Initialize.c create mode 100644 NetworkPkg/SnpDxe/Mcast_ip_to_mac.c create mode 100644 NetworkPkg/SnpDxe/Nvdata.c create mode 100644 NetworkPkg/SnpDxe/Receive.c create mode 100644 NetworkPkg/SnpDxe/Receive_filters.c create mode 100644 NetworkPkg/SnpDxe/Reset.c create mode 100644 NetworkPkg/SnpDxe/Shutdown.c create mode 100644 NetworkPkg/SnpDxe/Snp.c create mode 100644 NetworkPkg/SnpDxe/Snp.h create mode 100644 NetworkPkg/SnpDxe/SnpDxe.inf create mode 100644 NetworkPkg/SnpDxe/SnpDxe.uni create mode 100644 NetworkPkg/SnpDxe/SnpDxeExtra.uni create mode 100644 NetworkPkg/SnpDxe/Start.c create mode 100644 NetworkPkg/SnpDxe/Station_address.c create mode 100644 NetworkPkg/SnpDxe/Statistics.c create mode 100644 NetworkPkg/SnpDxe/Stop.c create mode 100644 NetworkPkg/SnpDxe/Transmit.c create mode 100644 NetworkPkg/SnpDxe/WaitForPacket.c (limited to 'NetworkPkg/SnpDxe') 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.
+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.
+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.
+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.
+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.
+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.
+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.
+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.
+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.
+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.
+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.
+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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef _SNP_H_ +#define _SNP_H_ + + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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.
+# 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.
+// +// 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.
+// +// 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.
+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.
+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.
+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.
+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.
+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.
+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); + } +} -- cgit v1.2.3