* [PATCH v6 2/3] UsbNetworkPkg/UsbCdcEcm: Add USB Cdc ECM devices support
2023-03-09 7:51 [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
@ 2023-03-09 7:51 ` RichardHo [何明忠]
2023-03-09 7:51 ` [PATCH v6 3/3] UsbNetworkPkg/UsbCdcNcm: Add USB Cdc NCM " RichardHo [何明忠]
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: RichardHo [何明忠] @ 2023-03-09 7:51 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Rebecca Cran, Tinh Nguyen,
Tony Lo (羅金松)
This driver provides UEFI driver for USB CDC ECM device
Signed-off-by: Richard Ho <richardho@ami.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Michael Kubacki <mikuback@linux.microsoft.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Rebecca Cran <rebecca@bsdio.com>
Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
Reviewed-by: Tony Lo <tonylo@ami.com>
---
UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf | 42 ++
UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h | 211 ++++++
UsbNetworkPkg/UsbCdcEcm/ComponentName.c | 170 +++++
UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c | 502 +++++++++++++
UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c | 880 +++++++++++++++++++++++
5 files changed, 1805 insertions(+)
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
create mode 100644 UsbNetworkPkg/UsbCdcEcm/ComponentName.c
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
new file mode 100644
index 000000000000..8e19982c1f5b
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
@@ -0,0 +1,42 @@
+## @file
+# This is Usb Cdc Ecm driver for DXE phase.
+#
+# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbCdcEcm
+ FILE_GUID = 07a84945-685d-48ec-a6a1-1b397579fa76
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UsbEcmEntry
+
+[Sources]
+ UsbCdcEcm.c
+ UsbCdcEcm.h
+ UsbEcmFunction.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UsbNetworkPkg/UsbNetworkPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
+ DebugLib
+ UefiUsbLib
+ MemoryAllocationLib
+ BaseMemoryLib
+
+[Protocols]
+ gEfiUsbIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiDriverBindingProtocolGuid
+ gEdkIIUsbEthProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
new file mode 100644
index 000000000000..598b7af14f80
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
@@ -0,0 +1,211 @@
+/** @file
+ Header file contains code for USB Ethernet Control Model
+ driver definitions
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _USB_CDC_ECM_H_
+#define _USB_CDC_ECM_H_
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiUsbLib.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/EdkIIUsbEthernetProtocol.h>
+
+typedef struct {
+ UINTN Signature;
+ EDKII_USB_ETHERNET_PROTOCOL UsbEth;
+ EFI_HANDLE UsbCdcDataHandle;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_CONFIG_DESCRIPTOR *Config;
+ UINT8 NumOfInterface;
+ UINT8 BulkInEndpoint;
+ UINT8 BulkOutEndpoint;
+ UINT8 InterruptEndpoint;
+ EFI_MAC_ADDRESS MacAddress;
+} USB_ETHERNET_DRIVER;
+
+#define USB_ECM_DRIVER_VERSION 1
+#define USB_ETHERNET_BULK_TIMEOUT 1
+#define USB_ETHERNET_TRANSFER_TIMEOUT 200
+
+#define USB_ETHERNET_SIGNATURE SIGNATURE_32('u', 'e', 't', 'h')
+#define USB_ETHERNET_DEV_FROM_THIS(a) CR (a, USB_ETHERNET_DRIVER, UsbEth, USB_ETHERNET_SIGNATURE)
+
+typedef struct {
+ UINT16 Src;
+ UINT16 Dst;
+} BIT_MAP;
+
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbEcmComponentName2;
+
+EFI_STATUS
+EFIAPI
+UsbEcmDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEcmDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEcmDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+LoadAllDescriptor (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
+ );
+
+BOOLEAN
+NextDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
+ IN OUT UINTN *Offset
+ );
+
+EFI_STATUS
+GetFunctionalDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Config,
+ IN UINT8 FunDescriptorType,
+ OUT VOID *DataBuffer
+ );
+
+VOID
+GetEndpoint (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN OUT USB_ETHERNET_DRIVER *UsbEthDriver
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthEcmReceive (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN OUT VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthEcmTransmit (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthEcmInterrupt (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollingInterval,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ );
+
+EFI_STATUS
+EFIAPI
+InterruptCallback (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Status
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthMacAddress (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT EFI_MAC_ADDRESS *MacAddress
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthEcmBulkSize (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT UINTN *BulkSize
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbHeaderFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbUnionFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
+ );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthMcastFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN VOID *McastAddr
+ );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN UINT16 Length,
+ IN VOID *PatternFilter
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ OUT BOOLEAN *PatternActive
+ );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthPacketFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthStatistic (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 FeatureSelector,
+ OUT VOID *Statistic
+ );
+
+#endif
diff --git a/UsbNetworkPkg/UsbCdcEcm/ComponentName.c b/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
new file mode 100644
index 000000000000..e37eecf22965
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
@@ -0,0 +1,170 @@
+/** @file
+ This file contains code for USB Ecm Driver Component Name definitions
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "UsbCdcEcm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbEcmDriverNameTable[] = {
+ {
+ "eng;en",
+ L"USB ECM Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+UsbEcmComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEcmComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbEcmComponentName = {
+ UsbEcmComponentNameGetDriverName,
+ UsbEcmComponentNameGetControllerName,
+ "eng"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbEcmComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbEcmComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbEcmComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language 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[out] DriverName 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
+UsbEcmComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ gUsbEcmDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbEcmComponentName)
+ );
+}
+
+/**
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
+ @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
+UsbEcmComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
new file mode 100644
index 000000000000..eb52d2af7a96
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
@@ -0,0 +1,502 @@
+/** @file
+ This file contains code for USB Ethernet Control Model
+ Driver
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "UsbCdcEcm.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbEcmDriverBinding = {
+ UsbEcmDriverSupported,
+ UsbEcmDriverStart,
+ UsbEcmDriverStop,
+ USB_ECM_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+/**
+ Check if this interface is USB ECM SubType
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+
+ @retval TRUE USB ECM SubType.
+ @retval FALSE Not USB ECM SubType.
+
+**/
+BOOLEAN
+IsSupportedDevice (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((InterfaceDescriptor.InterfaceClass == USB_CDC_CLASS) &&
+ (InterfaceDescriptor.InterfaceSubClass == USB_CDC_ECM_SUBCLASS) &&
+ (InterfaceDescriptor.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ USB ECM Driver Binding Support.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] 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
+UsbEcmDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+}
+
+/**
+ Check if the USB ECM and USB CDC Data interfaces are from the same device.
+
+ @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+ @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Is the same device.
+ @retval EFI_NOT_FOUND Is not the same device.
+
+**/
+EFI_STATUS
+IsSameDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbEthPath,
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
+ )
+{
+ while (1) {
+ if ((UsbEthPath->Type == ACPI_DEVICE_PATH) && (UsbEthPath->SubType == ACPI_DP)) {
+ if (CompareMem ((ACPI_HID_DEVICE_PATH *)UsbCdcDataPath, (ACPI_HID_DEVICE_PATH *)UsbEthPath, sizeof (ACPI_HID_DEVICE_PATH))) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ((UsbEthPath->Type == HARDWARE_DEVICE_PATH) && (UsbEthPath->SubType == HW_PCI_DP)) {
+ if (CompareMem ((PCI_DEVICE_PATH *)UsbCdcDataPath, (PCI_DEVICE_PATH *)UsbEthPath, sizeof (PCI_DEVICE_PATH))) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ((UsbEthPath->Type == MESSAGING_DEVICE_PATH) && (UsbEthPath->SubType == MSG_USB_DP)) {
+ if (IsDevicePathEnd (NextDevicePathNode (UsbEthPath))) {
+ if (((USB_DEVICE_PATH *)UsbEthPath)->ParentPortNumber ==
+ ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
+ {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ if (CompareMem ((USB_DEVICE_PATH *)UsbCdcDataPath, (USB_DEVICE_PATH *)UsbEthPath, sizeof (USB_DEVICE_PATH))) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ UsbEthPath = NextDevicePathNode (UsbEthPath);
+ UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
+ }
+}
+
+/**
+ Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
+
+ @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+ @param[in, out] UsbCdcDataHandle A pointer to the EFI_HANDLE for USB CDC Data.
+
+ @retval TRUE USB CDC Data(UsbIo) installed.
+ @retval FALSE USB CDC Data(UsbIo) did not installed.
+
+**/
+BOOLEAN
+IsUsbCdcData (
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbEthPath,
+ IN OUT EFI_HANDLE *UsbCdcDataHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Interface.InterfaceClass == USB_CDC_DATA_CLASS) &&
+ (Interface.InterfaceSubClass == USB_CDC_DATA_SUBCLASS) &&
+ (Interface.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&UsbCdcDataPath
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = IsSameDevice (UsbEthPath, UsbCdcDataPath);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (UsbCdcDataHandle, &HandleBuffer[Index], sizeof (EFI_HANDLE));
+ FreePool (HandleBuffer);
+ return TRUE;
+ }
+ }
+ }
+
+ FreePool (HandleBuffer);
+ return FALSE;
+}
+
+/**
+ Call Back Function.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+CallbackFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Interface.InterfaceClass == USB_CDC_CLASS) &&
+ (Interface.InterfaceSubClass == USB_CDC_ECM_SUBCLASS) &&
+ (Interface.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+ }
+
+ FreePool (HandleBuffer);
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB ECM Driver Binding Start.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEcmDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VOID *Reg;
+ EFI_EVENT Event;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
+ EFI_HANDLE UsbCdcDataHandle;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&UsbEthPath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+ }
+
+ Status = IsUsbCdcData (UsbEthPath, &UsbCdcDataHandle) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CallbackFunction, NULL, &Event);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->RegisterProtocolNotify (&gEfiUsbIoProtocolGuid, Event, &Reg);
+ return Status;
+ }
+
+ UsbEthDriver = AllocateZeroPool (sizeof (USB_ETHERNET_DRIVER));
+ if (!UsbEthDriver) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = LoadAllDescriptor (UsbIo, &UsbEthDriver->Config);
+ ASSERT_EFI_ERROR (Status);
+
+ GetEndpoint (UsbIo, UsbEthDriver);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ UsbEthDriver->Signature = USB_ETHERNET_SIGNATURE;
+ UsbEthDriver->NumOfInterface = Interface.InterfaceNumber;
+ UsbEthDriver->UsbCdcDataHandle = UsbCdcDataHandle;
+ UsbEthDriver->UsbIo = UsbIo;
+ UsbEthDriver->UsbEth.UsbEthReceive = UsbEthEcmReceive;
+ UsbEthDriver->UsbEth.UsbEthTransmit = UsbEthEcmTransmit;
+ UsbEthDriver->UsbEth.UsbEthInterrupt = UsbEthEcmInterrupt;
+ UsbEthDriver->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
+ UsbEthDriver->UsbEth.UsbEthMaxBulkSize = UsbEthEcmBulkSize;
+ UsbEthDriver->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
+ UsbEthDriver->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
+ UsbEthDriver->UsbEth.UsbEthFunDescriptor = GetUsbEthFunDescriptor;
+ UsbEthDriver->UsbEth.SetUsbEthMcastFilter = SetUsbEthMcastFilter;
+ UsbEthDriver->UsbEth.SetUsbEthPowerPatternFilter = SetUsbEthPowerFilter;
+ UsbEthDriver->UsbEth.GetUsbEthPowerPatternFilter = GetUsbEthPowerFilter;
+ UsbEthDriver->UsbEth.SetUsbEthPacketFilter = SetUsbEthPacketFilter;
+ UsbEthDriver->UsbEth.GetUsbEthStatistic = GetUsbEthStatistic;
+
+ Status = gBS->InstallProtocolInterface (
+ &ControllerHandle,
+ &gEdkIIUsbEthProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(UsbEthDriver->UsbEth)
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ FreePool (UsbEthDriver);
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ USB ECM Driver Binding Stop.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to stop driver on
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param[in] 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
+UsbEcmDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEdkIIUsbEthProtocolGuid,
+ (VOID **)&UsbEthProtocol,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (UsbEthProtocol);
+
+ Status = gBS->UninstallProtocolInterface (
+ ControllerHandle,
+ &gEdkIIUsbEthProtocolGuid,
+ UsbEthProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ FreePool (UsbEthDriver->Config);
+ FreePool (UsbEthDriver);
+ return Status;
+}
+
+/**
+ Entrypoint of ECM Driver.
+
+ This function is the entrypoint of ECM Driver. It installs Driver Binding
+ Protocols together with Component Name Protocols.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEcmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gUsbEcmDriverBinding.DriverBindingHandle = ImageHandle;
+ gUsbEcmDriverBinding.ImageHandle = ImageHandle;
+
+ return gBS->InstallMultipleProtocolInterfaces (
+ &gUsbEcmDriverBinding.DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gUsbEcmDriverBinding,
+ &gEfiComponentName2ProtocolGuid,
+ &gUsbEcmComponentName2,
+ NULL
+ );
+}
diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c b/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
new file mode 100644
index 000000000000..1017278a5d4d
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
@@ -0,0 +1,880 @@
+/** @file
+ This file contains code for USB Ethernet descriptor
+ and specific requests implement.
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UsbCdcEcm.h"
+
+/**
+ Load All of device descriptor.
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+ @param[out] ConfigDesc A pointer to the configuration descriptor.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
+ buffer specified by DescriptorLength and Descriptor
+ is not large enough to hold the result of the request.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
+ status is returned in Status.
+
+**/
+EFI_STATUS
+LoadAllDescriptor (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ EFI_USB_CONFIG_DESCRIPTOR Tmp;
+
+ Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->AllocatePool (EfiBootServicesData, Tmp.TotalLength, (VOID **)ConfigDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbGetDescriptor (
+ UsbIo,
+ USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
+ 0,
+ Tmp.TotalLength,
+ *ConfigDesc,
+ &TransStatus
+ );
+ return Status;
+}
+
+/**
+ Returns pointer to the next descriptor for the pack of USB descriptors
+ located in continues memory segment
+
+ @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
+ @param[in, out] Offset A pointer to the sum of descriptor length.
+
+ @retval TRUE The request executed successfully.
+ @retval FALSE No next descriptor.
+
+**/
+BOOLEAN
+NextDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
+ IN OUT UINTN *Offset
+ )
+{
+ if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
+ return FALSE;
+ }
+
+ if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
+ return FALSE;
+ }
+
+ *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
+ if ( *Offset >= Desc->TotalLength ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Read Function descriptor
+
+ @param[in] Config A pointer to all of configuration.
+ @param[in] FunDescriptorType USB CDC class descriptor SubType.
+ @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
+
+ @retval EFI_SUCCESS The device capability descriptor was retrieved
+ successfully.
+ @retval EFI_UNSUPPORTED No supported.
+ @retval EFI_NOT_FOUND The device capability descriptor was not found.
+
+**/
+EFI_STATUS
+GetFunctionalDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Config,
+ IN UINT8 FunDescriptorType,
+ OUT VOID *DataBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+
+ Status = EFI_NOT_FOUND;
+
+ for (Offset = 0; NextDescriptor (Config, &Offset);) {
+ Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
+ if (Interface->DescriptorType == CS_INTERFACE) {
+ if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
+ switch (FunDescriptorType) {
+ case HEADER_FUN_DESCRIPTOR:
+ CopyMem (
+ DataBuffer,
+ (USB_HEADER_FUN_DESCRIPTOR *)Interface,
+ sizeof (USB_HEADER_FUN_DESCRIPTOR)
+ );
+ return EFI_SUCCESS;
+ case UNION_FUN_DESCRIPTOR:
+ CopyMem (
+ DataBuffer,
+ (USB_UNION_FUN_DESCRIPTOR *)Interface,
+ ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
+ );
+ return EFI_SUCCESS;
+ case ETHERNET_FUN_DESCRIPTOR:
+ CopyMem (
+ DataBuffer,
+ (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
+ sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
+ );
+ return EFI_SUCCESS;
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+ @param[in, out] UsbEthDriver A pointer to the USB_ETHERNET_DRIVER instance.
+
+**/
+VOID
+GetEndpoint (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN OUT USB_ETHERNET_DRIVER *UsbEthDriver
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT32 Result;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Interface.NumEndpoints == 0) {
+ Status = UsbSetInterface (UsbIo, Interface.InterfaceNumber, 1, &Result);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ for (Index = 0; Index < Interface.NumEndpoints; Index++) {
+ Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
+ ASSERT_EFI_ERROR (Status);
+
+ switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
+ case USB_ENDPOINT_BULK:
+ if (Endpoint.EndpointAddress & BIT7) {
+ UsbEthDriver->BulkInEndpoint = Endpoint.EndpointAddress;
+ } else {
+ UsbEthDriver->BulkOutEndpoint = Endpoint.EndpointAddress;
+ }
+
+ break;
+ case USB_ENDPOINT_INTERRUPT:
+ UsbEthDriver->InterruptEndpoint = Endpoint.EndpointAddress;
+ break;
+ }
+ }
+}
+
+/**
+ This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
+
+ @param[in] Cdb A pointer to the command descriptor block.
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param[in, out] PacketLength A pointer to the PacketLength.
+
+ @retval EFI_SUCCESS The bulk transfer has been successfully executed.
+ @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
+ @retval EFI_TIMEOUT The control transfer fails due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthEcmReceive (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN OUT VOID *Packet,
+ IN OUT UINTN *PacketLength
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT32 TransStatus;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = gBS->HandleProtocol (
+ UsbEthDriver->UsbCdcDataHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthDriver->BulkInEndpoint == 0) {
+ GetEndpoint (UsbIo, UsbEthDriver);
+ }
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkInEndpoint,
+ Packet,
+ PacketLength,
+ USB_ETHERNET_BULK_TIMEOUT,
+ &TransStatus
+ );
+ return Status;
+}
+
+/**
+ This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
+
+ @param[in] Cdb A pointer to the command descriptor block.
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Packet A pointer to the buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param[in, out] PacketLength A pointer to the PacketLength.
+
+ @retval EFI_SUCCESS The bulk transfer has been successfully executed.
+ @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
+ @retval EFI_TIMEOUT The control transfer fails due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthEcmTransmit (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN VOID *Packet,
+ IN OUT UINTN *PacketLength
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT32 TransStatus;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = gBS->HandleProtocol (
+ UsbEthDriver->UsbCdcDataHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthDriver->BulkOutEndpoint == 0) {
+ GetEndpoint (UsbIo, UsbEthDriver);
+ }
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkOutEndpoint,
+ Packet,
+ PacketLength,
+ USB_ETHERNET_BULK_TIMEOUT,
+ &TransStatus
+ );
+ return Status;
+}
+
+/**
+ Async USB transfer callback routine.
+
+ @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
+ transfer completed successfully.
+ @param[in] DataLength The length of Data received or sent via the Asynchronous
+ Transfer, if transfer successfully completes.
+ @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
+ @param[in] Status Indicates the result of the asynchronous transfer.
+
+ @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
+ @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InterruptCallback (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Status
+ )
+{
+ if ((Data == NULL) || (Context == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == USB_CDC_NETWORK_CONNECTION) {
+ CopyMem (
+ (EFI_USB_DEVICE_REQUEST *)Context,
+ (EFI_USB_DEVICE_REQUEST *)Data,
+ sizeof (EFI_USB_DEVICE_REQUEST)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to manage a USB device with an interrupt transfer pipe.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
+ FALSE, the interrupt transfer is deleted from the device's interrupt
+ transfer queue.
+ @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
+ executed.This parameter is required when IsNewTransfer is TRUE. The
+ value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
+ The units are in milliseconds.
+ @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
+
+ @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
+ @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthEcmInterrupt (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollingInterval,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ UINTN DataLength;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+ DataLength = 0;
+
+ if (IsNewTransfer == TRUE) {
+ DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
+ Status = UsbEthDriver->UsbIo->UsbAsyncInterruptTransfer (
+ UsbEthDriver->UsbIo,
+ UsbEthDriver->InterruptEndpoint,
+ IsNewTransfer,
+ PollingInterval,
+ DataLength,
+ (EFI_ASYNC_USB_TRANSFER_CALLBACK)InterruptCallback,
+ Request
+ );
+ } else {
+ Status = UsbEthDriver->UsbIo->UsbAsyncInterruptTransfer (
+ UsbEthDriver->UsbIo,
+ UsbEthDriver->InterruptEndpoint,
+ IsNewTransfer,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the USB Ethernet Mac Address.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
+
+ @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthMacAddress (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT EFI_MAC_ADDRESS *MacAddress
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
+ CHAR16 *Data;
+ CHAR16 *DataPtr;
+ CHAR16 TmpStr[1];
+ UINT8 Index;
+ UINT8 Hi;
+ UINT8 Low;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ Status = UsbEthDriver->UsbIo->UsbGetStringDescriptor (
+ UsbEthDriver->UsbIo,
+ 0x409, // English-US Language ID
+ UsbEthDescriptor.MacAddress,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ DataPtr = Data;
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
+ DataPtr++;
+ Hi = (UINT8)StrHexToUintn (TmpStr);
+ CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
+ DataPtr++;
+ Low = (UINT8)StrHexToUintn (TmpStr);
+ MacAddress->Addr[Index] = (Hi << 4) | Low;
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the USB Ethernet Bulk transfer data size.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] BulkSize A pointer to the Bulk transfer data size.
+
+ @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
+ @retval other Failed to retrieve the bulk transfer data size.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthEcmBulkSize (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT UINTN *BulkSize
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
+ return Status;
+}
+
+/**
+ Retrieves the USB Header functional Descriptor.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
+
+ @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbHeaderFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ if (UsbHeaderFunDescriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetFunctionalDescriptor (UsbEthDriver->Config, HEADER_FUN_DESCRIPTOR, UsbHeaderFunDescriptor);
+ return Status;
+}
+
+/**
+ Retrieves the USB Union functional Descriptor.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
+
+ @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbUnionFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ if (UsbUnionFunDescriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetFunctionalDescriptor (UsbEthDriver->Config, UNION_FUN_DESCRIPTOR, UsbUnionFunDescriptor);
+ return Status;
+}
+
+/**
+ Retrieves the USB Ethernet functional Descriptor.
+
+ This function get the Mac Address, Ethernet statistics, maximum segment size,
+ number of multicast filters, and number of pattern filters from Ethernet
+ functional Descriptor.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
+
+ @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ if (UsbEthFunDescriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetFunctionalDescriptor (UsbEthDriver->Config, ETHERNET_FUN_DESCRIPTOR, UsbEthFunDescriptor);
+ return Status;
+}
+
+/**
+ This request sets the Ethernet device multicast filters as specified in the
+ sequential list of 48 bit Ethernet multicast addresses.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value Number of filters.
+ @param[in] McastAddr A pointer to the value of the multicast addresses.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthMcastFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN VOID *McastAddr
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+ Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
+ Request.Value = Value;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = Value * 6;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataOut,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ McastAddr,
+ Request.Length,
+ &TransStatus
+ );
+}
+
+/**
+ This request sets up the specified Ethernet power management pattern filter as
+ described in the data structure.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value Number of filters.
+ @param[in] Length Size of the power management pattern filter data.
+ @param[in] PatternFilter A pointer to the power management pattern filter structure.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN UINT16 Length,
+ IN VOID *PatternFilter
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+ Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
+ Request.Value = Value;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = Length;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataOut,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ PatternFilter,
+ Length,
+ &TransStatus
+ );
+}
+
+/**
+ This request retrieves the status of the specified Ethernet power management
+ pattern filter from the device.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value The filter number.
+ @param[out] PatternActive A pointer to the pattern active boolean.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ OUT BOOLEAN *PatternActive
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
+ Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
+ Request.Value = Value;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = USB_ETH_POWER_FILTER_LENGTH;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataIn,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ PatternActive,
+ USB_ETH_POWER_FILTER_LENGTH,
+ &TransStatus
+ );
+}
+
+BIT_MAP gTable[] = {
+ { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, USB_ETH_PACKET_TYPE_DIRECTED },
+ { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, USB_ETH_PACKET_TYPE_BROADCAST },
+ { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, USB_ETH_PACKET_TYPE_MULTICAST },
+ { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, USB_ETH_PACKET_TYPE_PROMISCUOUS },
+ { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, USB_ETH_PACKET_TYPE_ALL_MULTICAST },
+};
+
+/**
+ Convert value between PXE receive filter and USB ETH packet filter.
+
+ @param[in] Value PXE filter data.
+ @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
+
+**/
+VOID
+ConvertFilter (
+ IN UINT16 Value,
+ OUT UINT16 *CdcFilter
+ )
+{
+ UINT32 Index;
+ UINT32 Count;
+
+ Count = sizeof (gTable)/sizeof (gTable[0]);
+
+ for (Index = 0; (gTable[Index].Src != 0) && (Index < Count); Index++) {
+ if (gTable[Index].Src & Value) {
+ *CdcFilter |= gTable[Index].Dst;
+ }
+ }
+}
+
+/**
+ This request is used to configure device Ethernet packet filter settings.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value Packet Filter Bitmap.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthPacketFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ UINT16 CommandFilter;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+ CommandFilter = 0;
+
+ ConvertFilter (Value, &CommandFilter);
+
+ Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+ Request.Request = SET_ETH_PACKET_FILTER_REQ;
+ Request.Value = CommandFilter;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = USB_ETH_PACKET_FILTER_LENGTH;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbNoData,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ NULL,
+ USB_ETH_PACKET_FILTER_LENGTH,
+ &TransStatus
+ );
+}
+
+/**
+ This request is used to retrieve a statistic based on the feature selector.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] FeatureSelector Value of the feature selector.
+ @param[out] Statistic A pointer to the 32 bit unsigned integer.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthStatistic (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 FeatureSelector,
+ OUT VOID *Statistic
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthFunDescriptor.EthernetStatistics == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
+ Request.Request = GET_ETH_STATISTIC_REQ;
+ Request.Value = FeatureSelector;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = USB_ETH_STATISTIC;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataIn,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ Statistic,
+ USB_ETH_STATISTIC,
+ &TransStatus
+ );
+}
--
2.35.1.windows.2
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v6 3/3] UsbNetworkPkg/UsbCdcNcm: Add USB Cdc NCM devices support
2023-03-09 7:51 [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
2023-03-09 7:51 ` [PATCH v6 2/3] UsbNetworkPkg/UsbCdcEcm: Add USB Cdc ECM " RichardHo [何明忠]
@ 2023-03-09 7:51 ` RichardHo [何明忠]
2023-03-27 14:59 ` [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS " Tinh Nguyen
` (2 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: RichardHo [何明忠] @ 2023-03-09 7:51 UTC (permalink / raw)
To: devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Rebecca Cran, Tinh Nguyen,
Tony Lo (羅金松)
This driver provides UEFI driver for USB CDC NCM device
Signed-off-by: Richard Ho <richardho@ami.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Michael Kubacki <mikuback@linux.microsoft.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Rebecca Cran <rebecca@bsdio.com>
Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
Reviewed-by: Tony Lo <tonylo@ami.com>
---
UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf | 42 +
UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h | 245 ++++++
UsbNetworkPkg/UsbCdcNcm/ComponentName.c | 170 ++++
UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c | 506 ++++++++++++
UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c | 966 +++++++++++++++++++++++
5 files changed, 1929 insertions(+)
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
create mode 100644 UsbNetworkPkg/UsbCdcNcm/ComponentName.c
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
new file mode 100644
index 000000000000..bd085bdd0037
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
@@ -0,0 +1,42 @@
+## @file
+# This is Usb Cdc Ncm driver for DXE phase.
+#
+# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbCdcNcm
+ FILE_GUID = 52230d31-6c11-4442-b262-bec6bfe84efa
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UsbNcmEntry
+
+[Sources]
+ UsbCdcNcm.c
+ UsbCdcNcm.h
+ UsbNcmFunction.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UsbNetworkPkg/UsbNetworkPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
+ DebugLib
+ UefiUsbLib
+ MemoryAllocationLib
+ BaseMemoryLib
+
+[Protocols]
+ gEfiUsbIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiDriverBindingProtocolGuid
+ gEdkIIUsbEthProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
new file mode 100644
index 000000000000..f8c21302f170
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
@@ -0,0 +1,245 @@
+/** @file
+ Header file for USB Network Control Model driver
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _USB_CDC_NCM_H_
+#define _USB_CDC_NCM_H_
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiUsbLib.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/EdkIIUsbEthernetProtocol.h>
+
+typedef struct {
+ UINTN Signature;
+ EDKII_USB_ETHERNET_PROTOCOL UsbEth;
+ EFI_HANDLE UsbCdcDataHandle;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_CONFIG_DESCRIPTOR *Config;
+ UINT8 NumOfInterface;
+ UINT8 BulkInEndpoint;
+ UINT8 BulkOutEndpoint;
+ UINT8 InterruptEndpoint;
+ EFI_MAC_ADDRESS MacAddress;
+ UINT16 BulkOutSequence;
+ UINT8 *BulkBuffer;
+ UINT8 TotalDatagram;
+ UINT8 NowDatagram;
+} USB_ETHERNET_DRIVER;
+
+#define USB_NCM_DRIVER_VERSION 1
+#define USB_ETHERNET_BULK_TIMEOUT 1
+#define USB_ETHERNET_TRANSFER_TIMEOUT 200
+#define USB_NCM_MAX_NTB_SIZE 0xFFFF
+#define USB_ETHERNET_FRAME_SIZE 0x5F2 // MAX ethernet frame size
+
+// Defined in USB NCM 1.0 spec., section 3.2 and 3.3
+#define USB_NCM_NTH_SIGN_16 0x484D434E
+#define USB_NCM_NDP_SIGN_16 0x304D434E
+#define USB_NCM_NDP_SIGN_16_CRC 0x314D434E
+#define USB_NCM_NTH_LENGTH 0x000C
+#define USB_NCM_NDP_LENGTH 0x0010// at least 16
+
+// USB NCM Transfer header structure - UINT16
+typedef struct {
+ UINT32 Signature;
+ UINT16 HeaderLength;
+ UINT16 Sequence;
+ UINT16 BlockLength;
+ UINT16 NdpIndex;
+} USB_NCM_TRANSFER_HEADER_16;
+
+// USB NCM Datagram pointer structure - UINT16
+typedef struct {
+ UINT32 Signature;
+ UINT16 Length;
+ UINT16 NextNdpIndex;
+} USB_NCM_DATAGRAM_POINTER_16;
+
+// USB NCM Datagram structure
+typedef struct {
+ UINT16 DatagramIndex;
+ UINT16 DatagramLength;
+} USB_NCM_DATA_GRAM;
+
+#define USB_ETHERNET_SIGNATURE SIGNATURE_32('u', 'e', 't', 'h')
+#define USB_ETHERNET_DEV_FROM_THIS(a) CR (a, USB_ETHERNET_DRIVER, UsbEth, USB_ETHERNET_SIGNATURE)
+
+typedef struct {
+ UINT16 Src;
+ UINT16 Dst;
+} BIT_MAP;
+
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbNcmComponentName2;
+
+EFI_STATUS
+EFIAPI
+UsbNcmDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+LoadAllDescriptor (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
+ );
+
+BOOLEAN
+NextDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
+ IN OUT UINTN *Offset
+ );
+
+EFI_STATUS
+GetFunctionalDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Config,
+ IN UINT8 FunDescriptorType,
+ OUT VOID *DataBuffer
+ );
+
+VOID
+GetEndpoint (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN OUT USB_ETHERNET_DRIVER *UsbEthDriver
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmReceive (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN OUT VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmTransmit (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmInterrupt (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollingInterval,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ );
+
+EFI_STATUS
+EFIAPI
+InterruptCallback (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Status
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthMacAddress (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT EFI_MAC_ADDRESS *MacAddress
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmBulkSize (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT UINTN *BulkSize
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbHeaderFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbUnionFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
+ );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthMcastFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN VOID *McastAddr
+ );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN UINT16 Length,
+ IN VOID *PatternFilter
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ OUT BOOLEAN *PatternActive
+ );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthPacketFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value
+ );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthStatistic (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 FeatureSelector,
+ OUT VOID *Statistic
+ );
+
+#endif
diff --git a/UsbNetworkPkg/UsbCdcNcm/ComponentName.c b/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
new file mode 100644
index 000000000000..3cf3dc222df9
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
@@ -0,0 +1,170 @@
+/** @file
+ This file contains code for USB Ncm Driver Component Name definitions
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "UsbCdcNcm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbNcmDriverNameTable[] = {
+ {
+ "eng;en",
+ L"USB NCM Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+UsbNcmComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+UsbNcmComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbNcmComponentName = {
+ UsbNcmComponentNameGetDriverName,
+ UsbNcmComponentNameGetControllerName,
+ "eng"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbNcmComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbNcmComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbNcmComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language 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[out] DriverName 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
+UsbNcmComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ gUsbNcmDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbNcmComponentName)
+ );
+}
+
+/**
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
+ @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
+UsbNcmComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
new file mode 100644
index 000000000000..f67e6aab695f
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
@@ -0,0 +1,506 @@
+/** @file
+ This file contains code for USB Network Control Model
+ binding driver
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UsbCdcNcm.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbNcmDriverBinding = {
+ UsbNcmDriverSupported,
+ UsbNcmDriverStart,
+ UsbNcmDriverStop,
+ USB_NCM_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+/**
+ Check if this interface is USB NCM SubType
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+
+ @retval TRUE USB NCM SubType.
+ @retval FALSE Not USB NCM SubType.
+
+**/
+BOOLEAN
+IsSupportedDevice (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((InterfaceDescriptor.InterfaceClass == USB_CDC_CLASS) &&
+ (InterfaceDescriptor.InterfaceSubClass == USB_CDC_NCM_SUBCLASS) &&
+ (InterfaceDescriptor.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ USB NCM Driver Binding Support.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] 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
+UsbNcmDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+}
+
+/**
+ Check if the USB NCM and USB CDC Data interfaces are from the same device.
+
+ @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+ @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Is the same device.
+ @retval EFI_NOT_FOUND Is not the same device.
+
+**/
+EFI_STATUS
+IsSameDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbEthPath,
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
+ )
+{
+ while (1) {
+ if ((UsbEthPath->Type == ACPI_DEVICE_PATH) && (UsbEthPath->SubType == ACPI_DP)) {
+ if (CompareMem ((ACPI_HID_DEVICE_PATH *)UsbCdcDataPath, (ACPI_HID_DEVICE_PATH *)UsbEthPath, sizeof (ACPI_HID_DEVICE_PATH))) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ((UsbEthPath->Type == HARDWARE_DEVICE_PATH) && (UsbEthPath->SubType == HW_PCI_DP)) {
+ if (CompareMem ((PCI_DEVICE_PATH *)UsbCdcDataPath, (PCI_DEVICE_PATH *)UsbEthPath, sizeof (PCI_DEVICE_PATH))) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ((UsbEthPath->Type == MESSAGING_DEVICE_PATH) && (UsbEthPath->SubType == MSG_USB_DP)) {
+ if (IsDevicePathEnd (NextDevicePathNode (UsbEthPath))) {
+ if (((USB_DEVICE_PATH *)UsbEthPath)->ParentPortNumber ==
+ ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
+ {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ if (CompareMem ((USB_DEVICE_PATH *)UsbCdcDataPath, (USB_DEVICE_PATH *)UsbEthPath, sizeof (USB_DEVICE_PATH))) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ UsbEthPath = NextDevicePathNode (UsbEthPath);
+ UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
+ }
+}
+
+/**
+ Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
+
+ @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+ @param[in, out] UsbCdcDataHandle A pointer to the EFI_HANDLE for USB CDC Data.
+
+ @retval TRUE USB CDC Data(UsbIo) installed.
+ @retval FALSE USB CDC Data(UsbIo) did not installed.
+
+**/
+BOOLEAN
+IsUsbCdcData (
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbEthPath,
+ IN OUT EFI_HANDLE *UsbCdcDataHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Interface.InterfaceClass == USB_CDC_DATA_CLASS) &&
+ (Interface.InterfaceSubClass == USB_CDC_DATA_SUBCLASS) &&
+ (Interface.InterfaceProtocol == USB_NCM_NTB_PROTOCOL))
+ {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&UsbCdcDataPath
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = IsSameDevice (UsbEthPath, UsbCdcDataPath);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (UsbCdcDataHandle, &HandleBuffer[Index], sizeof (EFI_HANDLE));
+ FreePool (HandleBuffer);
+ return TRUE;
+ }
+ }
+ }
+
+ FreePool (HandleBuffer);
+ return FALSE;
+}
+
+/**
+ Call Back Function.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+CallbackFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Interface.InterfaceClass == USB_CDC_CLASS) &&
+ (Interface.InterfaceSubClass == USB_CDC_NCM_SUBCLASS) &&
+ (Interface.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+ }
+
+ FreePool (HandleBuffer);
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB NCM Driver Binding Start.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VOID *Reg;
+ EFI_EVENT Event;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
+ EFI_HANDLE UsbCdcDataHandle;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&UsbEthPath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+ }
+
+ Status = IsUsbCdcData (UsbEthPath, &UsbCdcDataHandle) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CallbackFunction, NULL, &Event);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->RegisterProtocolNotify (&gEfiUsbIoProtocolGuid, Event, &Reg);
+ return Status;
+ }
+
+ UsbEthDriver = AllocateZeroPool (sizeof (USB_ETHERNET_DRIVER));
+ if (!UsbEthDriver) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = LoadAllDescriptor (UsbIo, &UsbEthDriver->Config);
+ ASSERT_EFI_ERROR (Status);
+
+ GetEndpoint (UsbIo, UsbEthDriver);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ UsbEthDriver->Signature = USB_ETHERNET_SIGNATURE;
+ UsbEthDriver->NumOfInterface = Interface.InterfaceNumber;
+ UsbEthDriver->UsbCdcDataHandle = UsbCdcDataHandle;
+ UsbEthDriver->UsbIo = UsbIo;
+ UsbEthDriver->UsbEth.UsbEthReceive = UsbEthNcmReceive;
+ UsbEthDriver->UsbEth.UsbEthTransmit = UsbEthNcmTransmit;
+ UsbEthDriver->UsbEth.UsbEthInterrupt = UsbEthNcmInterrupt;
+ UsbEthDriver->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
+ UsbEthDriver->UsbEth.UsbEthMaxBulkSize = UsbEthNcmBulkSize;
+ UsbEthDriver->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
+ UsbEthDriver->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
+ UsbEthDriver->UsbEth.UsbEthFunDescriptor = GetUsbEthFunDescriptor;
+ UsbEthDriver->UsbEth.SetUsbEthMcastFilter = SetUsbEthMcastFilter;
+ UsbEthDriver->UsbEth.SetUsbEthPowerPatternFilter = SetUsbEthPowerFilter;
+ UsbEthDriver->UsbEth.GetUsbEthPowerPatternFilter = GetUsbEthPowerFilter;
+ UsbEthDriver->UsbEth.SetUsbEthPacketFilter = SetUsbEthPacketFilter;
+ UsbEthDriver->UsbEth.GetUsbEthStatistic = GetUsbEthStatistic;
+
+ UsbEthDriver->BulkBuffer = AllocateZeroPool (USB_NCM_MAX_NTB_SIZE);
+
+ Status = gBS->InstallProtocolInterface (
+ &ControllerHandle,
+ &gEdkIIUsbEthProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(UsbEthDriver->UsbEth)
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ FreePool (UsbEthDriver);
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ USB NCM Driver Binding Stop.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to stop driver on
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param[in] 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
+UsbNcmDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEdkIIUsbEthProtocolGuid,
+ (VOID **)&UsbEthProtocol,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (UsbEthProtocol);
+
+ Status = gBS->UninstallProtocolInterface (
+ ControllerHandle,
+ &gEdkIIUsbEthProtocolGuid,
+ UsbEthProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ FreePool (UsbEthDriver->Config);
+ FreePool (UsbEthDriver->BulkBuffer);
+ FreePool (UsbEthDriver);
+ return Status;
+}
+
+/**
+ Entrypoint of NCM Driver.
+
+ This function is the entrypoint of NCM Driver. It installs Driver Binding
+ Protocols together with Component Name Protocols.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbNcmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gUsbNcmDriverBinding.DriverBindingHandle = ImageHandle;
+ gUsbNcmDriverBinding.ImageHandle = ImageHandle;
+
+ return gBS->InstallMultipleProtocolInterfaces (
+ &gUsbNcmDriverBinding.DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gUsbNcmDriverBinding,
+ &gEfiComponentName2ProtocolGuid,
+ &gUsbNcmComponentName2,
+ NULL
+ );
+}
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
new file mode 100644
index 000000000000..24ced413d60b
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
@@ -0,0 +1,966 @@
+/** @file
+ This file contains code for USB Ethernet descriptor
+ and specific requests implement.
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UsbCdcNcm.h"
+
+/**
+ Load All of device descriptor.
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+ @param[out] ConfigDesc A pointer to the configuration descriptor.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
+ buffer specified by DescriptorLength and Descriptor
+ is not large enough to hold the result of the request.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
+ status is returned in Status.
+
+**/
+EFI_STATUS
+LoadAllDescriptor (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ EFI_USB_CONFIG_DESCRIPTOR Tmp;
+
+ Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->AllocatePool (EfiBootServicesData, Tmp.TotalLength, (VOID **)ConfigDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbGetDescriptor (
+ UsbIo,
+ USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
+ 0,
+ Tmp.TotalLength,
+ *ConfigDesc,
+ &TransStatus
+ );
+ return Status;
+}
+
+/**
+ Returns pointer to the next descriptor for the pack of USB descriptors
+ located in continues memory segment
+
+ @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
+ @param[in, out] Offset A pointer to the sum of descriptor length.
+
+ @retval TRUE The request executed successfully.
+ @retval FALSE No next descriptor.
+
+**/
+BOOLEAN
+NextDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
+ IN OUT UINTN *Offset
+ )
+{
+ if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
+ return FALSE;
+ }
+
+ if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
+ return FALSE;
+ }
+
+ *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
+ if ( *Offset >= Desc->TotalLength ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Read Function descriptor
+
+ @param[in] Config A pointer to all of configuration.
+ @param[in] FunDescriptorType USB CDC class descriptor SubType.
+ @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
+
+ @retval EFI_SUCCESS The device capability descriptor was retrieved
+ successfully.
+ @retval EFI_UNSUPPORTED No supported.
+ @retval EFI_NOT_FOUND The device capability descriptor was not found.
+
+**/
+EFI_STATUS
+GetFunctionalDescriptor (
+ IN EFI_USB_CONFIG_DESCRIPTOR *Config,
+ IN UINT8 FunDescriptorType,
+ OUT VOID *DataBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+
+ Status = EFI_NOT_FOUND;
+
+ for (Offset = 0; NextDescriptor (Config, &Offset);) {
+ Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
+ if (Interface->DescriptorType == CS_INTERFACE) {
+ if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
+ switch (FunDescriptorType) {
+ case HEADER_FUN_DESCRIPTOR:
+ CopyMem (
+ DataBuffer,
+ (USB_HEADER_FUN_DESCRIPTOR *)Interface,
+ sizeof (USB_HEADER_FUN_DESCRIPTOR)
+ );
+ return EFI_SUCCESS;
+ case UNION_FUN_DESCRIPTOR:
+ CopyMem (
+ DataBuffer,
+ (USB_UNION_FUN_DESCRIPTOR *)Interface,
+ ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
+ );
+ return EFI_SUCCESS;
+ case ETHERNET_FUN_DESCRIPTOR:
+ CopyMem (
+ DataBuffer,
+ (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
+ sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
+ );
+ return EFI_SUCCESS;
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+ @param[in, out] UsbEthDriver A pointer to the USB_ETHERNET_DRIVER instance.
+
+**/
+VOID
+GetEndpoint (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN OUT USB_ETHERNET_DRIVER *UsbEthDriver
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT32 Result;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Interface.NumEndpoints == 0) {
+ Status = UsbSetInterface (UsbIo, Interface.InterfaceNumber, 1, &Result);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ for (Index = 0; Index < Interface.NumEndpoints; Index++) {
+ Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
+ ASSERT_EFI_ERROR (Status);
+
+ switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
+ case USB_ENDPOINT_BULK:
+ if (Endpoint.EndpointAddress & BIT7) {
+ UsbEthDriver->BulkInEndpoint = Endpoint.EndpointAddress;
+ } else {
+ UsbEthDriver->BulkOutEndpoint = Endpoint.EndpointAddress;
+ }
+
+ break;
+ case USB_ENDPOINT_INTERRUPT:
+ UsbEthDriver->InterruptEndpoint = Endpoint.EndpointAddress;
+ break;
+ }
+ }
+}
+
+/**
+ This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
+
+ @param[in] Cdb A pointer to the command descriptor block.
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param[in, out] PacketLength A pointer to the PacketLength.
+
+ @retval EFI_SUCCESS The bulk transfer has been successfully executed.
+ @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
+ @retval EFI_TIMEOUT The control transfer fails due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmReceive (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN OUT VOID *Packet,
+ IN OUT UINTN *PacketLength
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT32 TransStatus;
+ UINT8 Index;
+ UINTN BulkDataLength;
+ UINTN TotalLength;
+ USB_NCM_TRANSFER_HEADER_16 *Nth;
+ USB_NCM_DATAGRAM_POINTER_16 *Ndp;
+ USB_NCM_DATA_GRAM *Datagram;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+ TotalLength = 0;
+
+ if (UsbEthDriver->TotalDatagram == UsbEthDriver->NowDatagram) {
+ Status = gBS->HandleProtocol (
+ UsbEthDriver->UsbCdcDataHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthDriver->BulkInEndpoint == 0) {
+ GetEndpoint (UsbIo, UsbEthDriver);
+ }
+
+ BulkDataLength = USB_NCM_MAX_NTB_SIZE;
+ SetMem (UsbEthDriver->BulkBuffer, BulkDataLength, 0);
+ UsbEthDriver->NowDatagram = 0;
+ UsbEthDriver->TotalDatagram = 0;
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkInEndpoint,
+ UsbEthDriver->BulkBuffer,
+ &BulkDataLength,
+ USB_ETHERNET_BULK_TIMEOUT,
+ &TransStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Nth = (USB_NCM_TRANSFER_HEADER_16 *)UsbEthDriver->BulkBuffer;
+ Ndp = (USB_NCM_DATAGRAM_POINTER_16 *)((UINT8 *)UsbEthDriver->BulkBuffer + Nth->NdpIndex);
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+ UsbEthDriver->TotalDatagram = (UINT8)((Ndp->Length - 8) / 4 - 1);
+
+ for (Index = 0; Index < UsbEthDriver->TotalDatagram; Index++) {
+ TotalLength += Datagram->DatagramLength;
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Datagram + sizeof (USB_NCM_DATA_GRAM));
+ }
+
+ if (TotalLength < USB_ETHERNET_FRAME_SIZE) {
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+
+ TotalLength = 0;
+ for (Index = 0; Index < UsbEthDriver->TotalDatagram; Index++) {
+ CopyMem ((UINT8 *)Packet + TotalLength, (UINT8 *)UsbEthDriver->BulkBuffer + Datagram->DatagramIndex, Datagram->DatagramLength);
+ TotalLength += Datagram->DatagramLength;
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Datagram + sizeof (USB_NCM_DATA_GRAM));
+ }
+
+ *PacketLength = TotalLength;
+ UsbEthDriver->NowDatagram = UsbEthDriver->TotalDatagram;
+ } else {
+ UsbEthDriver->NowDatagram++;
+
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+ CopyMem (Packet, (UINT8 *)UsbEthDriver->BulkBuffer + Datagram->DatagramIndex, Datagram->DatagramLength);
+ *PacketLength = Datagram->DatagramLength;
+ }
+
+ return Status;
+ } else {
+ UsbEthDriver->NowDatagram++;
+
+ Nth = (USB_NCM_TRANSFER_HEADER_16 *)UsbEthDriver->BulkBuffer;
+ Ndp = (USB_NCM_DATAGRAM_POINTER_16 *)((UINT8 *)UsbEthDriver->BulkBuffer + Nth->NdpIndex);
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Datagram + sizeof (USB_NCM_DATA_GRAM) * (UsbEthDriver->NowDatagram - 1));
+
+ CopyMem (Packet, (UINT8 *)UsbEthDriver->BulkBuffer + Datagram->DatagramIndex, Datagram->DatagramLength);
+ *PacketLength = Datagram->DatagramLength;
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
+
+ @param[in] Cdb A pointer to the command descriptor block.
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Packet A pointer to the buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param[in, out] PacketLength A pointer to the PacketLength.
+
+ @retval EFI_SUCCESS The bulk transfer has been successfully executed.
+ @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
+ @retval EFI_TIMEOUT The control transfer fails due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmTransmit (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN VOID *Packet,
+ IN OUT UINTN *PacketLength
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT32 TransStatus;
+ USB_NCM_TRANSFER_HEADER_16 *Nth;
+ USB_NCM_DATAGRAM_POINTER_16 *Ndp;
+ USB_NCM_DATA_GRAM *Datagram;
+ UINT8 *TotalPacket;
+ UINTN TotalLength;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = gBS->HandleProtocol (
+ UsbEthDriver->UsbCdcDataHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthDriver->BulkOutEndpoint == 0) {
+ GetEndpoint (UsbIo, UsbEthDriver);
+ }
+
+ TotalLength = (UINTN)(USB_NCM_NTH_LENGTH + USB_NCM_NDP_LENGTH + (*PacketLength));
+
+ Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&TotalPacket);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SetMem (TotalPacket, TotalLength, 0);
+
+ Nth = (USB_NCM_TRANSFER_HEADER_16 *)TotalPacket;
+ Nth->Signature = USB_NCM_NTH_SIGN_16;
+ Nth->HeaderLength = USB_NCM_NTH_LENGTH;
+ Nth->Sequence = UsbEthDriver->BulkOutSequence++;
+ Nth->BlockLength = (UINT16)TotalLength;
+ Nth->NdpIndex = Nth->HeaderLength;
+
+ Ndp = (USB_NCM_DATAGRAM_POINTER_16 *)((UINT8 *)TotalPacket + Nth->NdpIndex);
+ Ndp->Signature = USB_NCM_NDP_SIGN_16;
+ Ndp->Length = USB_NCM_NDP_LENGTH;
+ Ndp->NextNdpIndex = 0x00;
+
+ Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+ Datagram->DatagramIndex = Nth->HeaderLength + Ndp->Length;
+ Datagram->DatagramLength = (UINT16)*PacketLength;
+
+ CopyMem (TotalPacket + Datagram->DatagramIndex, Packet, *PacketLength);
+
+ *PacketLength = TotalLength;
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkOutEndpoint,
+ TotalPacket,
+ PacketLength,
+ USB_ETHERNET_BULK_TIMEOUT,
+ &TransStatus
+ );
+ FreePool (TotalPacket);
+ return Status;
+}
+
+/**
+ Async USB transfer callback routine.
+
+ @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
+ transfer completed successfully.
+ @param[in] DataLength The length of Data received or sent via the Asynchronous
+ Transfer, if transfer successfully completes.
+ @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
+ @param[in] Status Indicates the result of the asynchronous transfer.
+
+ @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
+ @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InterruptCallback (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Status
+ )
+{
+ if ((Data == NULL) || (Context == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == USB_CDC_NETWORK_CONNECTION) {
+ CopyMem (
+ (EFI_USB_DEVICE_REQUEST *)Context,
+ (EFI_USB_DEVICE_REQUEST *)Data,
+ sizeof (EFI_USB_DEVICE_REQUEST)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to manage a USB device with an interrupt transfer pipe.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
+ FALSE, the interrupt transfer is deleted from the device's interrupt
+ transfer queue.
+ @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
+ executed.This parameter is required when IsNewTransfer is TRUE. The
+ value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
+ The units are in milliseconds.
+ @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
+
+ @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
+ @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmInterrupt (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollingInterval,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ UINTN DataLength;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+ DataLength = 0;
+
+ if (IsNewTransfer == TRUE) {
+ DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
+ Status = UsbEthDriver->UsbIo->UsbAsyncInterruptTransfer (
+ UsbEthDriver->UsbIo,
+ UsbEthDriver->InterruptEndpoint,
+ IsNewTransfer,
+ PollingInterval,
+ DataLength,
+ (EFI_ASYNC_USB_TRANSFER_CALLBACK)InterruptCallback,
+ Request
+ );
+ } else {
+ Status = UsbEthDriver->UsbIo->UsbAsyncInterruptTransfer (
+ UsbEthDriver->UsbIo,
+ UsbEthDriver->InterruptEndpoint,
+ IsNewTransfer,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the USB Ethernet Mac Address.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
+
+ @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthMacAddress (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT EFI_MAC_ADDRESS *MacAddress
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
+ CHAR16 *Data;
+ CHAR16 *DataPtr;
+ CHAR16 TmpStr[1];
+ UINT8 Index;
+ UINT8 Hi;
+ UINT8 Low;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ Status = UsbEthDriver->UsbIo->UsbGetStringDescriptor (
+ UsbEthDriver->UsbIo,
+ 0x409, // English-US Language ID
+ UsbEthDescriptor.MacAddress,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ DataPtr = Data;
+ for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+ CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
+ DataPtr++;
+ Hi = (UINT8)StrHexToUintn (TmpStr);
+ CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
+ DataPtr++;
+ Low = (UINT8)StrHexToUintn (TmpStr);
+ MacAddress->Addr[Index] = (Hi << 4) | Low;
+ }
+
+ return Status;
+}
+
+/**
+ Get the USB NCM max NTB size.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] BulkSize A pointer to the Bulk transfer data size.
+
+ @retval EFI_SUCCESS Get the USB NCM max NTB size successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmBulkSize (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT UINTN *BulkSize
+ )
+{
+ *BulkSize = USB_NCM_MAX_NTB_SIZE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the USB Header functional Descriptor.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
+
+ @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbHeaderFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ if (UsbHeaderFunDescriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetFunctionalDescriptor (UsbEthDriver->Config, HEADER_FUN_DESCRIPTOR, UsbHeaderFunDescriptor);
+ return Status;
+}
+
+/**
+ Retrieves the USB Union functional Descriptor.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
+
+ @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbUnionFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ if (UsbUnionFunDescriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetFunctionalDescriptor (UsbEthDriver->Config, UNION_FUN_DESCRIPTOR, UsbUnionFunDescriptor);
+ return Status;
+}
+
+/**
+ Retrieves the USB Ethernet functional Descriptor.
+
+ This function get the Mac Address, Ethernet statistics, maximum segment size,
+ number of multicast filters, and number of pattern filters from Ethernet
+ functional Descriptor.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
+
+ @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
+ @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthFunDescriptor (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ if (UsbEthFunDescriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetFunctionalDescriptor (UsbEthDriver->Config, ETHERNET_FUN_DESCRIPTOR, UsbEthFunDescriptor);
+ return Status;
+}
+
+/**
+ This request sets the Ethernet device multicast filters as specified in the
+ sequential list of 48 bit Ethernet multicast addresses.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value Number of filters.
+ @param[in] McastAddr A pointer to the value of the multicast addresses.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthMcastFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN VOID *McastAddr
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+ Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
+ Request.Value = Value;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = Value * 6;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataOut,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ McastAddr,
+ Request.Length,
+ &TransStatus
+ );
+}
+
+/**
+ This request sets up the specified Ethernet power management pattern filter as
+ described in the data structure.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value Number of filters.
+ @param[in] Length Size of the power management pattern filter data.
+ @param[in] PatternFilter A pointer to the power management pattern filter structure.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ IN UINT16 Length,
+ IN VOID *PatternFilter
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+ Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
+ Request.Value = Value;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = Length;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataOut,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ PatternFilter,
+ Length,
+ &TransStatus
+ );
+}
+
+/**
+ This request retrieves the status of the specified Ethernet power management
+ pattern filter from the device.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value The filter number.
+ @param[out] PatternActive A pointer to the pattern active boolean.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthPowerFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value,
+ OUT BOOLEAN *PatternActive
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
+ Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
+ Request.Value = Value;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = USB_ETH_POWER_FILTER_LENGTH;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataIn,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ PatternActive,
+ USB_ETH_POWER_FILTER_LENGTH,
+ &TransStatus
+ );
+}
+
+BIT_MAP gTable[] = {
+ { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, USB_ETH_PACKET_TYPE_DIRECTED },
+ { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, USB_ETH_PACKET_TYPE_BROADCAST },
+ { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, USB_ETH_PACKET_TYPE_MULTICAST },
+ { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, USB_ETH_PACKET_TYPE_PROMISCUOUS },
+ { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, USB_ETH_PACKET_TYPE_ALL_MULTICAST },
+};
+
+/**
+ Convert value between PXE receive filter and USB ETH packet filter.
+
+ @param[in] Value PXE filter data.
+ @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
+
+**/
+VOID
+ConvertFilter (
+ IN UINT16 Value,
+ OUT UINT16 *CdcFilter
+ )
+{
+ UINT32 Index;
+ UINT32 Count;
+
+ Count = sizeof (gTable)/sizeof (gTable[0]);
+
+ for (Index = 0; (gTable[Index].Src != 0) && (Index < Count); Index++) {
+ if (gTable[Index].Src & Value) {
+ *CdcFilter |= gTable[Index].Dst;
+ }
+ }
+}
+
+/**
+ This request is used to configure device Ethernet packet filter settings.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] Value Packet Filter Bitmap.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthPacketFilter (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 Value
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+ UINT16 CommandFilter;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+ CommandFilter = 0;
+
+ ConvertFilter (Value, &CommandFilter);
+
+ Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+ Request.Request = SET_ETH_PACKET_FILTER_REQ;
+ Request.Value = CommandFilter;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = USB_ETH_PACKET_FILTER_LENGTH;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbNoData,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ NULL,
+ USB_ETH_PACKET_FILTER_LENGTH,
+ &TransStatus
+ );
+}
+
+/**
+ This request is used to retrieve a statistic based on the feature selector.
+
+ @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+ @param[in] FeatureSelector Value of the feature selector.
+ @param[out] Statistic A pointer to the 32 bit unsigned integer.
+
+ @retval EFI_SUCCESS The request executed successfully.
+ @retval EFI_TIMEOUT A timeout occurred executing the request.
+ @retval EFI_DEVICE_ERROR The request failed due to a device error.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthStatistic (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN UINT16 FeatureSelector,
+ OUT VOID *Statistic
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_REQUEST Request;
+ UINT32 TransStatus;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
+ USB_ETHERNET_DRIVER *UsbEthDriver;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthFunDescriptor.EthernetStatistics == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
+ Request.Request = GET_ETH_STATISTIC_REQ;
+ Request.Value = FeatureSelector;
+ Request.Index = UsbEthDriver->NumOfInterface;
+ Request.Length = USB_ETH_STATISTIC;
+
+ return UsbEthDriver->UsbIo->UsbControlTransfer (
+ UsbEthDriver->UsbIo,
+ &Request,
+ EfiUsbDataIn,
+ USB_ETHERNET_TRANSFER_TIMEOUT,
+ Statistic,
+ USB_ETH_STATISTIC,
+ &TransStatus
+ );
+}
--
2.35.1.windows.2
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-03-09 7:51 [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
2023-03-09 7:51 ` [PATCH v6 2/3] UsbNetworkPkg/UsbCdcEcm: Add USB Cdc ECM " RichardHo [何明忠]
2023-03-09 7:51 ` [PATCH v6 3/3] UsbNetworkPkg/UsbCdcNcm: Add USB Cdc NCM " RichardHo [何明忠]
@ 2023-03-27 14:59 ` Tinh Nguyen
2023-03-27 15:13 ` [edk2-devel] " Rebecca Cran
2023-03-28 11:40 ` Rebecca Cran
2023-04-07 1:57 ` Rebecca Cran
4 siblings, 1 reply; 11+ messages in thread
From: Tinh Nguyen @ 2023-03-27 14:59 UTC (permalink / raw)
To: Richard Ho (何明忠), devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Rebecca Cran, Tinh Nguyen,
Tony Lo (羅金松)
Are there any plans for these patches? Could someone please assist in
reviewing these?
On 3/9/2023 2:51 PM, Richard Ho (何明忠) wrote:
> This driver provides UEFI driver for USB RNDIS device
>
> Signed-off-by: Richard Ho <richardho@ami.com>
> Cc: Andrew Fish <afish@apple.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
> Reviewed-by: Tony Lo <tonylo@ami.com>
> ---
> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
> UsbNetworkPkg/ReadMe.md | 65 +
> UsbNetworkPkg/ReleaseNotes.md | 11 +
> 18 files changed, 7452 insertions(+)
> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> create mode 100644 UsbNetworkPkg/ReadMe.md
> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>
> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
> new file mode 100644
> index 000000000000..30e4e4c8aac7
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
> @@ -0,0 +1,46 @@
> +## @file
> +# This package defines Usb network specific interfaces and library classes
> +# as well as configuration for standard edk2 packages.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x00010005
> + PACKAGE_NAME = UsbNetworkPkg
> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
> + PACKAGE_VERSION = 0.1
> +
> +[Includes]
> + Include
> +
> +[Protocols]
> + ## Include/Protocol/EdkIIUsbEthernet.h
> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
> +
> +[Guids]
> + ## Usb Network package token space GUID
> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
> +
> +[PcdsFeatureFlag]
> +
> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
> +
> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
> +
> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
> +
> +[PcdsFixedAtBuild, PcdsPatchableInModule]
> + ## Support rate limiting
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
> +
> + ## The rate limiting Credit value is check in rate limiter event.
> + # It is to control the RateLimitingCreditCount max value.
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
> +
> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> new file mode 100644
> index 000000000000..a3316b1d4a89
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> @@ -0,0 +1,9 @@
> +## @file
> +# Global DSC definitions to be included into project DSC file.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Components.X64]
> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> new file mode 100644
> index 000000000000..544df8404c64
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> new file mode 100644
> index 000000000000..85a309bcf567
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> @@ -0,0 +1,23 @@
> +## @file
> +# Global switches enable/disable project features.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
> + DEFINE PEI=IA32
> + DEFINE DXE=X64
> +!else
> + DEFINE PEI=COMMON
> + DEFINE DXE=COMMON
> +!endif
> +
> +[Packages]
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[PcdsFeatureFlag]
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> new file mode 100644
> index 000000000000..10616d97edb4
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> new file mode 100644
> index 000000000000..8923102bc350
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> @@ -0,0 +1,49 @@
> +## @file
> +# This is Usb Network Common driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = NetworkCommon
> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = NetworkCommonEntry
> +
> +[Sources]
> + DriverBinding.c
> + DriverBinding.h
> + ComponentName.c
> + PxeFunction.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Pcd]
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> new file mode 100644
> index 000000000000..64205e427745
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# This is Usb Rndis driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = UsbRndis
> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = UsbRndisEntry
> +
> +[Sources]
> + UsbRndis.c
> + UsbRndis.h
> + UsbRndisFunction.c
> + ComponentName.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> new file mode 100644
> index 000000000000..f54946c7aa69
> --- /dev/null
> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> @@ -0,0 +1,878 @@
> +/** @file
> + Header file contains code for USB Ethernet Protocol
> + definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
> +
> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
> +
> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
> +
> +#define USB_CDC_CLASS 0x02
> +#define USB_CDC_ACM_SUBCLASS 0x02
> +#define USB_CDC_ECM_SUBCLASS 0x06
> +#define USB_CDC_NCM_SUBCLASS 0x0D
> +#define USB_CDC_DATA_CLASS 0x0A
> +#define USB_CDC_DATA_SUBCLASS 0x00
> +#define USB_NO_CLASS_PROTOCOL 0x00
> +#define USB_NCM_NTB_PROTOCOL 0x01
> +#define USB_VENDOR_PROTOCOL 0xFF
> +
> +// Type Values for the DescriptorType Field
> +#define CS_INTERFACE 0x24
> +#define CS_ENDPOINT 0x25
> +
> +// Descriptor SubType in Functional Descriptors
> +#define HEADER_FUN_DESCRIPTOR 0x00
> +#define UNION_FUN_DESCRIPTOR 0x06
> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
> +
> +#define MAX_LAN_INTERFACE 0x10
> +
> +// Table 20: Class-Specific Notification Codes
> +#define USB_CDC_NETWORK_CONNECTION 0x00
> +
> +// 6.3.1 NetworkConnection
> +#define NETWORK_CONNECTED 0x01
> +#define NETWORK_DISCONNECT 0x00
> +
> +// USB Header functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT16 BcdCdc;
> +} USB_HEADER_FUN_DESCRIPTOR;
> +
> +// USB Union Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MasterInterface;
> + UINT8 SlaveInterface;
> +} USB_UNION_FUN_DESCRIPTOR;
> +
> +// USB Ethernet Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MacAddress;
> + UINT32 EthernetStatistics;
> + UINT16 MaxSegmentSize;
> + UINT16 NumberMcFilters;
> + UINT8 NumberPowerFilters;
> +} USB_ETHERNET_FUN_DESCRIPTOR;
> +
> +typedef struct {
> + UINT32 UsBitRate;
> + UINT32 DsBitRate;
> +} USB_CONNECT_SPEED_CHANGE;
> +
> +// Request Type Codes for USB Ethernet
> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
> +
> +// Class-Specific Request Codes for Ethernet subclass
> +// USB ECM 1.2 specification, Section 6.2
> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
> +#define SET_ETH_PACKET_FILTER_REQ 0x43
> +#define GET_ETH_STATISTIC_REQ 0x44
> +
> +// USB ECM command request length
> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
> +
> +// USB Ethernet Packet Filter Bitmap
> +// USB ECM 1.2 specification, Section 6.2.4
> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
> +
> +// USB Ethernet Statistics Feature Selector Codes
> +// USB ECM 1.2 specification, Section 6.2.5
> +#define USB_ETH_XMIT_OK 0x01
> +#define USB_ETH_RCV_OK 0x02
> +#define USB_ETH_XMIT_ERROR 0x03
> +#define USB_ETH_RCV_ERROR 0x04
> +#define USB_ETH_RCV_NO_BUFFER 0x05
> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
> +#define USB_ETH_RCV_CRC_ERROR 0x12
> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
> +#define USB_ETH_XMIT_DEFERRED 0x17
> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
> +#define USB_ETH_RCV_OVERRUN 0x19
> +#define USB_ETH_XMIT_UNDERRUN 0x1A
> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
> +
> +// NIC Information
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + UINT16 InterrupOpFlag;
> + UINT64 MappedAddr;
> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
> + UINT8 McastCount;
> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
> + UINT8 TxBufferCount;
> + UINT16 State;
> + BOOLEAN CanTransmit;
> + UINT16 ReceiveStatus;
> + UINT8 RxFilter;
> + UINT32 RxFrame;
> + UINT32 TxFrame;
> + UINT16 NetworkConnect;
> + UINT8 CableDetect;
> + UINT16 MaxSegmentSize;
> + EFI_MAC_ADDRESS MacAddr;
> + PXE_CPB_START_31 PxeStart;
> + PXE_CPB_INITIALIZE PxeInit;
> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
> + EFI_USB_DEVICE_REQUEST Request;
> + EFI_EVENT RateLimiter;
> + UINT32 RateLimitingCredit;
> + UINT32 RateLimitingCreditCount;
> + UINT32 RateLimitingPollTimer;
> + BOOLEAN RateLimitingEnable;
> +} NIC_DATA;
> +
> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Request
> + );
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + );
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + );
> +
> +typedef struct {
> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
> +} EDKII_USB_ETHERNET_UNDI;
> +
> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
> +// descriptor and specific requests.
> +struct _EDKII_USB_ETHERNET_PROTOCOL {
> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
> + // for calling the UNDI child functions
> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
> +};
> +
> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> new file mode 100644
> index 000000000000..0416ce132302
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> @@ -0,0 +1,266 @@
> +/** @file
> + Header file for for USB network common driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _DRIVER_BINDING_H_
> +#define _DRIVER_BINDING_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/NetworkInterfaceIdentifier.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +#define NETWORK_COMMON_DRIVER_VERSION 1
> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
> +#define RX_BUFFER_COUNT 32
> +#define TX_BUFFER_COUNT 32
> +#define MEMORY_REQUIRE 0
> +
> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
> + UINT16 Protocol;
> +} EthernetHeader;
> +#pragma pack()
> +
> +typedef struct {
> + UINTN Signature;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
> + EFI_HANDLE DeviceHandle;
> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + NIC_DATA NicInfo;
> + VOID *ReceiveBuffer;
> +} NIC_DEVICE;
> +
> +typedef VOID (*API_FUNC)(
> + PXE_CDB *,
> + NIC_DATA *
> + );
> +
> +extern PXE_SW_UNDI *gPxe;
> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + );
> +
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + );
> +
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + );
> +
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + );
> +
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + );
> +
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + );
> +
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +#endif
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> new file mode 100644
> index 000000000000..775807042460
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> @@ -0,0 +1,586 @@
> +/** @file
> + Header file for for USB Rndis driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _USB_RNDIS_H_
> +#define _USB_RNDIS_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
> + EFI_HANDLE UsbCdcDataHandle;
> + EFI_HANDLE UsbRndisHandle;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
> + EFI_USB_CONFIG_DESCRIPTOR *Config;
> + UINT8 NumOfInterface;
> + UINT8 BulkInEndpoint;
> + UINT8 BulkOutEndpoint;
> + UINT8 InterrupEndpoint;
> + EFI_MAC_ADDRESS MacAddress;
> + UINT32 RequestId;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + LIST_ENTRY ReceivePacketList;
> +} USB_RNDIS_DEVICE;
> +
> +#define USB_RNDIS_DRIVER_VERSION 1
> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
> +
> +#define LAN_BULKIN_CMD_CONTROL 1
> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
> +#define RNDIS_RESERVED_BYTE_LENGTH 8
> +
> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
> +
> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
> +
> +struct BIT_MAP {
> + unsigned int Src;
> + unsigned int Dst;
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + );
> +
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + );
> +
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + );
> +
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN BOOLEAN *PatternActive
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *Statistic
> + );
> +
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + );
> +
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + );
> +
> +#define RNDIS_MAJOR_VERSION 0x00000001
> +#define RNDIS_MINOR_VERSION 0x00000000
> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
> +
> +#define RNDIS_PACKET_MSG 0x00000001
> +#define RNDIS_INITIALIZE_MSG 0x00000002
> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
> +#define RNDIS_HLT_MSG 0x00000003
> +#define RNDIS_QUERY_MSG 0x00000004
> +#define RNDIS_QUERY_CMPLT 0x80000004
> +#define RNDIS_SET_MSG 0x00000005
> +#define RNDIS_SET_CMPLT 0x80000005
> +#define RNDIS_RESET_MSG 0x00000006
> +#define RNDIS_RESET_CMPLT 0x80000006
> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
> +#define RNDIS_KEEPALIVE_MSG 0x00000008
> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
> +
> +#define RNDIS_STATUS_SUCCESS 0x00000000
> +#define RNDIS_STATUS_FAILURE 0xC0000001
> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
> +
> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
> +
> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
> +
> +//
> +// General Objects
> +//
> +// Taken from NTDDNDIS.H
> +#define OID_GEN_SUPPORTED_LIST 0x00010101
> +#define OID_GEN_HARDWARE_STATUS 0x00010102
> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
> +#define OID_GEN_MEDIA_IN_USE 0x00010104
> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
> +#define OID_GEN_LINK_SPEED 0x00010107
> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
> +#define OID_GEN_VENDOR_ID 0x0001010C
> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
> +#define OID_GEN_DRIVER_VERSION 0x00010110
> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
> +#define OID_GEN_MAC_OPTIONS 0x00010113
> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
> +
> +#define OID_GEN_XMIT_OK 0x00020101
> +#define OID_GEN_RCV_OK 0x00020102
> +#define OID_GEN_XMIT_ERROR 0x00020103
> +#define OID_GEN_RCV_ERROR 0x00020104
> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
> +
> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
> +
> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
> +//
> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
> +//
> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
> +#define NDIS_PACKET_TYPE_SMT 0x0040
> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
> +#define NDIS_PACKET_TYPE_GROUP 0x1000
> +
> +#pragma pack(1)
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> +} REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 MaxTransferSize;
> +} REMOTE_NDIS_INITIALIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_HALT_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_QUERY_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_SET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Reserved;
> +} REMOTE_NDIS_RESET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 StatusBufferLength;
> + UINT32 StatusBufferOffset;
> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
> +
> +typedef struct {
> + UINT32 DiagStatus;
> + UINT32 ErrorOffset;
> +} RNDIS_DIAGNOSTIC_INFO;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_KEEPALIVE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 DeviceFlags;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + UINT64 Reserved;
> +} REMOTE_NDIS_INITIALIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> +} REMOTE_NDIS_QUERY_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_SET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 AddressingReset;
> +} REMOTE_NDIS_RESET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 DataOffset;
> + UINT32 DataLength;
> + UINT32 OutOfBandDataOffset;
> + UINT32 OutOfBandDataLength;
> + UINT32 NumOutOfBandDataElements;
> + UINT32 PerPacketInfoOffset;
> + UINT32 PerPacketInfoLength;
> + UINT32 Reserved1;
> + UINT32 Reserved2;
> +} REMOTE_NDIS_PACKET_MSG;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} OUT_OF_BAND_DATA_RECORD;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} PER_PACKET_INFO_DATA_RECORD;
> +
> +typedef struct {
> + LIST_ENTRY PacketList;
> + UINT8 *OrgBuffer;
> + UINTN RemainingLength;
> + UINT8 *PacketStartBuffer; // Variable size data to follow
> +} PACKET_LIST;
> +
> +#pragma pack()
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> new file mode 100644
> index 000000000000..e83469e13079
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> @@ -0,0 +1,263 @@
> +/** @file
> + This file contains code for USB network common driver
> + component name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
> + {
> + "eng;en",
> + L"Network Common Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
> + NetworkCommonComponentNameGetDriverName,
> + NetworkCommonComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> + CHAR16 *HandleName;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
> +
> + if (!Language || !ControllerName) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (ChildHandle == NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Make sure this driver is currently managing ControllerHandle
> + //
> + Status = EfiTestManagedDevice (
> + Controller,
> + gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Make sure this driver produced ChildHandle
> + //
> + Status = EfiTestChildHandle (
> + Controller,
> + ChildHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
> +
> + if (!EFI_ERROR (Status)) {
> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *ControllerName = HandleName;
> +
> + if (gNetworkCommonControllerNameTable != NULL) {
> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
> + gNetworkCommonControllerNameTable = NULL;
> + }
> +
> + Status = AddUnicodeString2 (
> + "eng",
> + gNetworkCommonComponentName.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + TRUE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = AddUnicodeString2 (
> + "en",
> + gNetworkCommonComponentName2.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + FALSE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> new file mode 100644
> index 000000000000..23b791362091
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> @@ -0,0 +1,595 @@
> +/** @file
> + This file contains code for USB network binding driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +PXE_SW_UNDI *gPxe = NULL;
> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +UINT32 gRateLimitingCredit;
> +UINT32 gRateLimitingPollTimer;
> +BOOLEAN gRateLimitingEnable;
> +
> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
> + NetworkCommonSupported,
> + NetworkCommonDriverStart,
> + NetworkCommonDriverStop,
> + NETWORK_COMMON_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Create MAC Device Path
> +
> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
> + @retval EFI_SUCCESS MAC device path created successfully.
> +
> +**/
> +EFI_STATUS
> +CreateMacDevicePath (
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + MAC_ADDR_DEVICE_PATH MacAddrNode;
> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
> + UINT8 *DevicePath;
> + UINT16 TotalLength;
> + UINT16 BaseLength;
> +
> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
> +
> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
> + MacAddrNode.Header.Length[1] = 0;
> +
> + EndNode = BaseDev;
> +
> + while (!IsDevicePathEnd (EndNode)) {
> + EndNode = NextDevicePathNode (EndNode);
> + }
> +
> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
> + DevicePath += BaseLength;
> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
> + DevicePath += sizeof (MacAddrNode);
> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Network Common Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + EFI_MAC_ADDRESS MacAddress;
> + UINTN BulkDataSize;
> + NIC_DEVICE *NicDevice;
> + UINT8 *TmpPxePointer;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
> +
> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
> + ASSERT_EFI_ERROR (Status);
> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
> + if (!NicDevice) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + // for alignment adjustment
> + if (gPxe == NULL) {
> + TmpPxePointer = NULL;
> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
> + if (!TmpPxePointer) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + return EFI_OUT_OF_RESOURCES;
> + } else {
> + // check for paragraph alignment here
> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
> + } else {
> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
> + }
> +
> + if (!gPxe) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PxeStructInit (gPxe);
> + }
> + }
> +
> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
> +
> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
> +
> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
> +
> + NicDevice->NicInfo.UsbEth = UsbEth;
> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
> + NicDevice->NicInfo.CableDetect = 0;
> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
> +
> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
> +
> + NicDevice->NicInfo.TxBufferCount = 0;
> +
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
> + } else {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = CreateMacDevicePath (
> + &NicDevice->DevPath,
> + UsbEthPath,
> + &NicDevice->NicInfo
> + );
> +
> + if (EFI_ERROR (Status)) {
> + UpdateNicNum (NULL, gPxe);
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> + }
> +
> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
> + NicDevice->NiiProtocol.ImageSize = 0;
> + NicDevice->NiiProtocol.ImageAddr = 0;
> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
> +
> + NicDevice->NiiProtocol.StringId[0] = 'U';
> + NicDevice->NiiProtocol.StringId[1] = 'N';
> + NicDevice->NiiProtocol.StringId[2] = 'D';
> + NicDevice->NiiProtocol.StringId[3] = 'I';
> + NicDevice->DeviceHandle = NULL;
> +
> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
> + NicDevice->NicInfo.RateLimiter = NULL;
> +
> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &NicDevice->DeviceHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice->DevPath != NULL) {
> + FreePool (NicDevice->DevPath);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + NicDevice->DeviceHandle,
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AllChildrenStopped;
> + UINTN Index;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + NIC_DEVICE *NicDevice;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
> +
> + if (NumberOfChildren == 0) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + AllChildrenStopped = TRUE;
> +
> + for (Index = 0; Index < NumberOfChildren; Index++) {
> + Status = gBS->OpenProtocol (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + AllChildrenStopped = FALSE;
> + continue;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index]
> + );
> +
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index],
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> + } else {
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> + }
> + }
> +
> + if (!AllChildrenStopped) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Entrypoint of Network Common Driver.
> +
> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gNetworkCommonDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gNetworkCommonComponentName2,
> + NULL
> + );
> + return Status;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> new file mode 100644
> index 000000000000..687cabca4ce3
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> @@ -0,0 +1,1803 @@
> +/** @file
> + This file contains code for UNDI command based on UEFI specification.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +// API table, defined in UEFI specification
> +API_FUNC gUndiApiTable[] = {
> + UndiGetState,
> + UndiStart,
> + UndiStop,
> + UndiGetInitInfo,
> + UndiGetConfigInfo,
> + UndiInitialize,
> + UndiReset,
> + UndiShutdown,
> + UndiInterruptEnable,
> + UndiReceiveFilter,
> + UndiStationAddress,
> + UndiStatistics,
> + UndiMcastIp2Mac,
> + UndiNvData,
> + UndiGetStatus,
> + UndiFillHeader,
> + UndiTransmit,
> + UndiReceive
> +};
> +
> +/**
> + Callback function for enable Rate Limiter
> +
> + @param[in] Event Event whose notification function is being invoked
> + @param[in] Context Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +UndiRateLimiterCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + NIC_DATA *Nic = Context;
> +
> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
> + Nic->RateLimitingCreditCount++;
> + }
> +}
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_START_31 *Cpb;
> + EFI_STATUS Status;
> + BOOLEAN EventError;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
> +
> + Nic->PxeStart.Delay = Cpb->Delay;
> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
> + Nic->PxeStart.Block = Cpb->Block;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
> + EventError = FALSE;
> + Status = EFI_SUCCESS;
> + if (Nic->RateLimitingEnable == TRUE) {
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + UndiRateLimiterCallback,
> + Nic,
> + &Nic->RateLimiter
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = gBS->SetTimer (
> + Nic->RateLimiter,
> + TimerPeriodic,
> + Nic->RateLimitingPollTimer * 10000
> + );
> + if (EFI_ERROR (Status)) {
> + EventError = TRUE;
> + }
> + }
> + }
> +
> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + // Initial the state for UNDI start.
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + } else {
> + if (Nic->RateLimitingEnable == TRUE) {
> + if (!EventError) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + }
> +
> + if (Nic->RateLimiter) {
> + gBS->CloseEvent (&Nic->RateLimiter);
> + Nic->RateLimiter = 0;
> + }
> + }
> +
> + // Initial the state when UNDI start is fail
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
> + return;
> + }
> +
> + Nic->PxeStart.Delay = 0;
> + Nic->PxeStart.Virt2Phys = 0;
> + Nic->PxeStart.Block = 0;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = 0;
> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
> +
> + if (Nic->RateLimitingEnable == TRUE) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + gBS->CloseEvent (&Nic->RateLimiter);
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_INIT_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->MemoryRequired = MEMORY_REQUIRE;
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + Db->LinkSpeeds[0] = 10;
> + Db->LinkSpeeds[1] = 100;
> + Db->LinkSpeeds[2] = 1000;
> + Db->LinkSpeeds[3] = 0;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> + Db->IFtype = PXE_IFTYPE_ETHERNET;
> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
> +
> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_CONFIG_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->pci.BusType = PXE_BUSTYPE_USB;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_INITIALIZE *Cpb;
> + PXE_DB_INITIALIZE *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
> +
> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
> +
> + Cdb->StatCode = Initialize (Cdb, Nic);
> +
> + Db->MemoryUsed = MEMORY_REQUIRE;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> +
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + Nic->CanTransmit = FALSE;
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
> + }
> + }
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Initialize Network interface controller data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval Status A value of Pxe statcode.
> +
> +**/
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + UINTN Status;
> + UINT32 Index;
> + EFI_STATUS EfiStatus;
> +
> + Status = MapIt (
> + Nic,
> + Nic->PxeInit.MemoryAddr,
> + Nic->PxeInit.MemoryLength,
> + TO_AND_FROM_DEVICE,
> + (UINT64)(UINTN)&Nic->MappedAddr
> + );
> +
> + if (Status != 0) {
> + return (UINT16)Status;
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->BroadcastNodeAddress[Index] = 0xFF;
> + }
> +
> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = 0;
> + Nic->PermNodeAddress[Index] = 0;
> + Nic->BroadcastNodeAddress[Index] = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
> + if (EFI_ERROR (EfiStatus)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return (UINT16)Status;
> +}
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
> + Nic->InterrupOpFlag = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Nic->CanTransmit = FALSE;
> +
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + UINT16 NewFilter;
> + PXE_DB_RECEIVE_FILTERS *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> +
> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
> + if ((Cdb->DBsize != 0)) {
> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
> + }
> + }
> +
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
> + if (NewFilter == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Cdb->CPBsize != 0) {
> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if ((Cdb->CPBsize == 0)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + break;
> +
> + default:
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Set PXE receive filter.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] SetFilter PXE receive filter
> + @param[in] CpbAddr Command Parameter Block Address
> + @param[in] CpbSize Command Parameter Block Size
> +
> +**/
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_STATION_ADDRESS *Cpb;
> + PXE_DB_STATION_ADDRESS *Db;
> + UINT16 Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> + }
> +
> + if (Cdb->CPBaddr != 0) {
> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
> + }
> + }
> +
> + if (Cdb->DBaddr != 0) {
> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Return data for DB data.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> +**/
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + )
> +{
> + PXE_DB_STATISTICS *DbStatistic;
> + EFI_STATUS Status;
> +
> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
> +
> + if (DbSize == 0) {
> + return PXE_STATCODE_SUCCESS;
> + }
> +
> + DbStatistic->Supported = 0x802;
> + DbStatistic->Data[0x01] = Nic->RxFrame;
> + DbStatistic->Data[0x0B] = Nic->TxFrame;
> +
> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in, out] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
> + PXE_DB_MCAST_IP_TO_MAC *Db;
> + UINT8 *Tmp;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + return;
> + }
> +
> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
> +
> + if ((Tmp[0] & 0xF0) != 0xE0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
> + }
> +
> + Db->MAC[0] = 0x01;
> + Db->MAC[1] = 0x00;
> + Db->MAC[2] = 0x5E;
> + Db->MAC[3] = Tmp[1] & 0x7F;
> + Db->MAC[4] = Tmp[2];
> + Db->MAC[5] = Tmp[3];
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_STATUS *Db;
> + PXE_DB_GET_STATUS TmpGetStatus;
> + UINT16 NumEntries;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + TmpGetStatus.RxFrameLen = 0;
> + TmpGetStatus.reserved = 0;
> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
> + } else {
> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
> + if (Cdb->DBsize == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + NumEntries = Cdb->DBsize - sizeof (UINT64);
> + Cdb->DBsize = sizeof (UINT32) * 2;
> +
> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
> + if (Nic->TxBufferCount > 0) {
> + Nic->TxBufferCount--;
> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
> + }
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
> + if (Nic->ReceiveStatus != 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
> + }
> + }
> +
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_FILL_HEADER *CpbFillHeader;
> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
> + EthernetHeader *MacHeader;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
> +
> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
> + MacHeader->Protocol = CpbFill->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
> + }
> + } else {
> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
> + MacHeader->Protocol = CpbFillHeader->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk out command to transmit data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in] OpFlags Operation Flags.
> +
> +**/
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + )
> +{
> + EFI_STATUS Status;
> + PXE_CPB_TRANSMIT *Cpb;
> + UINT64 BulkOutData;
> + UINTN DataLength;
> + UINTN TransmitLength;
> + UINTN Map;
> + UINT32 Counter;
> + UINT16 StatCode;
> +
> + BulkOutData = 0;
> + Counter = 0;
> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
> +
> + if (Nic->CanTransmit) {
> + return PXE_STATCODE_BUSY;
> + }
> +
> + Nic->CanTransmit = TRUE;
> +
> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + Map = MapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + (UINT64)(UINTN)&BulkOutData
> + );
> +
> + if (Map != 0) {
> + Nic->CanTransmit = FALSE;
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
> + Nic->TxBufferCount++;
> + }
> +
> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
> +
> + while (1) {
> + if (Counter >= 3) {
> + StatCode = PXE_STATCODE_BUSY;
> + break;
> + }
> +
> + TransmitLength = DataLength;
> +
> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
> + if (EFI_ERROR (Status)) {
> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
> + break;
> + }
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + break;
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + Nic->TxFrame++;
> + StatCode = PXE_STATCODE_SUCCESS;
> + break;
> + }
> +
> + Counter++;
> + }
> +
> + UnMapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + BulkOutData
> + );
> +
> + Nic->CanTransmit = FALSE;
> +
> + return StatCode;
> +}
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk in command to receive data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in, out] DbAddr Data Block Address.
> +
> +**/
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + PXE_FRAME_TYPE FrameType;
> + PXE_CPB_RECEIVE *Cpb;
> + PXE_DB_RECEIVE *Db;
> + NIC_DEVICE *NicDevice;
> + UINT8 *BulkInData;
> + UINTN DataLength;
> + EthernetHeader *Header;
> + EFI_TPL OriginalTpl;
> +
> + FrameType = PXE_FRAME_TYPE_NONE;
> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
> + BulkInData = NicDevice->ReceiveBuffer;
> + DataLength = (UINTN)Nic->MaxSegmentSize;
> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
> +
> + if (!BulkInData) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
> + if (EFI_ERROR (Status)) {
> + Nic->ReceiveStatus = 0;
> + if (Nic->RateLimitingEnable == TRUE) {
> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + if (Nic->RateLimitingCreditCount != 0) {
> + Nic->RateLimitingCreditCount--;
> + }
> +
> + gBS->RestoreTPL (OriginalTpl);
> + }
> +
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Nic->RxFrame++;
> +
> + if (DataLength != 0) {
> + if (DataLength > Cpb->BufferLen) {
> + DataLength = (UINTN)Cpb->BufferLen;
> + }
> +
> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
> +
> + Header = (EthernetHeader *)BulkInData;
> +
> + Db->FrameLen = (UINT32)DataLength;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_UNICAST;
> + } else {
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_BROADCAST;
> + } else {
> + if ((Header->DestAddr[0] & 1) == 1) {
> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
> + } else {
> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
> + }
> + }
> + }
> +
> + Db->Type = FrameType;
> + Db->Protocol = Header->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
> + Db->DestAddr[Index] = Header->DestAddr[Index];
> + }
> + }
> +
> + if (FrameType == PXE_FRAME_TYPE_NONE) {
> + Nic->ReceiveStatus = 0;
> + } else {
> + Nic->ReceiveStatus = 1;
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Fill out PXE SW UNDI structure.
> +
> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
> + PxeSw->Fudge = 0;
> + PxeSw->IFcnt = 0;
> + PxeSw->IFcntExt = 0;
> + PxeSw->Rev = PXE_ROMID_REV;
> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
> + PxeSw->reserved1 = 0;
> +
> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
> + PXE_ROMID_IMP_FRAG_SUPPORTED |
> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
> +
> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
> + PxeSw->reserved2[0] = 0;
> + PxeSw->reserved2[1] = 0;
> + PxeSw->reserved2[2] = 0;
> + PxeSw->BusCnt = 1;
> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
> +}
> +
> +/**
> + Update NIC number.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + UINT16 NicNum;
> +
> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
> +
> + if (Nic == NULL) {
> + if (NicNum > 0) {
> + NicNum--;
> + }
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> + return;
> + }
> +
> + NicNum++;
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> +}
> +
> +/**
> + UNDI API table entry.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + )
> +{
> + PXE_CDB *CdbPtr;
> + NIC_DATA *Nic;
> +
> + if (Cdb == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Map virtual memory address for DMA. This field can be set to
> + zero if there is no mapping service.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[out] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + )
> +{
> + UINT64 *PhyAddr;
> +
> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
> +
> + if (Nic->PxeStart.Map_Mem == 0) {
> + *PhyAddr = MemAddr;
> + } else {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Un-map previously mapped virtual memory address. This field can be set
> + to zero only if the Map_Mem() service is also set to zero.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[in] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + )
> +{
> + if (Nic->PxeStart.UnMap_Mem != 0) {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
> new file mode 100644
> index 000000000000..b9ba170c135b
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
> @@ -0,0 +1,172 @@
> +/** @file
> + This file contains code for USB RNDIS Driver Component
> + Name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
> + {
> + "eng;en",
> + L"USB RNDIS Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
> + UsbRndisComponentNameGetDriverName,
> + UsbRndisComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gUsbRndisDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gUsbRndisComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> new file mode 100644
> index 000000000000..92830771e408
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> @@ -0,0 +1,886 @@
> +/** @file
> + This file contains code for USB Remote Network Driver
> + Interface Spec. Driver Binding
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
> + UsbRndisDriverSupported,
> + UsbRndisDriverStart,
> + UsbRndisDriverStop,
> + USB_RNDIS_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Check if this interface is USB Rndis SubType
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +
> +**/
> +BOOLEAN
> +IsSupportedDevice (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if this interface is USB Rndis SubType but not CDC Data interface
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +**/
> +BOOLEAN
> +IsRndisInterface (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
> +
> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> +
> + @retval EFI_SUCCESS Is the same device.
> + @retval EFI_UNSUPPORTED Is not the same device.
> +
> +**/
> +EFI_STATUS
> +IsSameDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
> + )
> +{
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
> + while (1) {
> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
> + {
> + return EFI_SUCCESS;
> + } else {
> + return EFI_UNSUPPORTED;
> + }
> + } else {
> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
> + }
> + }
> +
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
> +}
> +
> +/**
> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB CDC Data(UsbIo) installed.
> + @retval FALSE USB CDC Data(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbCdcData (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for CDC-DATA
> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB Rndis(UsbIo) installed
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis(UsbIo) installed.
> + @retval FALSE USB Rndis(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbRndis (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for Rndis
> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
> + For one device two USBIO will be installed each for CDC and RNDIS interface.
> +
> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +UpdateRndisDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + BOOLEAN IsRndisInterfaceFlag;
> +
> + IsRndisInterfaceFlag = FALSE;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEdkIIUsbEthProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthDevice
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
> + if (IsRndisInterfaceFlag == FALSE) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> +
> + if (!EFI_ERROR (Status)) {
> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> + FreePool (HandleBuffer);
> + return EFI_SUCCESS;
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> +
> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
> + and UsbIO protocol.
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
> +
> +**/
> +VOID
> +FindMatchingCdcData (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + UsbRndisDevice->UsbRndisHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
> + FreePool (HandleBuffer);
> + return;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> + if (!EFI_ERROR (Status)) {
> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + FreePool (HandleBuffer);
> + return;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +}
> +
> +/**
> +
> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
> +
> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FindMatchingRndisDev (
> + IN EFI_HANDLE CdcHandle,
> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
> + OUT EFI_HANDLE *RndisHandle
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + CdcHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
> + break;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + if (!EFI_ERROR (Status)) {
> + *RndisHandle = HandleBuffer[Index];
> + *CdcUsbIo = UsbIo;
> + FreePool (HandleBuffer);
> + return Status;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + USB Rndis Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + USB RNDIS Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_HANDLE RndisHandle;
> +
> + RndisHandle = ControllerHandle;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = UpdateRndisDevice (
> + UsbEthPath,
> + &UsbRndisDevice
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + return Status;
> + } else {
> + // Check if RnDis exist
> + Status = FindMatchingRndisDev (
> + ControllerHandle,
> + &UsbIo,
> + &RndisHandle
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> + }
> + }
> +
> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
> +
> + if (!UsbRndisDevice) {
> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Status = LoadAllDescriptor (
> + UsbIo,
> + &UsbRndisDevice->Config
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (
> + UsbIo,
> + &Interface
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
> + UsbRndisDevice->UsbCdcDataHandle = 0;
> + UsbRndisDevice->UsbIo = UsbIo;
> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
> +
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
> +
> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
> + UsbRndisDevice->PacketAlignmentFactor = 0;
> +
> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
> +
> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
> + FindMatchingCdcData (UsbRndisDevice);
> +
> + if (UsbRndisDevice->UsbIoCdcData) {
> + Status = gBS->InstallProtocolInterface (
> + &ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &(UsbRndisDevice->UsbEth)
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
> + return EFI_SUCCESS;
> + }
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + CheckandStopRndisDevice
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> +
> + @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
> +CheckandStopRndisDevice (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
> + return Status;
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + USB Rndis Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = CheckandStopRndisDevice (This, ControllerHandle);
> + return Status;
> + }
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
> +
> + Status = gBS->CloseProtocol (
> + UsbRndisDevice->UsbCdcDataHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + UsbRndisDevice->UsbCdcDataHandle
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
> + }
> +
> + Status = gBS->UninstallProtocolInterface (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + UsbEthProtocol
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Entrypoint of RNDIS Driver.
> +
> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
> +
> + return gBS->InstallMultipleProtocolInterfaces (
> + &gUsbRndisDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gUsbRndisDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gUsbRndisComponentName2,
> + NULL
> + );
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> new file mode 100644
> index 000000000000..e3fe737cdef1
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> @@ -0,0 +1,1718 @@
> +/** @file
> + This file contains code for USB Ethernet descriptor
> + and specific requests implement.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +UINT16 gStopBulkInCnt = 0;
> +UINT16 gBlockBulkInCnt = 0;
> +
> +/**
> + Load All of device descriptor.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[out] ConfigDesc A pointer to the configuration descriptor.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
> + buffer specified by DescriptorLength and Descriptor
> + is not large enough to hold the result of the request.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
> + status is returned in Status.
> +**/
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 TransStatus;
> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
> +
> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = gBS->AllocatePool (
> + EfiBootServicesData,
> + Tmp.TotalLength,
> + (VOID **)ConfigDesc
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbGetDescriptor (
> + UsbIo,
> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
> + 0,
> + Tmp.TotalLength,
> + *ConfigDesc,
> + &TransStatus
> + );
> + return Status;
> +}
> +
> +/**
> + Returns pointer to the next descriptor for the pack of USB descriptors
> + located in continues memory segment
> +
> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
> + @param[in, out] Offset A pointer to the sum of descriptor length.
> +
> + @retval TRUE The request executed successfully.
> + @retval FALSE No next descriptor.
> +
> +**/
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + )
> +{
> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
> + return FALSE;
> + }
> +
> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
> + return FALSE;
> + }
> +
> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
> + if ( *Offset >= Desc->TotalLength ) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Read Function descriptor
> +
> + @param[in] Config A pointer to all of configuration.
> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
> +
> + @retval EFI_SUCCESS The device capability descriptor was retrieved
> + successfully.
> + @retval EFI_UNSUPPORTED No supported.
> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Offset;
> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
> +
> + Status = EFI_NOT_FOUND;
> +
> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
> + if (Interface->DescriptorType == CS_INTERFACE) {
> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
> + switch (FunDescriptorType) {
> + case HEADER_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + case UNION_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
> + );
> + return EFI_SUCCESS;
> + case ETHERNET_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + default:
> + Status = EFI_UNSUPPORTED;
> + break;
> + }
> + }
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> +
> +**/
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Index;
> + UINT32 Result;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + if (Interface.NumEndpoints == 0 ) {
> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> + }
> +
> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
> + case USB_ENDPOINT_BULK:
> + if (Endpoint.EndpointAddress & BIT7) {
> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
> + } else {
> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
> + }
> +
> + break;
> + case USB_ENDPOINT_INTERRUPT:
> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
> + break;
> + }
> + }
> +}
> +
> +/**
> + Async USB transfer callback routine.
> +
> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
> + transfer completed successfully.
> + @param[in] DataLength The length of Data received or sent via the Asynchronous
> + Transfer, if transfer successfully completes.
> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
> + @param[in] Status Indicates the result of the asynchronous transfer.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + )
> +{
> + if ((Data == NULL) || (Context == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
> + CopyMem (
> + (EFI_USB_DEVICE_REQUEST *)Context,
> + (EFI_USB_DEVICE_REQUEST *)Data,
> + sizeof (EFI_USB_DEVICE_REQUEST)
> + );
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + UINTN DataLength;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + DataLength = 0;
> +
> + if (IsNewTransfer == TRUE) {
> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + PollingInterval,
> + DataLength,
> + InterruptCallback,
> + Requst
> + );
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + // Because of Stacked AsyncInterrupt request are not supported
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + 0,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> + } else {
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function is used to read USB interrupt transfer before the response RNDIS message.
> +
> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
> +
> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadRndisResponseInterrupt (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Data[2];
> + UINT32 UsbStatus;
> + UINTN DataLength;
> +
> + DataLength = 8;
> +
> + ZeroMem (Data, sizeof (Data));
> +
> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + &Data,
> + &DataLength,
> + 0x20,
> + &UsbStatus
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
> + CHAR16 *Data;
> + CHAR16 *DataPtr;
> + CHAR16 TmpStr[1];
> + UINT8 Index;
> + UINT8 Hi;
> + UINT8 Low;
> +
> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
> + }
> +
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
> + // To check USB Ethernet functional Descriptor
> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
> + UsbRndisDevice->UsbIo,
> + 0x409, // English-US Language ID
> + UsbEthDescriptor.MacAddress,
> + &Data
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + DataPtr = Data;
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Hi = (UINT8)StrHexToUintn (TmpStr);
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Low = (UINT8)StrHexToUintn (TmpStr);
> + MacAddress->Addr[Index] = (Hi << 4) | Low;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
> + @retval other Failed to retrieve the bulk transfer data size.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + )
> +{
> + EFI_STATUS Status;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbHeaderFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + HEADER_FUN_DESCRIPTOR,
> + UsbHeaderFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbUnionFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + UNION_FUN_DESCRIPTOR,
> + UsbUnionFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + This function get the Mac Address, Ethernet statistics, maximum segment size,
> + number of multicast filters, and number of pattern filters from Ethernet
> + functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbEthFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + ETHERNET_FUN_DESCRIPTOR,
> + UsbEthFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Value * 6;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + McastAddr,
> + Request.Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Length;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternFilter,
> + Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternActive,
> + USB_ETH_POWER_FILTER_LENGTH,
> + &TransStatus
> + );
> +}
> +
> +/**
> +
> + Converts PXE filter settings to RNDIS values
> +
> + @param[in] Value PXE filter data.
> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
> +
> +**/
> +VOID
> +ConvertFilter (
> + IN UINT16 Value,
> + OUT UINT16 *CdcFilter
> + )
> +{
> + UINT32 Index;
> + UINT32 Count;
> + static struct BIT_MAP Table[] = {
> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
> + };
> +
> + Count = sizeof (Table)/sizeof (Table[0]);
> +
> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
> + if (Table[Index].Src & Value) {
> + *CdcFilter |= Table[Index].Dst;
> + }
> + }
> +}
> +
> +/**
> +
> + Updates Filter settings on the device.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + UINT64 CpbAddr;
> + UINT32 CpbSize;
> + UINT16 SetFilter;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + CpbAddr = Cdb->CPBaddr;
> + CpbSize = Cdb->CPBsize;
> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + } else {
> + Nic->McastCount = 0;
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiStart is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
> +
> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
> + Status = RndisUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiReset (Cdb, Nic);
> + }
> +
> + Status = RndisUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiInitialize (Cdb, Nic);
> + }
> +
> + RndisUndiShutdown (Cdb, Nic);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when Undistop is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiGetInitInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + PXE_DB_GET_INIT_INFO *Db;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
> +
> + UsbEthDevice = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when RndisUndiGetConfigInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiInitialize is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
> +
> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> +
> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
> +
> + UsbRndisDevice->RequestId++;
> +
> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
> + return Status;
> + }
> +
> + // Only Wired Medium is supported
> + if (RndisInitMsgCmplt.Medium) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
> +
> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
> +
> + return Status;
> +}
> +
> +/**
> + This function is called when UndiReset is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
> +
> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
> +
> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
> +
> + UsbRndisDevice->RequestId = 1; // Let's start with 1
> +
> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiShutdown is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
> +
> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + Status = EFI_SUCCESS;
> + }
> +
> + UsbRndisDevice->RequestId = 1;
> + return Status;
> +}
> +
> +/**
> + Update the Media connection.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transmit the data after appending RNDIS header.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
> + if (RndisPacketMsg == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
> +
> + CopyMem (
> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
> + BulkOutData,
> + *DataLength
> + );
> +
> + TransferLength = RndisPacketMsg->MessageLength;
> +
> + Status = RndisTransmitDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
> +
> + FreePool (RndisPacketMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Receives and removes RNDIS header and returns the raw data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
> + @retval EFI_NOT_FOUND No buffer was found in the list.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> + VOID *Buffer;
> + PACKET_LIST *HeadPacket;
> + PACKET_LIST *PacketList;
> +
> + // Check if there is any outstanding packet to receive
> + // The buffer allocated has a linked List followed by the packet.
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + Buffer = NULL;
> + HeadPacket = NULL;
> +
> + while (1) {
> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
> + if (Buffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
> + PacketList = (PACKET_LIST *)Buffer;
> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
> + // Save the original address for freeing it up
> + PacketList->OrgBuffer = (UINT8 *)Buffer;
> + TransferLength = UsbRndisDevice->MaxTransferSize;
> +
> + Status = RndisReceiveDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
> + FreePool (Buffer);
> + break;
> + }
> +
> + // Collect all the RNDIS packet in Linked list.
> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
> + (TransferLength >= RndisPacketMsg->MessageLength))
> + {
> + // Insert Packet
> + PacketList->RemainingLength = TransferLength;
> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
> + } else {
> + FreePool (Buffer);
> + }
> + }
> +
> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
> +
> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
> +
> + // Check whether the packet is valid RNDIS packet.
> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
> + {
> + if (*DataLength >= RndisPacketMsg->DataLength) {
> + CopyMem (
> + BulkInData,
> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
> + RndisPacketMsg->DataLength
> + );
> +
> + *DataLength = RndisPacketMsg->DataLength;
> +
> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
> +
> + return EFI_SUCCESS;
> + } else {
> + *DataLength = RndisPacketMsg->DataLength;
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + }
> +
> + RemoveEntryList (&HeadPacket->PacketList);
> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
> + point to this function.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's control endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> +
> +**/
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + )
> +{
> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
> + EFI_USB_DEVICE_REQUEST DevReq;
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> + UINT32 SaveResponseType;
> + UINT32 SaveResponseLength;
> + UINT32 Index;
> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
> +
> + SaveResponseType = 0;
> + SaveResponseLength = 0;
> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
> +
> + if (RndisMsgResponse) {
> + SaveResponseType = RndisMsgResponse->MessageType;
> + SaveResponseLength = RndisMsgResponse->MessageLength;
> + }
> +
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsg,
> + RndisMsg->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
> +
> + // Error or no response expected
> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
> + return Status;
> + }
> +
> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
> + ReadRndisResponseInterrupt (UsbRndisDevice);
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsgResponse,
> + RndisMsgResponse->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
> +
> + PrintRndisMsg (RndisMsgResponse);
> +
> + if (!EFI_ERROR (Status)) {
> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
> +
> + RndisMsgResponse->MessageType = SaveResponseType;
> + RndisMsgResponse->MessageLength = SaveResponseLength;
> + continue;
> + }
> + }
> +
> + return Status;
> + }
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
> +
> + return EFI_TIMEOUT;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkOutEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_TX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (Status == EFI_SUCCESS) {
> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + UsbStatus = 0;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + // Use gStopBulkInCnt to stop BulkIn command
> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkInEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_RX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + } else {
> + gStopBulkInCnt--;
> + }
> + } else {
> + Status = EFI_TIMEOUT;
> + *TransferLength = 0;
> + gBlockBulkInCnt++;
> + }
> +
> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + gBlockBulkInCnt = 0;
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Prints RNDIS Header and Data
> +
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> +
> +**/
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + )
> +{
> + UINTN Length;
> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
> +
> + Length = 0;
> +
> + switch (RndisMsg->MessageType) {
> + case RNDIS_PACKET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
> + break;
> + case RNDIS_INITIALIZE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + break;
> + case RNDIS_INITIALIZE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> + break;
> + case RNDIS_HLT_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
> + break;
> + case RNDIS_QUERY_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
> + break;
> + case RNDIS_QUERY_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
> + break;
> + case RNDIS_SET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_MSG);
> + break;
> + case RNDIS_SET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
> + break;
> + case RNDIS_RESET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
> + break;
> + case RNDIS_RESET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
> + break;
> + case RNDIS_INDICATE_STATUS_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
> + break;
> + case RNDIS_KEEPALIVE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
> + break;
> + case RNDIS_KEEPALIVE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
> + }
> +
> + if (Length) {
> + UINTN Index = 0;
> + for ( ; Length; Length -= 4, Index++) {
> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
> + if (((Index % 4) == 3) && (Index != 0)) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> +
> + if ((Length < 8) && (Length > 4)) {
> + UINT32 Data32;
> + Index++;
> + Data32 = *((UINT32 *)RndisMsg + Index);
> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
> + break;
> + }
> + }
> +
> + if (Index % 4) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> + }
> +}
> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..cb70684f0bf1
> --- /dev/null
> +++ b/UsbNetworkPkg/ReadMe.md
> @@ -0,0 +1,65 @@
> +# UsbNetworkPkg
> +
> +This document is intend to provide package information, include the interface details.
> +
> +# INDEX
> + * [Introduction](#introduction)
> + * [Components](#components)
> + * [[NetworkCommon]](#networkcommon)
> + * [[UsbCdcEcm]](#usbcdcecm)
> + * [[UsbCdcNcm]](#usbcdcncm)
> + * [[UsbRndis]](#usbrndis)
> +
> +# Introduction
> +UsbNetworkPkg provides network functions for USB LAN devices.
> +
> +# Components
> +Below module is included in this package:<br>
> +- NetworkCommon
> +- UsbCdcEcm
> +- UsbCdcNcm
> +- UsbRndis
> +
> +## [NetworkCommon]
> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
> +
> +## Required Components
> +- NetworkPkg
> +
> +## [UsbCdcEcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x06|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbCdcNcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x0D|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbRndis]
> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x02|0xFF|
> +|0xEF|0x04|0x01|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
> new file mode 100644
> index 000000000000..f8ccccdb0830
> --- /dev/null
> +++ b/UsbNetworkPkg/ReleaseNotes.md
> @@ -0,0 +1,11 @@
> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
> +
> +# Release History<!-- omit in toc -->
> +- [1.00](#100)
> +
> +## 1.00
> +
> +**Release Date:** Mar 10, 2022
> +
> +**New Features**
> +- UsbNetworkPkg first release.
> --
> 2.35.1.windows.2
> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [edk2-devel] [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-03-27 14:59 ` [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS " Tinh Nguyen
@ 2023-03-27 15:13 ` Rebecca Cran
0 siblings, 0 replies; 11+ messages in thread
From: Rebecca Cran @ 2023-03-27 15:13 UTC (permalink / raw)
To: devel, tinhnguyen, Richard Ho (何明忠)
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Tony Lo (羅金松)
I'll review them later today.
--
Rebecca Cran
On 3/27/23 8:59 AM, Tinh Nguyen via groups.io wrote:
> Are there any plans for these patches? Could someone please assist in
> reviewing these?
>
> On 3/9/2023 2:51 PM, Richard Ho (何明忠) wrote:
>> This driver provides UEFI driver for USB RNDIS device
>>
>> Signed-off-by: Richard Ho <richardho@ami.com>
>> Cc: Andrew Fish <afish@apple.com>
>> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
>> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
>> Cc: Liming Gao <gaoliming@byosoft.com.cn>
>> Cc: Rebecca Cran <rebecca@bsdio.com>
>> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
>> Reviewed-by: Tony Lo <tonylo@ami.com>
>> ---
>> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
>> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
>> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
>> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
>> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
>> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
>> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
>> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
>> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
>> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
>> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
>> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
>> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
>> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
>> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
>> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
>> UsbNetworkPkg/ReadMe.md | 65 +
>> UsbNetworkPkg/ReleaseNotes.md | 11 +
>> 18 files changed, 7452 insertions(+)
>> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> create mode 100644
>> UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> create mode 100644
>> UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> create mode 100644
>> UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
>> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
>> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> create mode 100644 UsbNetworkPkg/ReadMe.md
>> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>>
>> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec
>> b/UsbNetworkPkg/UsbNetworkPkg.dec
>> new file mode 100644
>> index 000000000000..30e4e4c8aac7
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
>> @@ -0,0 +1,46 @@
>> +## @file
>> +# This package defines Usb network specific interfaces and library
>> classes
>> +# as well as configuration for standard edk2 packages.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + DEC_SPECIFICATION = 0x00010005
>> + PACKAGE_NAME = UsbNetworkPkg
>> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
>> + PACKAGE_VERSION = 0.1
>> +
>> +[Includes]
>> + Include
>> +
>> +[Protocols]
>> + ## Include/Protocol/EdkIIUsbEthernet.h
>> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2,
>> 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
>> +
>> +[Guids]
>> + ## Usb Network package token space GUID
>> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, {
>> 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
>> +
>> +[PcdsFeatureFlag]
>> +
>> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm
>> device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
>> +
>> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm
>> device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
>> +
>> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device'
>> need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
>> +
>> +[PcdsFixedAtBuild, PcdsPatchableInModule]
>> + ## Support rate limiting
>> +
>> gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
>> +
>> + ## The rate limiting Credit value is check in rate limiter event.
>> + # It is to control the RateLimitingCreditCount max value.
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
>> +
>> + ## The value of rate limiter event for timeout check. Default
>> value is 100(unit 1ms).
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> new file mode 100644
>> index 000000000000..a3316b1d4a89
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> @@ -0,0 +1,9 @@
>> +## @file
>> +# Global DSC definitions to be included into project DSC file.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Components.X64]
>> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> new file mode 100644
>> index 000000000000..544df8404c64
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
>> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
>> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
>> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> +!endif
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> new file mode 100644
>> index 000000000000..85a309bcf567
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> @@ -0,0 +1,23 @@
>> +## @file
>> +# Global switches enable/disable project features.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
>> + DEFINE PEI=IA32
>> + DEFINE DXE=X64
>> +!else
>> + DEFINE PEI=COMMON
>> + DEFINE DXE=COMMON
>> +!endif
>> +
>> +[Packages]
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[PcdsFeatureFlag]
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
>> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> new file mode 100644
>> index 000000000000..10616d97edb4
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
>> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
>> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
>> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> +!endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> new file mode 100644
>> index 000000000000..8923102bc350
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> @@ -0,0 +1,49 @@
>> +## @file
>> +# This is Usb Network Common driver for DXE phase.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = NetworkCommon
>> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = NetworkCommonEntry
>> +
>> +[Sources]
>> + DriverBinding.c
>> + DriverBinding.h
>> + ComponentName.c
>> + PxeFunction.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + MdeModulePkg/MdeModulePkg.dec
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[LibraryClasses]
>> + UefiDriverEntryPoint
>> + UefiBootServicesTableLib
>> + UefiLib
>> + DebugLib
>> + UefiUsbLib
>> + MemoryAllocationLib
>> + BaseMemoryLib
>> +
>> +[Protocols]
>> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
>> + gEfiUsbIoProtocolGuid
>> + gEfiDevicePathProtocolGuid
>> + gEfiDriverBindingProtocolGuid
>> + gEdkIIUsbEthProtocolGuid
>> +
>> +[Pcd]
>> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> new file mode 100644
>> index 000000000000..64205e427745
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> @@ -0,0 +1,42 @@
>> +## @file
>> +# This is Usb Rndis driver for DXE phase.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = UsbRndis
>> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = UsbRndisEntry
>> +
>> +[Sources]
>> + UsbRndis.c
>> + UsbRndis.h
>> + UsbRndisFunction.c
>> + ComponentName.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[LibraryClasses]
>> + UefiDriverEntryPoint
>> + UefiBootServicesTableLib
>> + UefiLib
>> + DebugLib
>> + UefiUsbLib
>> + MemoryAllocationLib
>> + BaseMemoryLib
>> +
>> +[Protocols]
>> + gEfiUsbIoProtocolGuid
>> + gEfiDevicePathProtocolGuid
>> + gEfiDriverBindingProtocolGuid
>> + gEdkIIUsbEthProtocolGuid
>> +
>> +[Depex]
>> + TRUE
>> diff --git
>> a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> new file mode 100644
>> index 000000000000..f54946c7aa69
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> @@ -0,0 +1,878 @@
>> +/** @file
>> + Header file contains code for USB Ethernet Protocol
>> + definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
>> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
>> +
>> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
>> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f,
>> 0x38, 0x56, 0x43}}
>> +
>> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL
>> EDKII_USB_ETHERNET_PROTOCOL;
>> +
>> +#define USB_CDC_CLASS 0x02
>> +#define USB_CDC_ACM_SUBCLASS 0x02
>> +#define USB_CDC_ECM_SUBCLASS 0x06
>> +#define USB_CDC_NCM_SUBCLASS 0x0D
>> +#define USB_CDC_DATA_CLASS 0x0A
>> +#define USB_CDC_DATA_SUBCLASS 0x00
>> +#define USB_NO_CLASS_PROTOCOL 0x00
>> +#define USB_NCM_NTB_PROTOCOL 0x01
>> +#define USB_VENDOR_PROTOCOL 0xFF
>> +
>> +// Type Values for the DescriptorType Field
>> +#define CS_INTERFACE 0x24
>> +#define CS_ENDPOINT 0x25
>> +
>> +// Descriptor SubType in Functional Descriptors
>> +#define HEADER_FUN_DESCRIPTOR 0x00
>> +#define UNION_FUN_DESCRIPTOR 0x06
>> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
>> +
>> +#define MAX_LAN_INTERFACE 0x10
>> +
>> +// Table 20: Class-Specific Notification Codes
>> +#define USB_CDC_NETWORK_CONNECTION 0x00
>> +
>> +// 6.3.1 NetworkConnection
>> +#define NETWORK_CONNECTED 0x01
>> +#define NETWORK_DISCONNECT 0x00
>> +
>> +// USB Header functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT16 BcdCdc;
>> +} USB_HEADER_FUN_DESCRIPTOR;
>> +
>> +// USB Union Functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT8 MasterInterface;
>> + UINT8 SlaveInterface;
>> +} USB_UNION_FUN_DESCRIPTOR;
>> +
>> +// USB Ethernet Functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT8 MacAddress;
>> + UINT32 EthernetStatistics;
>> + UINT16 MaxSegmentSize;
>> + UINT16 NumberMcFilters;
>> + UINT8 NumberPowerFilters;
>> +} USB_ETHERNET_FUN_DESCRIPTOR;
>> +
>> +typedef struct {
>> + UINT32 UsBitRate;
>> + UINT32 DsBitRate;
>> +} USB_CONNECT_SPEED_CHANGE;
>> +
>> +// Request Type Codes for USB Ethernet
>> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
>> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
>> +
>> +// Class-Specific Request Codes for Ethernet subclass
>> +// USB ECM 1.2 specification, Section 6.2
>> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
>> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
>> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
>> +#define SET_ETH_PACKET_FILTER_REQ 0x43
>> +#define GET_ETH_STATISTIC_REQ 0x44
>> +
>> +// USB ECM command request length
>> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
>> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
>> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
>> +
>> +// USB Ethernet Packet Filter Bitmap
>> +// USB ECM 1.2 specification, Section 6.2.4
>> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
>> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
>> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
>> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
>> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
>> +
>> +// USB Ethernet Statistics Feature Selector Codes
>> +// USB ECM 1.2 specification, Section 6.2.5
>> +#define USB_ETH_XMIT_OK 0x01
>> +#define USB_ETH_RCV_OK 0x02
>> +#define USB_ETH_XMIT_ERROR 0x03
>> +#define USB_ETH_RCV_ERROR 0x04
>> +#define USB_ETH_RCV_NO_BUFFER 0x05
>> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
>> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
>> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
>> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
>> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
>> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
>> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
>> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
>> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
>> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
>> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
>> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
>> +#define USB_ETH_RCV_CRC_ERROR 0x12
>> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
>> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
>> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
>> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
>> +#define USB_ETH_XMIT_DEFERRED 0x17
>> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
>> +#define USB_ETH_RCV_OVERRUN 0x19
>> +#define USB_ETH_XMIT_UNDERRUN 0x1A
>> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
>> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
>> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
>> +
>> +// NIC Information
>> +typedef struct {
>> + UINT32 Signature;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + UINT16 InterrupOpFlag;
>> + UINT64 MappedAddr;
>> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
>> + UINT8 McastCount;
>> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
>> + UINT8 TxBufferCount;
>> + UINT16 State;
>> + BOOLEAN CanTransmit;
>> + UINT16 ReceiveStatus;
>> + UINT8 RxFilter;
>> + UINT32 RxFrame;
>> + UINT32 TxFrame;
>> + UINT16 NetworkConnect;
>> + UINT8 CableDetect;
>> + UINT16 MaxSegmentSize;
>> + EFI_MAC_ADDRESS MacAddr;
>> + PXE_CPB_START_31 PxeStart;
>> + PXE_CPB_INITIALIZE PxeInit;
>> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
>> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
>> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
>> + EFI_USB_DEVICE_REQUEST Request;
>> + EFI_EVENT RateLimiter;
>> + UINT32 RateLimitingCredit;
>> + UINT32 RateLimitingCreditCount;
>> + UINT32 RateLimitingPollTimer;
>> + BOOLEAN RateLimitingEnable;
>> +} NIC_DATA;
>> +
>> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
>> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a,
>> NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
>> +
>> +/**
>> + This command is used to determine the operational state of the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to change the UNDI operational state from
>> stopped to started.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to change the UNDI operational state from
>> started to stopped.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to retrieve initialization information that is
>> + needed by drivers and applications to initialized UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to retrieve configuration information about
>> + the NIC being controlled by the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and reinitializes the UNDI
>> + with the same parameters provided in the Initialize command.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Shutdown command resets the network adapter and leaves it in a
>> + safe state for another driver to initialize.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Interrupt Enables command can be used to read and/or change
>> + the current external interrupt enable settings.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and change receive filters and,
>> + if supported, read and change the multicast MAC address filter list.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to get current station and broadcast MAC
>> addresses
>> + and, if supported, to change the current station MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + Translate a multicast IPv4 or IPv6 address to a multicast MAC
>> address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and write (if supported by NIC H/W)
>> + nonvolatile storage on the NIC.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command returns the current interrupt status and/or the
>> + transmitted buffer addresses and the current media status.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to fill the media header(s) in transmit
>> packet(s).
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Transmit command is used to place a packet into the transmit
>> queue.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + When the network adapter has received a frame, this command is used
>> + to copy the frame into driver/application storage.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller
>> data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Nic A pointer to the Network interface controller
>> data.
>> + @param[in] DbAddr Data Block Address.
>> + @param[in] DbSize Data Block Size.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with the bulk
>> transfer pipe. The endpoint is Bulk in.
>> +
>> + @param[in] Cdb A pointer to the command descriptor
>> block.
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] Packet A pointer to the buffer of data that
>> will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] PacketLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been
>> successfully executed.
>> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer
>> status is returned in status.
>> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted
>> due to a lack of resources.
>> + @retval EFI_TIMEOUT The control transfer fails due to
>> timeout.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *Packet,
>> + IN OUT UINTN *PacketLength
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with the bulk
>> transfer pipe. The endpoint is Bulk out.
>> +
>> + @param[in] Cdb A pointer to the command descriptor
>> block.
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] Packet A pointer to the buffer of data that
>> will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] PacketLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been
>> successfully executed.
>> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer
>> status is returned in status.
>> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted
>> due to a lack of resources.
>> + @retval EFI_TIMEOUT The control transfer fails due to
>> timeout.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *Packet,
>> + IN OUT UINTN *PacketLength
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with an interrupt
>> transfer pipe.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] IsNewTransfer If TRUE, a new transfer will be
>> submitted to USB controller. If
>> + FALSE, the interrupt transfer is
>> deleted from the device's interrupt
>> + transfer queue.
>> + @param[in] PollingInterval Indicates the periodic rate, in
>> milliseconds, that the transfer is to be
>> + executed.This parameter is required
>> when IsNewTransfer is TRUE. The
>> + value must be between 1 to 255,
>> otherwise EFI_INVALID_PARAMETER is returned.
>> + The units are in milliseconds.
>> + @param[in] Request A pointer to the
>> EFI_USB_DEVICE_REQUEST data.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer
>> request transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer
>> request failed.
>> +
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Request
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet Mac Address.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] MacAddress A pointer to the caller allocated USB
>> Ethernet Mac Address.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor
>> was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet Bulk transfer data size.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] BulkSize A pointer to the Bulk transfer data size.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor
>> was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + );
>> +
>> +/**
>> + Retrieves the USB Header functional Descriptor.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbHeaderFunDescriptor A pointer to the caller
>> allocated USB Header Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor
>> was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + );
>> +
>> +/**
>> + Retrieves the USB Union functional Descriptor.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbUnionFunDescriptor A pointer to the caller
>> allocated USB Union Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Union Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Union Functional descriptor
>> was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet functional Descriptor.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbEthFunDescriptor A pointer to the caller
>> allocated USB Ethernet Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Ethernet Functional
>> descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Ethernet Functional
>> descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + );
>> +
>> +/**
>> + This request sets the Ethernet device multicast filters as
>> specified in the
>> + sequential list of 48 bit Ethernet multicast addresses.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] McastAddr A pointer to the value of the
>> multicast addresses.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + );
>> +
>> +/**
>> + This request sets up the specified Ethernet power management
>> pattern filter as
>> + described in the data structure.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] Length Size of the power management
>> pattern filter data.
>> + @param[in] PatternFilter A pointer to the power
>> management pattern filter structure.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + );
>> +
>> +/**
>> + This request retrieves the status of the specified Ethernet power
>> management
>> + pattern filter from the device.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value The filter number.
>> + @param[out] PatternActive A pointer to the pattern active
>> boolean.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + OUT BOOLEAN *PatternActive
>> + );
>> +
>> +/**
>> + This request is used to configure device Ethernet packet filter
>> settings.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Packet Filter Bitmap.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + );
>> +
>> +/**
>> + This request is used to retrieve a statistic based on the feature
>> selector.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] FeatureSelector Value of the feature selector.
>> + @param[out] Statistic A pointer to the 32 bit unsigned
>> integer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 FeatureSelector,
>> + OUT VOID *Statistic
>> + );
>> +
>> +typedef struct {
>> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
>> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
>> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
>> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
>> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
>> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
>> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
>> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
>> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
>> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
>> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
>> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
>> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
>> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
>> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
>> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
>> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
>> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
>> +} EDKII_USB_ETHERNET_UNDI;
>> +
>> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet
>> device relevant
>> +// descriptor and specific requests.
>> +struct _EDKII_USB_ETHERNET_PROTOCOL {
>> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
>> + // for calling the UNDI child functions
>> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
>> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
>> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
>> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
>> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
>> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
>> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
>> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
>> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
>> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
>> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
>> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER
>> SetUsbEthPowerPatternFilter;
>> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER
>> GetUsbEthPowerPatternFilter;
>> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
>> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
>> +};
>> +
>> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> new file mode 100644
>> index 000000000000..0416ce132302
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> @@ -0,0 +1,266 @@
>> +/** @file
>> + Header file for for USB network common driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef _DRIVER_BINDING_H_
>> +#define _DRIVER_BINDING_H_
>> +
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/UefiUsbLib.h>
>> +#include <Protocol/UsbIo.h>
>> +#include <Protocol/NetworkInterfaceIdentifier.h>
>> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
>> +
>> +#define NETWORK_COMMON_DRIVER_VERSION 1
>> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
>> +#define RX_BUFFER_COUNT 32
>> +#define TX_BUFFER_COUNT 32
>> +#define MEMORY_REQUIRE 0
>> +
>> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
>> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol,
>> UNDI_DEV_SIGNATURE)
>> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo,
>> UNDI_DEV_SIGNATURE)
>> +
>> +#pragma pack(1)
>> +typedef struct {
>> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
>> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
>> + UINT16 Protocol;
>> +} EthernetHeader;
>> +#pragma pack()
>> +
>> +typedef struct {
>> + UINTN Signature;
>> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
>> + EFI_HANDLE DeviceHandle;
>> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
>> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
>> + NIC_DATA NicInfo;
>> + VOID *ReceiveBuffer;
>> +} NIC_DEVICE;
>> +
>> +typedef VOID (*API_FUNC)(
>> + PXE_CDB *,
>> + NIC_DATA *
>> + );
>> +
>> +extern PXE_SW_UNDI *gPxe;
>> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
>> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + );
>> +
>> +VOID
>> +PxeStructInit (
>> + OUT PXE_SW_UNDI *PxeSw
>> + );
>> +
>> +VOID
>> +UpdateNicNum (
>> + IN NIC_DATA *Nic,
>> + IN OUT PXE_SW_UNDI *PxeSw
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UndiApiEntry (
>> + IN UINT64 Cdb
>> + );
>> +
>> +UINTN
>> +MapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + OUT UINT64 MappedAddr
>> + );
>> +
>> +VOID
>> +UnMapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + IN UINT64 MappedAddr
>> + );
>> +
>> +VOID
>> +UndiGetState (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiInterruptEnable (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStationAddress (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStatistics (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiMcastIp2Mac (
>> + IN OUT PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiNvData (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiFillHeader (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +UINT16
>> +Initialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +UINT16
>> +Transmit (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN UINT16 OpFlags
>> + );
>> +
>> +UINT16
>> +Receive (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN OUT UINT64 DbAddr
>> + );
>> +
>> +UINT16
>> +SetFilter (
>> + IN NIC_DATA *Nic,
>> + IN UINT16 SetFilter,
>> + IN UINT64 CpbAddr,
>> + IN UINT32 CpbSize
>> + );
>> +
>> +UINT16
>> +Statistics (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + );
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> new file mode 100644
>> index 000000000000..775807042460
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> @@ -0,0 +1,586 @@
>> +/** @file
>> + Header file for for USB Rndis driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef _USB_RNDIS_H_
>> +#define _USB_RNDIS_H_
>> +
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/UefiUsbLib.h>
>> +#include <Protocol/UsbIo.h>
>> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
>> +
>> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
>> +
>> +typedef struct {
>> + UINT32 Signature;
>> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
>> + EFI_HANDLE UsbCdcDataHandle;
>> + EFI_HANDLE UsbRndisHandle;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
>> + EFI_USB_CONFIG_DESCRIPTOR *Config;
>> + UINT8 NumOfInterface;
>> + UINT8 BulkInEndpoint;
>> + UINT8 BulkOutEndpoint;
>> + UINT8 InterrupEndpoint;
>> + EFI_MAC_ADDRESS MacAddress;
>> + UINT32 RequestId;
>> + UINT32 Medium;
>> + UINT32 MaxPacketsPerTransfer;
>> + UINT32 MaxTransferSize;
>> + UINT32 PacketAlignmentFactor;
>> + LIST_ENTRY ReceivePacketList;
>> +} USB_RNDIS_DEVICE;
>> +
>> +#define USB_RNDIS_DRIVER_VERSION 1
>> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
>> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
>> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
>> +
>> +#define LAN_BULKIN_CMD_CONTROL 1
>> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum
>> counts for waiting bulk in command
>> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum
>> counts for waiting bulk in command
>> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the
>> waiting counts for send bulk in command when system pending
>> +#define RNDIS_RESERVED_BYTE_LENGTH 8
>> +
>> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
>> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE,
>> UsbEth, USB_RNDIS_SIGNATURE)
>> +
>> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
>> +
>> +struct BIT_MAP {
>> + unsigned int Src;
>> + unsigned int Dst;
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + );
>> +
>> +EFI_STATUS
>> +LoadAllDescriptor (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
>> + );
>> +
>> +BOOLEAN
>> +NextDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
>> + IN OUT UINTN *Offset
>> + );
>> +
>> +EFI_STATUS
>> +GetFunctionalDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
>> + IN UINT8 FunDescriptorType,
>> + OUT VOID *DataBuffer
>> + );
>> +
>> +VOID
>> +GetEndpoint (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisInterrupt (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Requst
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +InterruptCallback (
>> + IN VOID *Data,
>> + IN UINTN DataLength,
>> + IN VOID *Context,
>> + IN UINT32 Status
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbEthMacAddress (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbEthBulkSize (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisDummyReturn (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN VOID *BulkOutData,
>> + IN OUT UINTN *DataLength
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *BulkInData,
>> + IN OUT UINTN *DataLength
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbHeaderFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbUnionFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisMcastFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN BOOLEAN *PatternActive
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPacketFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetRndisStatistic (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *Statistic
>> + );
>> +
>> +EFI_STATUS
>> +RndisControlMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
>> + );
>> +
>> +EFI_STATUS
>> +RndisTransmitDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + UINTN *TransferLength
>> + );
>> +
>> +EFI_STATUS
>> +RndisReceiveDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + UINTN *TransferLength
>> + );
>> +
>> +VOID
>> +PrintRndisMsg (
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
>> + );
>> +
>> +#define RNDIS_MAJOR_VERSION 0x00000001
>> +#define RNDIS_MINOR_VERSION 0x00000000
>> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
>> +
>> +#define RNDIS_PACKET_MSG 0x00000001
>> +#define RNDIS_INITIALIZE_MSG 0x00000002
>> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
>> +#define RNDIS_HLT_MSG 0x00000003
>> +#define RNDIS_QUERY_MSG 0x00000004
>> +#define RNDIS_QUERY_CMPLT 0x80000004
>> +#define RNDIS_SET_MSG 0x00000005
>> +#define RNDIS_SET_CMPLT 0x80000005
>> +#define RNDIS_RESET_MSG 0x00000006
>> +#define RNDIS_RESET_CMPLT 0x80000006
>> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
>> +#define RNDIS_KEEPALIVE_MSG 0x00000008
>> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
>> +
>> +#define RNDIS_STATUS_SUCCESS 0x00000000
>> +#define RNDIS_STATUS_FAILURE 0xC0000001
>> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
>> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
>> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
>> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
>> +
>> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
>> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
>> +
>> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
>> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
>> +
>> +//
>> +// General Objects
>> +//
>> +// Taken from NTDDNDIS.H
>> +#define OID_GEN_SUPPORTED_LIST 0x00010101
>> +#define OID_GEN_HARDWARE_STATUS 0x00010102
>> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
>> +#define OID_GEN_MEDIA_IN_USE 0x00010104
>> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
>> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
>> +#define OID_GEN_LINK_SPEED 0x00010107
>> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
>> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
>> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
>> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
>> +#define OID_GEN_VENDOR_ID 0x0001010C
>> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
>> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
>> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
>> +#define OID_GEN_DRIVER_VERSION 0x00010110
>> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
>> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
>> +#define OID_GEN_MAC_OPTIONS 0x00010113
>> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
>> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
>> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
>> +
>> +#define OID_GEN_XMIT_OK 0x00020101
>> +#define OID_GEN_RCV_OK 0x00020102
>> +#define OID_GEN_XMIT_ERROR 0x00020103
>> +#define OID_GEN_RCV_ERROR 0x00020104
>> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
>> +
>> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
>> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
>> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
>> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
>> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
>> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
>> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
>> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
>> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
>> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
>> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
>> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
>> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
>> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
>> +
>> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
>> +//
>> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
>> +//
>> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
>> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
>> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
>> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
>> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
>> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
>> +#define NDIS_PACKET_TYPE_SMT 0x0040
>> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
>> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
>> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
>> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
>> +#define NDIS_PACKET_TYPE_GROUP 0x1000
>> +
>> +#pragma pack(1)
>> +
>> +typedef struct _REMOTE_NDIS_MSG_HEADER {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> +} REMOTE_NDIS_MSG_HEADER;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 MajorVersion;
>> + UINT32 MinorVersion;
>> + UINT32 MaxTransferSize;
>> +} REMOTE_NDIS_INITIALIZE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> +} REMOTE_NDIS_HALT_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Oid;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_QUERY_MSG;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_MSG QueryMsg;
>> + UINT8 Addr[6];
>> +} REMOTE_NDIS_QUERY_MAC_MSG;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_MSG QueryMsg;
>> + UINT32 MaxTotalSize;
>> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Oid;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_SET_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_RESET_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Status;
>> + UINT32 StatusBufferLength;
>> + UINT32 StatusBufferOffset;
>> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
>> +
>> +typedef struct {
>> + UINT32 DiagStatus;
>> + UINT32 ErrorOffset;
>> +} RNDIS_DIAGNOSTIC_INFO;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> +} REMOTE_NDIS_KEEPALIVE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> + UINT32 MajorVersion;
>> + UINT32 MinorVersion;
>> + UINT32 DeviceFlags;
>> + UINT32 Medium;
>> + UINT32 MaxPacketsPerTransfer;
>> + UINT32 MaxTransferSize;
>> + UINT32 PacketAlignmentFactor;
>> + UINT64 Reserved;
>> +} REMOTE_NDIS_INITIALIZE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> +} REMOTE_NDIS_QUERY_CMPLT;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
>> + UINT8 Addr[6];
>> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
>> + UINT32 MaxTotalSize;
>> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> +} REMOTE_NDIS_SET_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Status;
>> + UINT32 AddressingReset;
>> +} REMOTE_NDIS_RESET_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 DataOffset;
>> + UINT32 DataLength;
>> + UINT32 OutOfBandDataOffset;
>> + UINT32 OutOfBandDataLength;
>> + UINT32 NumOutOfBandDataElements;
>> + UINT32 PerPacketInfoOffset;
>> + UINT32 PerPacketInfoLength;
>> + UINT32 Reserved1;
>> + UINT32 Reserved2;
>> +} REMOTE_NDIS_PACKET_MSG;
>> +
>> +typedef struct {
>> + UINT32 Size;
>> + UINT32 Type;
>> + UINT32 ClassInformationOffset;
>> +} OUT_OF_BAND_DATA_RECORD;
>> +
>> +typedef struct {
>> + UINT32 Size;
>> + UINT32 Type;
>> + UINT32 ClassInformationOffset;
>> +} PER_PACKET_INFO_DATA_RECORD;
>> +
>> +typedef struct {
>> + LIST_ENTRY PacketList;
>> + UINT8 *OrgBuffer;
>> + UINTN RemainingLength;
>> + UINT8 *PacketStartBuffer; // Variable size data to follow
>> +} PACKET_LIST;
>> +
>> +#pragma pack()
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> new file mode 100644
>> index 000000000000..e83469e13079
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> @@ -0,0 +1,263 @@
>> +/** @file
>> + This file contains code for USB network common driver
>> + component name definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
>> gNetworkCommonDriverNameTable[] = {
>> + {
>> + "eng;en",
>> + L"Network Common Driver"
>> + },
>> + {
>> + NULL,
>> + NULL
>> + }
>> +};
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
>> *gNetworkCommonControllerNameTable = NULL;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL
>> gNetworkCommonComponentName = {
>> + NetworkCommonComponentNameGetDriverName,
>> + NetworkCommonComponentNameGetControllerName,
>> + "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL
>> gNetworkCommonComponentName2 = {
>> +
>> (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
>> +
>> (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
>> + "en"
>> +};
>> +
>> +/**
>> + 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[in] This A pointer to the
>> EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Language 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[out] DriverName 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
>> +NetworkCommonComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + )
>> +{
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gNetworkCommonDriverNameTable,
>> + DriverName,
>> + (BOOLEAN)(This == &gNetworkCommonComponentName)
>> + );
>> +}
>> +
>> +/**
>> + 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[in] This A pointer to the
>> EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid
>> EFI_HANDLE.
>> + @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
>> +NetworkCommonComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + )
>> +{
>> + EFI_STATUS Status;
>> + CHAR16 *HandleName;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
>> +
>> + if (!Language || !ControllerName) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + if (ChildHandle == NULL) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + //
>> + // Make sure this driver is currently managing ControllerHandle
>> + //
>> + Status = EfiTestManagedDevice (
>> + Controller,
>> + gNetworkCommonDriverBinding.DriverBindingHandle,
>> + &gEdkIIUsbEthProtocolGuid
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + //
>> + // Make sure this driver produced ChildHandle
>> + //
>> + Status = EfiTestChildHandle (
>> + Controller,
>> + ChildHandle,
>> + &gEdkIIUsbEthProtocolGuid
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid,
>> (VOID **)&UsbIo);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409,
>> DevDesc.StrManufacturer, &HandleName);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *ControllerName = HandleName;
>> +
>> + if (gNetworkCommonControllerNameTable != NULL) {
>> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
>> + gNetworkCommonControllerNameTable = NULL;
>> + }
>> +
>> + Status = AddUnicodeString2 (
>> + "eng",
>> + gNetworkCommonComponentName.SupportedLanguages,
>> + &gNetworkCommonControllerNameTable,
>> + HandleName,
>> + TRUE
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = AddUnicodeString2 (
>> + "en",
>> + gNetworkCommonComponentName2.SupportedLanguages,
>> + &gNetworkCommonControllerNameTable,
>> + HandleName,
>> + FALSE
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gNetworkCommonControllerNameTable,
>> + ControllerName,
>> + (BOOLEAN)(This == &gNetworkCommonComponentName)
>> + );
>> + }
>> +
>> + return EFI_UNSUPPORTED;
>> +}
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> new file mode 100644
>> index 000000000000..23b791362091
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> @@ -0,0 +1,595 @@
>> +/** @file
>> + This file contains code for USB network binding driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +PXE_SW_UNDI *gPxe = NULL;
>> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
>> +UINT32 gRateLimitingCredit;
>> +UINT32 gRateLimitingPollTimer;
>> +BOOLEAN gRateLimitingEnable;
>> +
>> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
>> + NetworkCommonSupported,
>> + NetworkCommonDriverStart,
>> + NetworkCommonDriverStop,
>> + NETWORK_COMMON_DRIVER_VERSION,
>> + NULL,
>> + NULL
>> +};
>> +
>> +/**
>> + Create MAC Device Path
>> +
>> + @param[in, out] Dev A pointer to the
>> EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] BaseDev A pointer to the
>> EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] Nic A pointer to the Network interface
>> controller data.
>> +
>> + @retval EFI_OUT_OF_RESOURCES The device path could not be
>> created successfully due to a lack of resources.
>> + @retval EFI_SUCCESS MAC device path created successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +CreateMacDevicePath (
>> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
>> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> + MAC_ADDR_DEVICE_PATH MacAddrNode;
>> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
>> + UINT8 *DevicePath;
>> + UINT16 TotalLength;
>> + UINT16 BaseLength;
>> +
>> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
>> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof
>> (EFI_MAC_ADDRESS));
>> +
>> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
>> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
>> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
>> + MacAddrNode.Header.Length[1] = 0;
>> +
>> + EndNode = BaseDev;
>> +
>> + while (!IsDevicePathEnd (EndNode)) {
>> + EndNode = NextDevicePathNode (EndNode);
>> + }
>> +
>> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
>> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof
>> (EFI_DEVICE_PATH_PROTOCOL));
>> +
>> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength,
>> (VOID **)&DevicePath);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
>> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
>> + DevicePath += BaseLength;
>> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
>> + DevicePath += sizeof (MacAddrNode);
>> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof
>> (EFI_DEVICE_PATH_PROTOCOL));
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Support.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to test.
>> + @param[in] 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
>> +NetworkCommonSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Start.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind
>> driver to.
>> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install
>> successfully due to a lack of resources.
>> + @retval other This driver does not support
>> this device
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + EFI_MAC_ADDRESS MacAddress;
>> + UINTN BulkDataSize;
>> + NIC_DEVICE *NicDevice;
>> + UINT8 *TmpPxePointer;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbEthPath,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
>> +
>> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
>> + ASSERT_EFI_ERROR (Status);
>> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize +
>> 4096);
>> + if (!NicDevice) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + // for alignment adjustment
>> + if (gPxe == NULL) {
>> + TmpPxePointer = NULL;
>> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
>> + if (!TmpPxePointer) {
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + return EFI_OUT_OF_RESOURCES;
>> + } else {
>> + // check for paragraph alignment here
>> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
>> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
>> + } else {
>> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
>> + }
>> +
>> + if (!gPxe) {
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + PxeStructInit (gPxe);
>> + }
>> + }
>> +
>> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
>> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
>> +
>> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
>> +
>> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
>> +
>> + NicDevice->NicInfo.UsbEth = UsbEth;
>> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
>> + NicDevice->NicInfo.CableDetect = 0;
>> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID
>> *)NicDevice, 4096);
>> +
>> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8
>> *)&MacAddress, sizeof (MacAddress));
>> +
>> + NicDevice->NicInfo.TxBufferCount = 0;
>> +
>> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
>> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
>> + } else {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> +
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = CreateMacDevicePath (
>> + &NicDevice->DevPath,
>> + UsbEthPath,
>> + &NicDevice->NicInfo
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + UpdateNicNum (NULL, gPxe);
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> + }
>> +
>> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
>> + NicDevice->NiiProtocol.Revision =
>> EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
>> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
>> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
>> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
>> + NicDevice->NiiProtocol.ImageSize = 0;
>> + NicDevice->NiiProtocol.ImageAddr = 0;
>> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
>> +
>> + NicDevice->NiiProtocol.StringId[0] = 'U';
>> + NicDevice->NiiProtocol.StringId[1] = 'N';
>> + NicDevice->NiiProtocol.StringId[2] = 'D';
>> + NicDevice->NiiProtocol.StringId[3] = 'I';
>> + NicDevice->DeviceHandle = NULL;
>> +
>> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
>> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
>> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
>> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
>> + NicDevice->NicInfo.RateLimiter = NULL;
>> +
>> + ZeroMem (&NicDevice->NicInfo.Request, sizeof
>> (EFI_USB_DEVICE_REQUEST));
>> +
>> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE,
>> NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &NicDevice->DeviceHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
>> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> +
>> + if (NicDevice->DevPath != NULL) {
>> + FreePool (NicDevice->DevPath);
>> + }
>> +
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + NicDevice->DeviceHandle,
>> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> + );
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Stop.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to stop driver on
>> + @param[in] NumberOfChildren Number of Handles in
>> ChildHandleBuffer. If number of
>> + children is zero stop the entire
>> bus driver.
>> + @param[in] 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
>> +NetworkCommonDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + BOOLEAN AllChildrenStopped;
>> + UINTN Index;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + NIC_DEVICE *NicDevice;
>> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
>> +
>> + if (NumberOfChildren == 0) {
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + (VOID **)&NiiProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_SUCCESS;
>> + }
>> +
>> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
>> + Status = gBS->UninstallMultipleProtocolInterfaces (
>> + ControllerHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + FreePool (NicDevice->DevPath);
>> + FreePool (NicDevice);
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_SUCCESS;
>> + }
>> +
>> + AllChildrenStopped = TRUE;
>> +
>> + for (Index = 0; Index < NumberOfChildren; Index++) {
>> + Status = gBS->OpenProtocol (
>> + ChildHandleBuffer[Index],
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + (VOID **)&NiiProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + AllChildrenStopped = FALSE;
>> + continue;
>> + }
>> +
>> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ChildHandleBuffer[Index]
>> + );
>> +
>> + Status = gBS->UninstallMultipleProtocolInterfaces (
>> + ChildHandleBuffer[Index],
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ChildHandleBuffer[Index],
>> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> + );
>> + } else {
>> + FreePool (NicDevice->DevPath);
>> + FreePool (NicDevice);
>> + }
>> + }
>> +
>> + if (!AllChildrenStopped) {
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Entrypoint of Network Common Driver.
>> +
>> + This function is the entrypoint of Network Common Driver. It
>> installs Driver Binding
>> + Protocols together with Component Name Protocols.
>> +
>> + @param[in] ImageHandle The firmware allocated handle for
>> the EFI image.
>> + @param[in] SystemTable A pointer to the EFI System Table.
>> +
>> + @retval EFI_SUCCESS The entry point is executed
>> successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonEntry (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
>> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
>> + gRateLimitingEnable = PcdGetBool
>> (EnableRateLimiting);
>> + gRateLimitingCredit = PcdGet32
>> (RateLimitingCredit);
>> + gRateLimitingPollTimer = PcdGet32
>> (RateLimitingFactor);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &gNetworkCommonDriverBinding.DriverBindingHandle,
>> + &gEfiDriverBindingProtocolGuid,
>> + &gNetworkCommonDriverBinding,
>> + &gEfiComponentName2ProtocolGuid,
>> + &gNetworkCommonComponentName2,
>> + NULL
>> + );
>> + return Status;
>> +}
>> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> new file mode 100644
>> index 000000000000..687cabca4ce3
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> @@ -0,0 +1,1803 @@
>> +/** @file
>> + This file contains code for UNDI command based on UEFI specification.
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +// API table, defined in UEFI specification
>> +API_FUNC gUndiApiTable[] = {
>> + UndiGetState,
>> + UndiStart,
>> + UndiStop,
>> + UndiGetInitInfo,
>> + UndiGetConfigInfo,
>> + UndiInitialize,
>> + UndiReset,
>> + UndiShutdown,
>> + UndiInterruptEnable,
>> + UndiReceiveFilter,
>> + UndiStationAddress,
>> + UndiStatistics,
>> + UndiMcastIp2Mac,
>> + UndiNvData,
>> + UndiGetStatus,
>> + UndiFillHeader,
>> + UndiTransmit,
>> + UndiReceive
>> +};
>> +
>> +/**
>> + Callback function for enable Rate Limiter
>> +
>> + @param[in] Event Event whose notification function is
>> being invoked
>> + @param[in] Context Pointer to the notification function's
>> context
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +UndiRateLimiterCallback (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + )
>> +{
>> + NIC_DATA *Nic = Context;
>> +
>> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
>> + Nic->RateLimitingCreditCount++;
>> + }
>> +}
>> +
>> +/**
>> + This command is used to determine the operational state of the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetState (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to change the UNDI operational state from
>> stopped to started.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_START_31 *Cpb;
>> + EFI_STATUS Status;
>> + BOOLEAN EventError;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
>> +
>> + Nic->PxeStart.Delay = Cpb->Delay;
>> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
>> + Nic->PxeStart.Block = Cpb->Block;
>> + Nic->PxeStart.Map_Mem = 0;
>> + Nic->PxeStart.UnMap_Mem = 0;
>> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
>> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
>> + EventError = FALSE;
>> + Status = EFI_SUCCESS;
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + Status = gBS->CreateEvent (
>> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
>> + TPL_NOTIFY,
>> + UndiRateLimiterCallback,
>> + Nic,
>> + &Nic->RateLimiter
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + Status = gBS->SetTimer (
>> + Nic->RateLimiter,
>> + TimerPeriodic,
>> + Nic->RateLimitingPollTimer * 10000
>> + );
>> + if (EFI_ERROR (Status)) {
>> + EventError = TRUE;
>> + }
>> + }
>> + }
>> +
>> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) &&
>> (EventError == FALSE)) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
>> + }
>> +
>> + if (!EFI_ERROR (Status)) {
>> + // Initial the state for UNDI start.
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + } else {
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + if (!EventError) {
>> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
>> + }
>> +
>> + if (Nic->RateLimiter) {
>> + gBS->CloseEvent (&Nic->RateLimiter);
>> + Nic->RateLimiter = 0;
>> + }
>> + }
>> +
>> + // Initial the state when UNDI start is fail
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
>> + }
>> +}
>> +
>> +/**
>> + This command is used to change the UNDI operational state from
>> started to stopped.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
>> + return;
>> + }
>> +
>> + Nic->PxeStart.Delay = 0;
>> + Nic->PxeStart.Virt2Phys = 0;
>> + Nic->PxeStart.Block = 0;
>> + Nic->PxeStart.Map_Mem = 0;
>> + Nic->PxeStart.UnMap_Mem = 0;
>> + Nic->PxeStart.Sync_Mem = 0;
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
>> +
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
>> + gBS->CloseEvent (&Nic->RateLimiter);
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to retrieve initialization information that is
>> + needed by drivers and applications to initialized UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_INIT_INFO *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->MemoryRequired = MEMORY_REQUIRE;
>> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
>> + Db->LinkSpeeds[0] = 10;
>> + Db->LinkSpeeds[1] = 100;
>> + Db->LinkSpeeds[2] = 1000;
>> + Db->LinkSpeeds[3] = 0;
>> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
>> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
>> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
>> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
>> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
>> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
>> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
>> + Db->IFtype = PXE_IFTYPE_ETHERNET;
>> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
>> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
>> +
>> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
>> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to retrieve configuration information about
>> + the NIC being controlled by the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_CONFIG_INFO *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->pci.BusType = PXE_BUSTYPE_USB;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb,
>> Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller
>> data.
>> +
>> +**/
>> +VOID
>> +UndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_INITIALIZE *Cpb;
>> + PXE_DB_INITIALIZE *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
>> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
>> +
>> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
>> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
>> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
>> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
>> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
>> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
>> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
>> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
>> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
>> +
>> + Cdb->StatCode = Initialize (Cdb, Nic);
>> +
>> + Db->MemoryUsed = MEMORY_REQUIRE;
>> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
>> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
>> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
>> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
>> +
>> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
>> + Nic->CanTransmit = FALSE;
>> +
>> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
>> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) &&
>> (Nic->Request.Value == NETWORK_DISCONNECT)) {
>> + Nic->CableDetect = 0;
>> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION)
>> && (Nic->Request.Value == NETWORK_CONNECTED)) {
>> + Nic->CableDetect = 1;
>> + }
>> +
>> + if (Nic->CableDetect == 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
>> + }
>> + }
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Initialize Network interface controller data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface
>> controller data.
>> +
>> + @retval Status A value of Pxe statcode.
>> +
>> +**/
>> +UINT16
>> +Initialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + UINTN Status;
>> + UINT32 Index;
>> + EFI_STATUS EfiStatus;
>> +
>> + Status = MapIt (
>> + Nic,
>> + Nic->PxeInit.MemoryAddr,
>> + Nic->PxeInit.MemoryLength,
>> + TO_AND_FROM_DEVICE,
>> + (UINT64)(UINTN)&Nic->MappedAddr
>> + );
>> +
>> + if (Status != 0) {
>> + return (UINT16)Status;
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->BroadcastNodeAddress[Index] = 0xFF;
>> + }
>> +
>> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = 0;
>> + Nic->PermNodeAddress[Index] = 0;
>> + Nic->BroadcastNodeAddress[Index] = 0;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
>> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
>> + if (EFI_ERROR (EfiStatus)) {
>> + return PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + return (UINT16)Status;
>> +}
>> +
>> +/**
>> + This command resets the network adapter and reinitializes the UNDI
>> + with the same parameters provided in the Initialize command.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
>> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
>> + Nic->InterrupOpFlag = 0;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Shutdown command resets the network adapter and leaves it in a
>> + safe state for another driver to initialize.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller
>> data.
>> +
>> +**/
>> +VOID
>> +UndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + Nic->CanTransmit = FALSE;
>> +
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Interrupt Enables command can be used to read and/or change
>> + the current external interrupt enable settings.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiInterruptEnable (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb,
>> Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and change receive filters and,
>> + if supported, read and change the multicast MAC address filter list.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + UINT16 NewFilter;
>> + PXE_DB_RECEIVE_FILTERS *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>> +
>> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
>> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
>> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST)
>> == 0) {
>> + if ((Cdb->DBsize != 0)) {
>> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
>> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
>> + }
>> + }
>> +
>> + break;
>> +
>> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
>> + if (NewFilter == 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if (Cdb->CPBsize != 0) {
>> + if (((NewFilter &
>> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
>> + ((NewFilter &
>> PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
>> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST)
>> != 0) ||
>> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + if ((Cdb->OpFlags &
>> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
>> + if (((Cdb->OpFlags &
>> PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
>> + ((Cdb->OpFlags &
>> PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if ((Cdb->CPBsize == 0)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr,
>> Cdb->CPBsize);
>> + break;
>> +
>> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
>> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + break;
>> +
>> + default:
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb,
>> Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Set PXE receive filter.
>> +
>> + @param[in] Nic A pointer to the Network interface
>> controller data.
>> + @param[in] SetFilter PXE receive filter
>> + @param[in] CpbAddr Command Parameter Block Address
>> + @param[in] CpbSize Command Parameter Block Size
>> +
>> +**/
>> +UINT16
>> +SetFilter (
>> + IN NIC_DATA *Nic,
>> + IN UINT16 SetFilter,
>> + IN UINT64 CpbAddr,
>> + IN UINT32 CpbSize
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 *McastList;
>> + UINT8 Count;
>> + UINT8 Index1;
>> + UINT8 Index2;
>> + PXE_CPB_RECEIVE_FILTERS *Cpb;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> +
>> + Count = 0;
>> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
>> +
>> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
>> + Nic->RxFilter = (UINT8)SetFilter;
>> +
>> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST)
>> != 0) || (Cpb != NULL)) {
>> + if (Cpb != NULL) {
>> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
>> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
>> + }
>> +
>> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth,
>> &UsbEthFunDescriptor);
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + } else {
>> + Status = gBS->AllocatePool (EfiBootServicesData,
>> Nic->McastCount * 6, (VOID **)&McastList);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Cpb != NULL) {
>> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
>> + for (Index2 = 0; Index2 < 6; Index2++) {
>> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
>> + }
>> + }
>> + }
>> +
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
>> + if (Cpb != NULL) {
>> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth,
>> Nic->McastCount, McastList);
>> + }
>> +
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + FreePool (McastList);
>> + }
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + This command is used to get current station and broadcast MAC
>> addresses
>> + and, if supported, to change the current station MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStationAddress (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_STATION_ADDRESS *Cpb;
>> + PXE_DB_STATION_ADDRESS *Db;
>> + UINT16 Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
>> + if (CompareMem (&Nic->CurrentNodeAddress[0],
>> &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
>> + }
>> + }
>> + }
>> +
>> + if (Cdb->CPBaddr != 0) {
>> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
>> + }
>> + }
>> +
>> + if (Cdb->DBaddr != 0) {
>> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
>> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
>> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb,
>> Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStatistics (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Return data for DB data.
>> +
>> + @param[in] Nic A pointer to the Network interface controller
>> data.
>> + @param[in] DbAddr Data Block Address.
>> + @param[in] DbSize Data Block Size.
>> +
>> +**/
>> +UINT16
>> +Statistics (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + )
>> +{
>> + PXE_DB_STATISTICS *DbStatistic;
>> + EFI_STATUS Status;
>> +
>> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
>> +
>> + if (DbSize == 0) {
>> + return PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + DbStatistic->Supported = 0x802;
>> + DbStatistic->Data[0x01] = Nic->RxFrame;
>> + DbStatistic->Data[0x0B] = Nic->TxFrame;
>> +
>> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
>> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Translate a multicast IPv4 or IPv6 address to a multicast MAC
>> address.
>> +
>> + @param[in, out] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller
>> data.
>> +
>> +**/
>> +VOID
>> +UndiMcastIp2Mac (
>> + IN OUT PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
>> + PXE_DB_MCAST_IP_TO_MAC *Db;
>> + UINT8 *Tmp;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
>> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + return;
>> + }
>> +
>> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
>> +
>> + if ((Tmp[0] & 0xF0) != 0xE0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
>> + }
>> +
>> + Db->MAC[0] = 0x01;
>> + Db->MAC[1] = 0x00;
>> + Db->MAC[2] = 0x5E;
>> + Db->MAC[3] = Tmp[1] & 0x7F;
>> + Db->MAC[4] = Tmp[2];
>> + Db->MAC[5] = Tmp[3];
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and write (if supported by NIC H/W)
>> + nonvolatile storage on the NIC.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiNvData (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command returns the current interrupt status and/or the
>> + transmitted buffer addresses and the current media status.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_STATUS *Db;
>> + PXE_DB_GET_STATUS TmpGetStatus;
>> + UINT16 NumEntries;
>> + UINTN Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + TmpGetStatus.RxFrameLen = 0;
>> + TmpGetStatus.reserved = 0;
>> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
>> +
>> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
>> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
>> + } else {
>> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
>> + if (Cdb->DBsize == 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + NumEntries = Cdb->DBsize - sizeof (UINT64);
>> + Cdb->DBsize = sizeof (UINT32) * 2;
>> +
>> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++,
>> NumEntries -= sizeof (UINT64)) {
>> + if (Nic->TxBufferCount > 0) {
>> + Nic->TxBufferCount--;
>> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
>> + }
>> + }
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
>> + if (Nic->ReceiveStatus != 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
>> + }
>> + }
>> +
>> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) &&
>> (Nic->Request.Value == NETWORK_DISCONNECT)) {
>> + Nic->CableDetect = 0;
>> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) &&
>> (Nic->Request.Value == NETWORK_CONNECTED)) {
>> + Nic->CableDetect = 1;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
>> + if (Nic->CableDetect == 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to fill the media header(s) in transmit
>> packet(s).
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiFillHeader (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_FILL_HEADER *CpbFillHeader;
>> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
>> + EthernetHeader *MacHeader;
>> + UINTN Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
>> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
>> +
>> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen <
>> PXE_MAC_HEADER_LEN_ETHER)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + MacHeader = (EthernetHeader
>> *)(UINTN)CpbFill->FragDesc[0].FragAddr;
>> + MacHeader->Protocol = CpbFill->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
>> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
>> + }
>> + } else {
>> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
>> +
>> + MacHeader = (EthernetHeader
>> *)(UINTN)CpbFillHeader->MediaHeader;
>> + MacHeader->Protocol = CpbFillHeader->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
>> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Transmit command is used to place a packet into the transmit
>> queue.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + return;
>> + }
>> +
>> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +}
>> +
>> +/**
>> + Use USB Ethernet Protocol Bulk out command to transmit data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface
>> controller data.
>> + @param[in] CpbAddr Command Parameter Block Address.
>> + @param[in] OpFlags Operation Flags.
>> +
>> +**/
>> +UINT16
>> +Transmit (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN UINT16 OpFlags
>> + )
>> +{
>> + EFI_STATUS Status;
>> + PXE_CPB_TRANSMIT *Cpb;
>> + UINT64 BulkOutData;
>> + UINTN DataLength;
>> + UINTN TransmitLength;
>> + UINTN Map;
>> + UINT32 Counter;
>> + UINT16 StatCode;
>> +
>> + BulkOutData = 0;
>> + Counter = 0;
>> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
>> +
>> + if (Nic->CanTransmit) {
>> + return PXE_STATCODE_BUSY;
>> + }
>> +
>> + Nic->CanTransmit = TRUE;
>> +
>> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + Map = MapIt (
>> + Nic,
>> + Cpb->FrameAddr,
>> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
>> + TO_DEVICE,
>> + (UINT64)(UINTN)&BulkOutData
>> + );
>> +
>> + if (Map != 0) {
>> + Nic->CanTransmit = FALSE;
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
>> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
>> + Nic->TxBufferCount++;
>> + }
>> +
>> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
>> +
>> + while (1) {
>> + if (Counter >= 3) {
>> + StatCode = PXE_STATCODE_BUSY;
>> + break;
>> + }
>> +
>> + TransmitLength = DataLength;
>> +
>> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID
>> *)(UINTN)BulkOutData, &TransmitLength);
>> + if (EFI_ERROR (Status)) {
>> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if (Status == EFI_INVALID_PARAMETER) {
>> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
>> + break;
>> + }
>> +
>> + if (Status == EFI_DEVICE_ERROR) {
>> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
>> + break;
>> + }
>> +
>> + if (!EFI_ERROR (Status)) {
>> + Nic->TxFrame++;
>> + StatCode = PXE_STATCODE_SUCCESS;
>> + break;
>> + }
>> +
>> + Counter++;
>> + }
>> +
>> + UnMapIt (
>> + Nic,
>> + Cpb->FrameAddr,
>> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
>> + TO_DEVICE,
>> + BulkOutData
>> + );
>> +
>> + Nic->CanTransmit = FALSE;
>> +
>> + return StatCode;
>> +}
>> +
>> +/**
>> + When the network adapter has received a frame, this command is used
>> + to copy the frame into driver/application storage.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + return;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +}
>> +
>> +/**
>> + Use USB Ethernet Protocol Bulk in command to receive data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface
>> controller data.
>> + @param[in] CpbAddr Command Parameter Block Address.
>> + @param[in, out] DbAddr Data Block Address.
>> +
>> +**/
>> +UINT16
>> +Receive (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN OUT UINT64 DbAddr
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + PXE_FRAME_TYPE FrameType;
>> + PXE_CPB_RECEIVE *Cpb;
>> + PXE_DB_RECEIVE *Db;
>> + NIC_DEVICE *NicDevice;
>> + UINT8 *BulkInData;
>> + UINTN DataLength;
>> + EthernetHeader *Header;
>> + EFI_TPL OriginalTpl;
>> +
>> + FrameType = PXE_FRAME_TYPE_NONE;
>> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
>> + BulkInData = NicDevice->ReceiveBuffer;
>> + DataLength = (UINTN)Nic->MaxSegmentSize;
>> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
>> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
>> +
>> + if (!BulkInData) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if ((Nic->RateLimitingCreditCount == 0) &&
>> (Nic->RateLimitingEnable == TRUE)) {
>> + return PXE_STATCODE_NO_DATA;
>> + }
>> +
>> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID
>> *)BulkInData, &DataLength);
>> + if (EFI_ERROR (Status)) {
>> + Nic->ReceiveStatus = 0;
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
>> + if (Nic->RateLimitingCreditCount != 0) {
>> + Nic->RateLimitingCreditCount--;
>> + }
>> +
>> + gBS->RestoreTPL (OriginalTpl);
>> + }
>> +
>> + return PXE_STATCODE_NO_DATA;
>> + }
>> +
>> + Nic->RxFrame++;
>> +
>> + if (DataLength != 0) {
>> + if (DataLength > Cpb->BufferLen) {
>> + DataLength = (UINTN)Cpb->BufferLen;
>> + }
>> +
>> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData,
>> DataLength);
>> +
>> + Header = (EthernetHeader *)BulkInData;
>> +
>> + Db->FrameLen = (UINT32)DataLength;
>> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
>> + break;
>> + }
>> + }
>> +
>> + if (Index >= PXE_HWADDR_LEN_ETHER) {
>> + FrameType = PXE_FRAME_TYPE_UNICAST;
>> + } else {
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + if (Header->DestAddr[Index] !=
>> Nic->BroadcastNodeAddress[Index]) {
>> + break;
>> + }
>> + }
>> +
>> + if (Index >= PXE_HWADDR_LEN_ETHER) {
>> + FrameType = PXE_FRAME_TYPE_BROADCAST;
>> + } else {
>> + if ((Header->DestAddr[0] & 1) == 1) {
>> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
>> + } else {
>> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
>> + }
>> + }
>> + }
>> +
>> + Db->Type = FrameType;
>> + Db->Protocol = Header->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
>> + Db->DestAddr[Index] = Header->DestAddr[Index];
>> + }
>> + }
>> +
>> + if (FrameType == PXE_FRAME_TYPE_NONE) {
>> + Nic->ReceiveStatus = 0;
>> + } else {
>> + Nic->ReceiveStatus = 1;
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Fill out PXE SW UNDI structure.
>> +
>> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
>> +
>> +**/
>> +VOID
>> +PxeStructInit (
>> + OUT PXE_SW_UNDI *PxeSw
>> + )
>> +{
>> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
>> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
>> + PxeSw->Fudge = 0;
>> + PxeSw->IFcnt = 0;
>> + PxeSw->IFcntExt = 0;
>> + PxeSw->Rev = PXE_ROMID_REV;
>> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
>> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
>> + PxeSw->reserved1 = 0;
>> +
>> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
>> + PXE_ROMID_IMP_FRAG_SUPPORTED |
>> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
>> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
>> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
>> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
>> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
>> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
>> +
>> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
>> + PxeSw->reserved2[0] = 0;
>> + PxeSw->reserved2[1] = 0;
>> + PxeSw->reserved2[2] = 0;
>> + PxeSw->BusCnt = 1;
>> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
>> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw,
>> PxeSw->Len);
>> +}
>> +
>> +/**
>> + Update NIC number.
>> +
>> + @param[in] Nic A pointer to the Network interface
>> controller data.
>> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
>> +
>> +**/
>> +VOID
>> +UpdateNicNum (
>> + IN NIC_DATA *Nic,
>> + IN OUT PXE_SW_UNDI *PxeSw
>> + )
>> +{
>> + UINT16 NicNum;
>> +
>> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
>> +
>> + if (Nic == NULL) {
>> + if (NicNum > 0) {
>> + NicNum--;
>> + }
>> +
>> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
>> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper
>> byte
>> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID
>> *)PxeSw, PxeSw->Len));
>> + return;
>> + }
>> +
>> + NicNum++;
>> +
>> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
>> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
>> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID
>> *)PxeSw, PxeSw->Len));
>> +}
>> +
>> +/**
>> + UNDI API table entry.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UndiApiEntry (
>> + IN UINT64 Cdb
>> + )
>> +{
>> + PXE_CDB *CdbPtr;
>> + NIC_DATA *Nic;
>> +
>> + if (Cdb == 0) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
>> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
>> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Map virtual memory address for DMA. This field can be set to
>> + zero if there is no mapping service.
>> +
>> + @param[in] Nic A pointer to the Network interface
>> controller data.
>> + @param[in] MemAddr Virtual address to be mapped.
>> + @param[in] Size Size of memory to be mapped.
>> + @param[in] Direction Direction of data flow for this memory's
>> usage:
>> + cpu->device, device->cpu or both ways.
>> + @param[out] MappedAddr Pointer to return the mapped device
>> address.
>> +
>> +**/
>> +UINTN
>> +MapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + OUT UINT64 MappedAddr
>> + )
>> +{
>> + UINT64 *PhyAddr;
>> +
>> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
>> +
>> + if (Nic->PxeStart.Map_Mem == 0) {
>> + *PhyAddr = MemAddr;
>> + } else {
>> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN)
>> Nic->PxeStart.Map_Mem)(
>> + Nic->PxeStart.Unique_ID,
>> + MemAddr,
>> + Size,
>> + Direction,
>> + MappedAddr
>> + );
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Un-map previously mapped virtual memory address. This field can be
>> set
>> + to zero only if the Map_Mem() service is also set to zero.
>> +
>> + @param[in] Nic A pointer to the Network interface
>> controller data.
>> + @param[in] MemAddr Virtual address to be mapped.
>> + @param[in] Size Size of memory to be mapped.
>> + @param[in] Direction Direction of data flow for this memory's
>> usage:
>> + cpu->device, device->cpu or both ways.
>> + @param[in] MappedAddr Pointer to return the mapped device
>> address.
>> +
>> +**/
>> +VOID
>> +UnMapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + IN UINT64 MappedAddr
>> + )
>> +{
>> + if (Nic->PxeStart.UnMap_Mem != 0) {
>> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN)
>> Nic->PxeStart.UnMap_Mem)(
>> + Nic->PxeStart.Unique_ID,
>> + MemAddr,
>> + Size,
>> + Direction,
>> + MappedAddr
>> + );
>> + }
>> +
>> + return;
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c
>> b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> new file mode 100644
>> index 000000000000..b9ba170c135b
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> @@ -0,0 +1,172 @@
>> +/** @file
>> + This file contains code for USB RNDIS Driver Component
>> + Name definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
>> gUsbRndisDriverNameTable[] = {
>> + {
>> + "eng;en",
>> + L"USB RNDIS Driver"
>> + },
>> + {
>> + NULL,
>> + NULL
>> + }
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL
>> gUsbRndisComponentName = {
>> + UsbRndisComponentNameGetDriverName,
>> + UsbRndisComponentNameGetControllerName,
>> + "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL
>> gUsbRndisComponentName2 = {
>> +
>> (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
>> +
>> (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
>> + "en"
>> +};
>> +
>> +/**
>> + 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[in] This A pointer to the
>> EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Language 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[out] DriverName 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
>> +UsbRndisComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + )
>> +{
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gUsbRndisDriverNameTable,
>> + DriverName,
>> + (BOOLEAN)(This == &gUsbRndisComponentName)
>> + );
>> +}
>> +
>> +/**
>> + 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[in] This A pointer to the
>> EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid
>> EFI_HANDLE.
>> + @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
>> +UsbRndisComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + )
>> +{
>> + return EFI_UNSUPPORTED;
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> new file mode 100644
>> index 000000000000..92830771e408
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> @@ -0,0 +1,886 @@
>> +/** @file
>> + This file contains code for USB Remote Network Driver
>> + Interface Spec. Driver Binding
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
>> + UsbRndisDriverSupported,
>> + UsbRndisDriverStart,
>> + UsbRndisDriverStop,
>> + USB_RNDIS_DRIVER_VERSION,
>> + NULL,
>> + NULL
>> +};
>> +
>> +/**
>> + Check if this interface is USB Rndis SubType
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis SubType.
>> + @retval FALSE Not USB Rndis SubType.
>> +
>> +**/
>> +BOOLEAN
>> +IsSupportedDevice (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
>> &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check specific device/RNDIS and CDC-DATA
>> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
>> + )
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if this interface is USB Rndis SubType but not CDC Data
>> interface
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis SubType.
>> + @retval FALSE Not USB Rndis SubType.
>> +**/
>> +BOOLEAN
>> +IsRndisInterface (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
>> &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for specific device/RNDIS and CDC-DATA
>> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
>> + )
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if the USB RNDIS and USB CDC Data interfaces are from the
>> same device.
>> +
>> + @param[in] UsbRndisDataPath A pointer to the
>> EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] UsbCdcDataPath A pointer to the
>> EFI_DEVICE_PATH_PROTOCOL instance.
>> +
>> + @retval EFI_SUCCESS Is the same device.
>> + @retval EFI_UNSUPPORTED Is not the same device.
>> +
>> +**/
>> +EFI_STATUS
>> +IsSameDevice (
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
>> + )
>> +{
>> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
>> + while (1) {
>> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
>> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
>> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
>> + {
>> + return EFI_SUCCESS;
>> + } else {
>> + return EFI_UNSUPPORTED;
>> + }
>> + } else {
>> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof
>> (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
>> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
>> + }
>> + }
>> +
>> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
>> +}
>> +
>> +/**
>> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data
>> Handle.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB CDC Data(UsbIo) installed.
>> + @retval FALSE USB CDC Data(UsbIo) did not installed.
>> +
>> +**/
>> +BOOLEAN
>> +IsUsbCdcData (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
>> &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for CDC-DATA
>> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if the USB Rndis(UsbIo) installed
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL
>> instance.
>> +
>> + @retval TRUE USB Rndis(UsbIo) installed.
>> + @retval FALSE USB Rndis(UsbIo) did not installed.
>> +
>> +**/
>> +BOOLEAN
>> +IsUsbRndis (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
>> &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for Rndis
>> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Control comes here when a CDC device is found.Check if a RNDIS
>> interface is already found for this device or not.
>> + For one device two USBIO will be installed each for CDC and RNDIS
>> interface.
>> +
>> + @param[in] UsbEthPath A pointer to the
>> EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
>> +
>> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this
>> CDC Data is found.
>> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this
>> CDC Data is not found.
>> +
>> +**/
>> +EFI_STATUS
>> +UpdateRndisDevice (
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
>> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + BOOLEAN IsRndisInterfaceFlag;
>> +
>> + IsRndisInterfaceFlag = FALSE;
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEdkIIUsbEthProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEthDevice
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
>> + if (IsRndisInterfaceFlag == FALSE) {
>> + continue;
>> + }
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> +
>> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>> +
>> + if (!EFI_ERROR (Status)) {
>> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>> + FreePool (HandleBuffer);
>> + return EFI_SUCCESS;
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> +
>> + For the given Rndis Device, find a matching CDC device already
>> exists or not. If found update the handle
>> + and UsbIO protocol.
>> +
>> + @param[in] UsbRndisDevice A pointer to the
>> USB_RNDIS_DEVICE data.
>> +
>> +**/
>> +VOID
>> +FindMatchingCdcData (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = gBS->HandleProtocol (
>> + UsbRndisDevice->UsbRndisHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + return;
>> + }
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEfiUsbIoProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + if (IsUsbCdcData (UsbIo)) {
>> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData
>> interface found\n"));
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbCdcDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not
>> found\n"));
>> + FreePool (HandleBuffer);
>> + return;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>> + if (!EFI_ERROR (Status)) {
>> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
>> + UsbRndisDevice->UsbIoCdcData = UsbIo;
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + FreePool (HandleBuffer);
>> + return;
>> + }
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> +}
>> +
>> +/**
>> +
>> + For the given UsbIo CdcData, find a matching RNDIS device already
>> exists or not.
>> +
>> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB
>> CDC Data.
>> + @param[out] CdcUsbIo A pointer for retrieve the
>> EFI_USB_IO_PROTOCOL instance.
>> + @param[out] RndisHandle A pointer for retrieve the handle of
>> RNDIS device.
>> +
>> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this
>> CDC Data is found.
>> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this
>> CDC Data is not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FindMatchingRndisDev (
>> + IN EFI_HANDLE CdcHandle,
>> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
>> + OUT EFI_HANDLE *RndisHandle
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = gBS->HandleProtocol (
>> + CdcHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbCdcDataPath
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEfiUsbIoProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if (IsUsbRndis (UsbIo)) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
>> + break;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + *RndisHandle = HandleBuffer[Index];
>> + *CdcUsbIo = UsbIo;
>> + FreePool (HandleBuffer);
>> + return Status;
>> + }
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> + USB Rndis Driver Binding Support.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to test.
>> + @param[in] 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
>> +UsbRndisDriverSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + USB RNDIS Driver Binding Start.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind
>> driver to.
>> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install
>> successfully due to a lack of resources.
>> + @retval other This driver does not support
>> this device
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
>> + EFI_HANDLE RndisHandle;
>> +
>> + RndisHandle = ControllerHandle;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbEthPath,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + // Controls come here for RNDIS and CDC. If it is CDC, check
>> whether RNDIS is present on the same controller or not.
>> + if (IsUsbCdcData (UsbIo)) {
>> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = UpdateRndisDevice (
>> + UsbEthPath,
>> + &UsbRndisDevice
>> + );
>> +
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
>> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
>> + UsbRndisDevice->UsbIoCdcData = UsbIo;
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + return Status;
>> + } else {
>> + // Check if RnDis exist
>> + Status = FindMatchingRndisDev (
>> + ControllerHandle,
>> + &UsbIo,
>> + &RndisHandle
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> + }
>> + }
>> +
>> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
>> +
>> + if (!UsbRndisDevice) {
>> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + Status = LoadAllDescriptor (
>> + UsbIo,
>> + &UsbRndisDevice->Config
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n",
>> __FUNCTION__, Status));
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (
>> + UsbIo,
>> + &Interface
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =
>> %r\n", __FUNCTION__, Status));
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + UsbRndisDevice->Signature =
>> USB_RNDIS_SIGNATURE;
>> + UsbRndisDevice->NumOfInterface =
>> Interface.InterfaceNumber;
>> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
>> + UsbRndisDevice->UsbCdcDataHandle = 0;
>> + UsbRndisDevice->UsbIo = UsbIo;
>> + UsbRndisDevice->UsbEth.UsbEthReceive =
>> RndisUndiReceive;
>> + UsbRndisDevice->UsbEth.UsbEthTransmit =
>> RndisUndiTransmit;
>> + UsbRndisDevice->UsbEth.UsbEthInterrupt =
>> UsbRndisInterrupt;
>> + UsbRndisDevice->UsbEth.UsbEthMacAddress =
>> GetUsbEthMacAddress;
>> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
>> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor =
>> GetUsbHeaderFunDescriptor;
>> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor =
>> GetUsbUnionFunDescriptor;
>> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor =
>> GetUsbRndisFunDescriptor;
>> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter =
>> SetUsbRndisMcastFilter;
>> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter =
>> SetUsbRndisPowerFilter;
>> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter =
>> GetUsbRndisPowerFilter;
>> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter =
>> SetUsbRndisPacketFilter;
>> + UsbRndisDevice->UsbEth.GetUsbEthStatistic =
>> GetRndisStatistic;
>> +
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState =
>> RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart =
>> RndisUndiStart;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop =
>> RndisUndiStop;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo =
>> RndisUndiGetInitInfo;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo =
>> RndisUndiGetConfigInfo;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize =
>> RndisUndiInitialize;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset =
>> RndisUndiReset;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown =
>> RndisUndiShutdown;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable =
>> RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter =
>> RndisUndiReceiveFilter;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress =
>> RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac =
>> RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData =
>> RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus =
>> RndisUndiGetStatus;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader =
>> RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
>> +
>> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
>> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
>> + UsbRndisDevice->PacketAlignmentFactor = 0;
>> +
>> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
>> +
>> + // This is a RNDIS interface. See whether CDC-DATA interface has
>> already been connected or not
>> + FindMatchingCdcData (UsbRndisDevice);
>> +
>> + if (UsbRndisDevice->UsbIoCdcData) {
>> + Status = gBS->InstallProtocolInterface (
>> + &ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + EFI_NATIVE_INTERFACE,
>> + &(UsbRndisDevice->UsbEth)
>> + );
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
>> +
>> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n",
>> UsbRndisDevice->UsbRndisHandle));
>> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n",
>> UsbRndisDevice->UsbCdcDataHandle));
>> + return EFI_SUCCESS;
>> + }
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + CheckandStopRndisDevice
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> +
>> + @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
>> +CheckandStopRndisDevice (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if (IsUsbRndis (UsbIo)) {
>> + Status = gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
>> + return Status;
>> + }
>> +
>> + return EFI_UNSUPPORTED;
>> +}
>> +
>> +/**
>> + USB Rndis Driver Binding Stop.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to stop driver on
>> + @param[in] NumberOfChildren Number of Handles in
>> ChildHandleBuffer. If number of
>> + children is zero stop the entire
>> bus driver.
>> + @param[in] 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
>> +UsbRndisDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n",
>> ControllerHandle));
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEthProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + Status = CheckandStopRndisDevice (This, ControllerHandle);
>> + return Status;
>> + }
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
>> +
>> + Status = gBS->CloseProtocol (
>> + UsbRndisDevice->UsbCdcDataHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + UsbRndisDevice->UsbCdcDataHandle
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n",
>> __FUNCTION__, Status));
>> + }
>> +
>> + Status = gBS->UninstallProtocolInterface (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + UsbEthProtocol
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> +
>> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
>> + return Status;
>> +}
>> +
>> +/**
>> + Entrypoint of RNDIS Driver.
>> +
>> + This function is the entrypoint of RNDIS Driver. It installs
>> Driver Binding
>> + Protocols together with Component Name Protocols.
>> +
>> + @param[in] ImageHandle The firmware allocated handle for
>> the EFI image.
>> + @param[in] SystemTable A pointer to the EFI System Table.
>> +
>> + @retval EFI_SUCCESS The entry point is executed
>> successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisEntry (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
>> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
>> +
>> + return gBS->InstallMultipleProtocolInterfaces (
>> + &gUsbRndisDriverBinding.DriverBindingHandle,
>> + &gEfiDriverBindingProtocolGuid,
>> + &gUsbRndisDriverBinding,
>> + &gEfiComponentName2ProtocolGuid,
>> + &gUsbRndisComponentName2,
>> + NULL
>> + );
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> new file mode 100644
>> index 000000000000..e3fe737cdef1
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> @@ -0,0 +1,1718 @@
>> +/** @file
>> + This file contains code for USB Ethernet descriptor
>> + and specific requests implement.
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All
>> rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +UINT16 gStopBulkInCnt = 0;
>> +UINT16 gBlockBulkInCnt = 0;
>> +
>> +/**
>> + Load All of device descriptor.
>> +
>> + @param[in] UsbIo A pointer to the
>> EFI_USB_IO_PROTOCOL instance.
>> + @param[out] ConfigDesc A pointer to the configuration
>> descriptor.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be completed
>> because the
>> + buffer specified by DescriptorLength
>> and Descriptor
>> + is not large enough to hold the
>> result of the request.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error. The transfer
>> + status is returned in Status.
>> +**/
>> +EFI_STATUS
>> +LoadAllDescriptor (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 TransStatus;
>> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
>> +
>> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n",
>> __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = gBS->AllocatePool (
>> + EfiBootServicesData,
>> + Tmp.TotalLength,
>> + (VOID **)ConfigDesc
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n",
>> __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = UsbGetDescriptor (
>> + UsbIo,
>> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue -
>> 1), // zero based
>> + 0,
>> + Tmp.TotalLength,
>> + *ConfigDesc,
>> + &TransStatus
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Returns pointer to the next descriptor for the pack of USB
>> descriptors
>> + located in continues memory segment
>> +
>> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
>> + @param[in, out] Offset A pointer to the sum of descriptor length.
>> +
>> + @retval TRUE The request executed successfully.
>> + @retval FALSE No next descriptor.
>> +
>> +**/
>> +BOOLEAN
>> +NextDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
>> + IN OUT UINTN *Offset
>> + )
>> +{
>> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
>> + return FALSE;
>> + }
>> +
>> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length
>> == 0) {
>> + return FALSE;
>> + }
>> +
>> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char
>> *)Desc+*Offset))->Length;
>> + if ( *Offset >= Desc->TotalLength ) {
>> + return FALSE;
>> + }
>> +
>> + return TRUE;
>> +}
>> +
>> +/**
>> + Read Function descriptor
>> +
>> + @param[in] Config A pointer to all of configuration.
>> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
>> + @param[out] DataBuffer A pointer to the Data of
>> corresponding to device capability.
>> +
>> + @retval EFI_SUCCESS The device capability descriptor was
>> retrieved
>> + successfully.
>> + @retval EFI_UNSUPPORTED No supported.
>> + @retval EFI_NOT_FOUND The device capability descriptor was
>> not found.
>> +
>> +**/
>> +EFI_STATUS
>> +GetFunctionalDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
>> + IN UINT8 FunDescriptorType,
>> + OUT VOID *DataBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Offset;
>> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
>> +
>> + Status = EFI_NOT_FOUND;
>> +
>> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
>> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config +
>> Offset);
>> + if (Interface->DescriptorType == CS_INTERFACE) {
>> + if (((USB_HEADER_FUN_DESCRIPTOR
>> *)Interface)->DescriptorSubtype == FunDescriptorType) {
>> + switch (FunDescriptorType) {
>> + case HEADER_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
>> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
>> + );
>> + return EFI_SUCCESS;
>> + case UNION_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
>> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
>> + );
>> + return EFI_SUCCESS;
>> + case ETHERNET_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
>> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
>> + );
>> + return EFI_SUCCESS;
>> + default:
>> + Status = EFI_UNSUPPORTED;
>> + break;
>> + }
>> + }
>> + }
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
>> +
>> + @param[in] UsbIo A pointer to the
>> EFI_USB_IO_PROTOCOL instance.
>> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
>> instance.
>> +
>> +**/
>> +VOID
>> +GetEndpoint (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 Index;
>> + UINT32 Result;
>> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
>> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =
>> %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + if (Interface.NumEndpoints == 0 ) {
>> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n",
>> __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =
>> %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> + }
>> +
>> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
>> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status =
>> %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
>> + case USB_ENDPOINT_BULK:
>> + if (Endpoint.EndpointAddress & BIT7) {
>> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
>> + } else {
>> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
>> + }
>> +
>> + break;
>> + case USB_ENDPOINT_INTERRUPT:
>> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
>> + break;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Async USB transfer callback routine.
>> +
>> + @param[in] Data Data received or sent via the USB
>> Asynchronous Transfer, if the
>> + transfer completed successfully.
>> + @param[in] DataLength The length of Data received or sent
>> via the Asynchronous
>> + Transfer, if transfer successfully
>> completes.
>> + @param[in] Context Data passed from
>> UsbAsyncInterruptTransfer() request.
>> + @param[in] Status Indicates the result of the
>> asynchronous transfer.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer
>> request has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer
>> request failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +InterruptCallback (
>> + IN VOID *Data,
>> + IN UINTN DataLength,
>> + IN VOID *Context,
>> + IN UINT32 Status
>> + )
>> +{
>> + if ((Data == NULL) || (Context == NULL)) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
>> + CopyMem (
>> + (EFI_USB_DEVICE_REQUEST *)Context,
>> + (EFI_USB_DEVICE_REQUEST *)Data,
>> + sizeof (EFI_USB_DEVICE_REQUEST)
>> + );
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is used to manage a USB device with an interrupt
>> transfer pipe.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] IsNewTransfer If TRUE, a new transfer will be
>> submitted to USB controller. If
>> + FALSE, the interrupt transfer is
>> deleted from the device's interrupt
>> + transfer queue.
>> + @param[in] PollingInterval Indicates the periodic rate, in
>> milliseconds, that the transfer is to be
>> + executed.This parameter is required
>> when IsNewTransfer is TRUE. The
>> + value must be between 1 to 255,
>> otherwise EFI_INVALID_PARAMETER is returned.
>> + The units are in milliseconds.
>> + @param[in] Request A pointer to the
>> EFI_USB_DEVICE_REQUEST data.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer
>> request transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer
>> request failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisInterrupt (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Requst
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + UINTN DataLength;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> + DataLength = 0;
>> +
>> + if (IsNewTransfer == TRUE) {
>> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof
>> (USB_CONNECT_SPEED_CHANGE);
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + IsNewTransfer,
>> + PollingInterval,
>> + DataLength,
>> + InterruptCallback,
>> + Requst
>> + );
>> +
>> + if (Status == EFI_INVALID_PARAMETER) {
>> + // Because of Stacked AsyncInterrupt request are not supported
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + 0,
>> + 0,
>> + 0,
>> + NULL,
>> + NULL
>> + );
>> + }
>> + } else {
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + IsNewTransfer,
>> + 0,
>> + 0,
>> + NULL,
>> + NULL
>> + );
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function is used to read USB interrupt transfer before the
>> response RNDIS message.
>> +
>> + @param[in] This A pointer to the USB_RNDIS_DEVICE
>> instance.
>> +
>> + @retval EFI_SUCCESS The USB interrupt transfer has been
>> successfully executed.
>> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ReadRndisResponseInterrupt (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 Data[2];
>> + UINT32 UsbStatus;
>> + UINTN DataLength;
>> +
>> + DataLength = 8;
>> +
>> + ZeroMem (Data, sizeof (Data));
>> +
>> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + &Data,
>> + &DataLength,
>> + 0x20,
>> + &UsbStatus
>> + );
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet Mac Address.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] MacAddress A pointer to the caller allocated USB
>> Ethernet Mac Address.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor
>> was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbEthMacAddress (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
>> + CHAR16 *Data;
>> + CHAR16 *DataPtr;
>> + CHAR16 TmpStr[1];
>> + UINT8 Index;
>> + UINT8 Hi;
>> + UINT8 Low;
>> +
>> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
>> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
>> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
>> +
>> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
>> + RndisQueryMsg.QueryMsg.MessageLength = sizeof
>> (REMOTE_NDIS_QUERY_MAC_MSG);
>> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
>> +
>> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
>> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof
>> (REMOTE_NDIS_QUERY_MAC_CMPLT);
>> +
>> + Status = RndisControlMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS
>> message.\n"));
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
>> + }
>> +
>> + UsbRndisDevice->RequestId++;
>> + return Status;
>> + }
>> +
>> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
>> + // To check USB Ethernet functional Descriptor
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n",
>> __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
>> + UsbRndisDevice->UsbIo,
>> + 0x409, // English-US Language ID
>> + UsbEthDescriptor.MacAddress,
>> + &Data
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n",
>> __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + DataPtr = Data;
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
>> + DataPtr++;
>> + Hi = (UINT8)StrHexToUintn (TmpStr);
>> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
>> + DataPtr++;
>> + Low = (UINT8)StrHexToUintn (TmpStr);
>> + MacAddress->Addr[Index] = (Hi << 4) | Low;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet Bulk transfer data size.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] BulkSize A pointer to the Bulk transfer data size.
>> +
>> + @retval EFI_SUCCESS The bulk transfer data size was
>> retrieved successfully.
>> + @retval other Failed to retrieve the bulk transfer
>> data size.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbEthBulkSize (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
>> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + ZeroMem (&RndisQueryMsg, sizeof
>> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
>> + ZeroMem (&RndisQueryMsgCmplt, sizeof
>> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
>> +
>> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
>> + RndisQueryMsg.QueryMsg.MessageLength = sizeof
>> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
>> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
>> +
>> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
>> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof
>> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
>> +
>> + Status = RndisControlMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n",
>> RndisQueryMsgCmplt.MaxTotalSize));
>> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
>> + UsbRndisDevice->RequestId++;
>> + return Status;
>> + }
>> +
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Header functional Descriptor.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbHeaderFunDescriptor A pointer to the caller
>> allocated USB Header Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor
>> was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbHeaderFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbHeaderFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + HEADER_FUN_DESCRIPTOR,
>> + UsbHeaderFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Union functional Descriptor.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbUnionFunDescriptor A pointer to the caller
>> allocated USB Union Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Union Functional descriptor
>> was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Union Functional descriptor
>> was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbUnionFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbUnionFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + UNION_FUN_DESCRIPTOR,
>> + UsbUnionFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet functional Descriptor.
>> +
>> + This function get the Mac Address, Ethernet statistics, maximum
>> segment size,
>> + number of multicast filters, and number of pattern filters from
>> Ethernet
>> + functional Descriptor.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbEthFunDescriptor A pointer to the caller
>> allocated USB Ethernet Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Ethernet Functional
>> descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Ethernet Functional
>> descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbEthFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + ETHERNET_FUN_DESCRIPTOR,
>> + UsbEthFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + This request sets the Ethernet device multicast filters as
>> specified in the
>> + sequential list of 48 bit Ethernet multicast addresses.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] McastAddr A pointer to the value of the
>> multicast addresses.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an
>> invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisMcastFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
>> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = Value * 6;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + McastAddr,
>> + Request.Length,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> + This request sets up the specified Ethernet power management
>> pattern filter as
>> + described in the data structure.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] Length Size of the power management
>> pattern filter data.
>> + @param[in] PatternFilter A pointer to the power
>> management pattern filter structure.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an
>> invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + )
>> +{
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
>> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = Length;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + PatternFilter,
>> + Length,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> + This request retrieves the status of the specified Ethernet power
>> management
>> + pattern filter from the device.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value The filter number.
>> + @param[out] PatternActive A pointer to the pattern active
>> boolean.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an
>> invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + OUT BOOLEAN *PatternActive
>> + )
>> +{
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
>> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataIn,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + PatternActive,
>> + USB_ETH_POWER_FILTER_LENGTH,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> +
>> + Converts PXE filter settings to RNDIS values
>> +
>> + @param[in] Value PXE filter data.
>> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter
>> Bitmap value converted by PXE_OPFLAGS.
>> +
>> +**/
>> +VOID
>> +ConvertFilter (
>> + IN UINT16 Value,
>> + OUT UINT16 *CdcFilter
>> + )
>> +{
>> + UINT32 Index;
>> + UINT32 Count;
>> + static struct BIT_MAP Table[] = {
>> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST,
>> NDIS_PACKET_TYPE_DIRECTED },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST,
>> NDIS_PACKET_TYPE_BROADCAST },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST,
>> NDIS_PACKET_TYPE_MULTICAST },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS,
>> NDIS_PACKET_TYPE_PROMISCUOUS },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST,
>> NDIS_PACKET_TYPE_ALL_MULTICAST },
>> + };
>> +
>> + Count = sizeof (Table)/sizeof (Table[0]);
>> +
>> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count);
>> Index++) {
>> + if (Table[Index].Src & Value) {
>> + *CdcFilter |= Table[Index].Dst;
>> + }
>> + }
>> +}
>> +
>> +/**
>> +
>> + Updates Filter settings on the device.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_STATUS
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 *McastList;
>> + UINT8 Count;
>> + UINT8 Index1;
>> + UINT8 Index2;
>> + UINT64 CpbAddr;
>> + UINT32 CpbSize;
>> + UINT16 SetFilter;
>> + PXE_CPB_RECEIVE_FILTERS *Cpb;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> +
>> + Count = 0;
>> + CpbAddr = Cdb->CPBaddr;
>> + CpbSize = Cdb->CPBsize;
>> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
>> +
>> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
>> + Nic->RxFilter = (UINT8)SetFilter;
>> +
>> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST)
>> != 0) || (Cpb != NULL)) {
>> + if (Cpb != NULL) {
>> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
>> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
>> + } else {
>> + Nic->McastCount = 0;
>> + }
>> +
>> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth,
>> &UsbEthFunDescriptor);
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
>> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth
>> %lx ", Nic, Nic->UsbEth));
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + } else {
>> + Status = gBS->AllocatePool (EfiBootServicesData,
>> Nic->McastCount * 6, (VOID **)&McastList);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Cpb != NULL) {
>> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
>> + for (Index2 = 0; Index2 < 6; Index2++) {
>> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
>> + }
>> + }
>> + }
>> +
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
>> + if (Cpb != NULL) {
>> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth,
>> Nic->McastCount, McastList);
>> + }
>> +
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + FreePool (McastList);
>> + }
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This request is used to configure device Ethernet packet filter
>> settings.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Packet Filter Bitmap.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPacketFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + )
>> +{
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This request is used to retrieve a statistic based on the feature
>> selector.
>> +
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] FeatureSelector Value of the feature selector.
>> + @param[out] Statistic A pointer to the 32 bit unsigned
>> integer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the
>> request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
>> value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetRndisStatistic (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 FeatureSelector,
>> + OUT VOID *Statistic
>> + )
>> +{
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiStart is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State
>> %x\n", Nic, Cdb, Nic->State));
>> +
>> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED
>> state
>> + Status = RndisUndiReset (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + RndisUndiReset (Cdb, Nic);
>> + }
>> +
>> + Status = RndisUndiInitialize (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + RndisUndiInitialize (Cdb, Nic);
>> + }
>> +
>> + RndisUndiShutdown (Cdb, Nic);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when Undistop is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiGetInitInfo is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + PXE_DB_GET_INIT_INFO *Db;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
>> +
>> + UsbEthDevice = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>> +
>> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof
>> (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
>> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
>> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
>> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when RndisUndiGetConfigInfo is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiInitialize is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
>> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
>> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
>> +
>> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
>> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
>> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
>> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
>> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
>> +
>> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
>> + RndisInitMsgCmplt.MessageLength = sizeof
>> (REMOTE_NDIS_INITIALIZE_CMPLT);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER
>> *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
>> +
>> + UsbRndisDevice->RequestId++;
>> +
>> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
>> + return Status;
>> + }
>> +
>> + // Only Wired Medium is supported
>> + if (RndisInitMsgCmplt.Medium) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
>> + UsbRndisDevice->MaxPacketsPerTransfer =
>> RndisInitMsgCmplt.MaxPacketsPerTransfer;
>> + UsbRndisDevice->MaxTransferSize =
>> RndisInitMsgCmplt.MaxTransferSize;
>> + UsbRndisDevice->PacketAlignmentFactor =
>> RndisInitMsgCmplt.PacketAlignmentFactor;
>> +
>> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
>> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n",
>> RndisInitMsgCmplt.MaxPacketsPerTransfer));
>> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n",
>> RndisInitMsgCmplt.MaxTransferSize));
>> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n",
>> RndisInitMsgCmplt.PacketAlignmentFactor));
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function is called when UndiReset is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device
>> error.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
>> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
>> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
>> +
>> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
>> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
>> +
>> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
>> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER
>> *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
>> +
>> + UsbRndisDevice->RequestId = 1; // Let's start with 1
>> +
>> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiShutdown is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
>> +
>> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
>> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER
>> *)&RndisHltMsg, NULL);
>> +
>> + if (Status == EFI_DEVICE_ERROR) {
>> + Status = EFI_SUCCESS;
>> + }
>> +
>> + UsbRndisDevice->RequestId = 1;
>> + return Status;
>> +}
>> +
>> +/**
>> + Update the Media connection.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Transmit the data after appending RNDIS header.
>> +
>> + @param[in] Cdb A pointer to the command descriptor
>> block.
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] BulkOutData A pointer to the buffer of data that
>> will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] DataLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN VOID *BulkOutData,
>> + IN OUT UINTN *DataLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
>> + UINTN TransferLength;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n",
>> *DataLength));
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG)
>> + *DataLength);
>> + if (RndisPacketMsg == NULL) {
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
>> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) +
>> (UINT32)*DataLength;
>> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
>> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
>> +
>> + CopyMem (
>> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
>> + BulkOutData,
>> + *DataLength
>> + );
>> +
>> + TransferLength = RndisPacketMsg->MessageLength;
>> +
>> + Status = RndisTransmitDataMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
>> + &TransferLength
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n",
>> TransferLength));
>> +
>> + FreePool (RndisPacketMsg);
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Receives and removes RNDIS header and returns the raw data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor
>> block.
>> + @param[in] This A pointer to the
>> EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] BulkInData A pointer to the buffer of data that
>> will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] DataLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
>> + @retval EFI_NOT_FOUND No buffer was found in the list.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *BulkInData,
>> + IN OUT UINTN *DataLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
>> + UINTN TransferLength;
>> + VOID *Buffer;
>> + PACKET_LIST *HeadPacket;
>> + PACKET_LIST *PacketList;
>> +
>> + // Check if there is any outstanding packet to receive
>> + // The buffer allocated has a linked List followed by the packet.
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> + Buffer = NULL;
>> + HeadPacket = NULL;
>> +
>> + while (1) {
>> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof
>> (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
>> + if (Buffer == NULL) {
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG
>> *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
>> + PacketList = (PACKET_LIST *)Buffer;
>> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof
>> (PACKET_LIST);
>> + // Save the original address for freeing it up
>> + PacketList->OrgBuffer = (UINT8 *)Buffer;
>> + TransferLength = UsbRndisDevice->MaxTransferSize;
>> +
>> + Status = RndisReceiveDataMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
>> + &TransferLength
>> + );
>> +
>> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
>> + FreePool (Buffer);
>> + break;
>> + }
>> +
>> + // Collect all the RNDIS packet in Linked list.
>> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> + (RndisPacketMsg->DataOffset == sizeof
>> (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
>> + (TransferLength >= RndisPacketMsg->MessageLength))
>> + {
>> + // Insert Packet
>> + PacketList->RemainingLength = TransferLength;
>> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
>> + } else {
>> + FreePool (Buffer);
>> + }
>> + }
>> +
>> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
>> + HeadPacket = (PACKET_LIST *)GetFirstNode
>> (&UsbRndisDevice->ReceivePacketList);
>> +
>> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8
>> *)HeadPacket->PacketStartBuffer;
>> +
>> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
>> +
>> + // Check whether the packet is valid RNDIS packet.
>> + if ((HeadPacket->RemainingLength > sizeof
>> (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType ==
>> RNDIS_PACKET_MSG) &&
>> + (RndisPacketMsg->DataOffset == (sizeof
>> (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
>> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
>> + {
>> + if (*DataLength >= RndisPacketMsg->DataLength) {
>> + CopyMem (
>> + BulkInData,
>> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset +
>> RNDIS_RESERVED_BYTE_LENGTH),
>> + RndisPacketMsg->DataLength
>> + );
>> +
>> + *DataLength = RndisPacketMsg->DataLength;
>> +
>> + HeadPacket->RemainingLength = HeadPacket->RemainingLength
>> - RndisPacketMsg->MessageLength;
>> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg +
>> RndisPacketMsg->MessageLength;
>> +
>> + return EFI_SUCCESS;
>> + } else {
>> + *DataLength = RndisPacketMsg->DataLength;
>> + return EFI_BUFFER_TOO_SMALL;
>> + }
>> + }
>> +
>> + RemoveEntryList (&HeadPacket->PacketList);
>> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
>> + }
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> + This is a dummy function which just returns. Unimplemented
>> EDKII_USB_ETHERNET_PROTOCOL functions
>> + point to this function.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisDummyReturn (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's control
>> endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
>> instance.
>> + @param[in] RndisMsg A pointer to the
>> REMOTE_NDIS_MSG_HEADER data.
>> + @param[out] RndisMsgResponse A pointer to the
>> REMOTE_NDIS_MSG_HEADER data for getting responses.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been
>> successfully executed.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisControlMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
>> + )
>> +{
>> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
>> + EFI_USB_DEVICE_REQUEST DevReq;
>> + UINT32 UsbStatus;
>> + EFI_STATUS Status;
>> + UINT32 SaveResponseType;
>> + UINT32 SaveResponseLength;
>> + UINT32 Index;
>> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
>> +
>> + SaveResponseType = 0;
>> + SaveResponseLength = 0;
>> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT
>> *)RndisMsgResponse;
>> +
>> + if (RndisMsgResponse) {
>> + SaveResponseType = RndisMsgResponse->MessageType;
>> + SaveResponseLength = RndisMsgResponse->MessageLength;
>> + }
>> +
>> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
>> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
>> + DevReq.Value = 0;
>> + DevReq.Index = 0;
>> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + Status = UsbIo->UsbControlTransfer (
>> + UsbIo,
>> + &DevReq,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + RndisMsg,
>> + RndisMsg->MessageLength,
>> + &UsbStatus
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r
>> RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
>> +
>> + // Error or no response expected
>> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status :
>> %r\n", UsbStatus, Status));
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
>> + ReadRndisResponseInterrupt (UsbRndisDevice);
>> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS |
>> USB_TARGET_INTERFACE;
>> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
>> + DevReq.Value = 0;
>> + DevReq.Index = 0;
>> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
>> +
>> + Status = UsbIo->UsbControlTransfer (
>> + UsbIo,
>> + &DevReq,
>> + EfiUsbDataIn,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + RndisMsgResponse,
>> + RndisMsgResponse->MessageLength,
>> + &UsbStatus
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x
>> Status : %r \n", UsbStatus, Status));
>> +
>> + PrintRndisMsg (RndisMsgResponse);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + if ((RndisInitCmplt->RequestID !=
>> ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) ||
>> (RndisInitCmplt->MessageType != SaveResponseType)) {
>> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
>> +
>> + RndisMsgResponse->MessageType = SaveResponseType;
>> + RndisMsgResponse->MessageLength = SaveResponseLength;
>> + continue;
>> + }
>> + }
>> +
>> + return Status;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
>> +
>> + return EFI_TIMEOUT;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's Data
>> endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
>> instance.
>> + @param[in] RndisMsg A pointer to the
>> REMOTE_NDIS_MSG_HEADER to send out.
>> + @param[in, out] TransferLength The length of the RndisMsg data to
>> transfer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisTransmitDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + IN OUT UINTN *TransferLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 UsbStatus;
>> +
>> + if (UsbRndisDevice->BulkInEndpoint == 0) {
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + }
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>> + UsbRndisDevice->UsbIoCdcData,
>> + UsbRndisDevice->BulkOutEndpoint,
>> + RndisMsg,
>> + TransferLength,
>> + USB_TX_ETHERNET_BULK_TIMEOUT,
>> + &UsbStatus
>> + );
>> +
>> + if (Status == EFI_SUCCESS) {
>> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending
>> cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's Data
>> endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the
>> USB_RNDIS_DEVICE instance.
>> + @param[in, out] RndisMsg A pointer to the
>> REMOTE_NDIS_MSG_HEADER to send out.
>> + @param[in, out] TransferLength The length of the RndisMsg data
>> to transfer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisReceiveDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + IN OUT UINTN *TransferLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 UsbStatus;
>> +
>> + UsbStatus = 0;
>> +
>> + if (UsbRndisDevice->BulkInEndpoint == 0) {
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + }
>> +
>> + // Use gStopBulkInCnt to stop BulkIn command
>> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
>> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>> + UsbRndisDevice->UsbIoCdcData,
>> + UsbRndisDevice->BulkInEndpoint,
>> + RndisMsg,
>> + TransferLength,
>> + USB_RX_ETHERNET_BULK_TIMEOUT,
>> + &UsbStatus
>> + );
>> +
>> + if (!EFI_ERROR (Status)) {
>> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>> + } else {
>> + gStopBulkInCnt--;
>> + }
>> + } else {
>> + Status = EFI_TIMEOUT;
>> + *TransferLength = 0;
>> + gBlockBulkInCnt++;
>> + }
>> +
>> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
>> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>> + gBlockBulkInCnt = 0;
>> + }
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Prints RNDIS Header and Data
>> +
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
>> +
>> +**/
>> +VOID
>> +PrintRndisMsg (
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
>> + )
>> +{
>> + UINTN Length;
>> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
>> +
>> + Length = 0;
>> +
>> + switch (RndisMsg->MessageType) {
>> + case RNDIS_PACKET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
>> + break;
>> + case RNDIS_INITIALIZE_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
>> + break;
>> + case RNDIS_INITIALIZE_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
>> + break;
>> + case RNDIS_HLT_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
>> + break;
>> + case RNDIS_QUERY_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
>> + break;
>> + case RNDIS_QUERY_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
>> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
>> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) +
>> RndisQueryCmplt->InformationBufferLength;
>> + break;
>> + case RNDIS_SET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_SET_MSG);
>> + break;
>> + case RNDIS_SET_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
>> + break;
>> + case RNDIS_RESET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
>> + break;
>> + case RNDIS_RESET_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
>> + break;
>> + case RNDIS_INDICATE_STATUS_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
>> + break;
>> + case RNDIS_KEEPALIVE_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
>> + break;
>> + case RNDIS_KEEPALIVE_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
>> + }
>> +
>> + if (Length) {
>> + UINTN Index = 0;
>> + for ( ; Length; Length -= 4, Index++) {
>> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
>> + if (((Index % 4) == 3) && (Index != 0)) {
>> + DEBUG ((DEBUG_INFO, "\n"));
>> + }
>> +
>> + if ((Length < 8) && (Length > 4)) {
>> + UINT32 Data32;
>> + Index++;
>> + Data32 = *((UINT32 *)RndisMsg + Index);
>> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
>> + break;
>> + }
>> + }
>> +
>> + if (Index % 4) {
>> + DEBUG ((DEBUG_INFO, "\n"));
>> + }
>> + }
>> +}
>> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
>> new file mode 100644
>> index 000000000000..cb70684f0bf1
>> --- /dev/null
>> +++ b/UsbNetworkPkg/ReadMe.md
>> @@ -0,0 +1,65 @@
>> +# UsbNetworkPkg
>> +
>> +This document is intend to provide package information, include the
>> interface details.
>> +
>> +# INDEX
>> + * [Introduction](#introduction)
>> + * [Components](#components)
>> + * [[NetworkCommon]](#networkcommon)
>> + * [[UsbCdcEcm]](#usbcdcecm)
>> + * [[UsbCdcNcm]](#usbcdcncm)
>> + * [[UsbRndis]](#usbrndis)
>> +
>> +# Introduction
>> +UsbNetworkPkg provides network functions for USB LAN devices.
>> +
>> +# Components
>> +Below module is included in this package:<br>
>> +- NetworkCommon
>> +- UsbCdcEcm
>> +- UsbCdcNcm
>> +- UsbRndis
>> +
>> +## [NetworkCommon]
>> +Provides a LAN driver based on UEFI specification(UNDI). It supports
>> USB communication class subclass devices and USB Rndis devices,
>> depending on the UsbEthernetProtocol.
>> +
>> +## Required Components
>> +- NetworkPkg
>> +
>> +## [UsbCdcEcm]
>> +This driver provides a communication interface for USB Ethernet
>> devices that follows the ECM protocol. The driver installs
>> UsbEthernetProtocol with ECM functions which are consumed by the
>> NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x06|0x00|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> +## [UsbCdcNcm]
>> +This driver provides a communication interface for USB Ethernet
>> devices that follows the NCM protocol. The driver installs
>> UsbEthernetProtocol with NCM functions which are consumed by the
>> NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x0D|0x00|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> +## [UsbRndis]
>> +This driver provides a communication interface for USB Ethernet
>> devices that follows the RNDIS protocol. The driver installs
>> UsbEthernetProtocol with RNDIS functions which are consumed by the
>> NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x02|0xFF|
>> +|0xEF|0x04|0x01|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> diff --git a/UsbNetworkPkg/ReleaseNotes.md
>> b/UsbNetworkPkg/ReleaseNotes.md
>> new file mode 100644
>> index 000000000000..f8ccccdb0830
>> --- /dev/null
>> +++ b/UsbNetworkPkg/ReleaseNotes.md
>> @@ -0,0 +1,11 @@
>> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
>> +
>> +# Release History<!-- omit in toc -->
>> +- [1.00](#100)
>> +
>> +## 1.00
>> +
>> +**Release Date:** Mar 10, 2022
>> +
>> +**New Features**
>> +- UsbNetworkPkg first release.
>> --
>> 2.35.1.windows.2
>> -The information contained in this message may be confidential and
>> proprietary to American Megatrends (AMI). This communication is
>> intended to be read only by the individual or entity to whom it is
>> addressed or by their designee. If the reader of this message is not
>> the intended recipient, you are on notice that any distribution of
>> this message, in any form, is strictly prohibited. Please promptly
>> notify the sender by reply e-mail or by telephone at 770-246-8600,
>> and then delete or destroy all copies of the transmission.
>
>
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-03-09 7:51 [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
` (2 preceding siblings ...)
2023-03-27 14:59 ` [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS " Tinh Nguyen
@ 2023-03-28 11:40 ` Rebecca Cran
2023-03-29 2:11 ` RichardHo [何明忠]
2023-04-07 1:57 ` Rebecca Cran
4 siblings, 1 reply; 11+ messages in thread
From: Rebecca Cran @ 2023-03-28 11:40 UTC (permalink / raw)
To: Richard Ho (何明忠), devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Tinh Nguyen,
Tony Lo (羅金松)
The include files should have the suffix ".dsc.inc" or ".fdf.inc", not
".inc.dsc" and ".inc.fdf".
How are the include files expected to be used?
I've tried including them in OvmfPkg/OvmfPkgX64.dsc and
OvmfPkg/OvmfPkgX64.fdf but am having trouble figuring out where in those
files the various lines should be located.
--
Rebecca Cran
On 3/9/23 12:51 AM, Richard Ho (何明忠) wrote:
> This driver provides UEFI driver for USB RNDIS device
>
> Signed-off-by: Richard Ho <richardho@ami.com>
> Cc: Andrew Fish <afish@apple.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
> Reviewed-by: Tony Lo <tonylo@ami.com>
> ---
> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
> UsbNetworkPkg/ReadMe.md | 65 +
> UsbNetworkPkg/ReleaseNotes.md | 11 +
> 18 files changed, 7452 insertions(+)
> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> create mode 100644 UsbNetworkPkg/ReadMe.md
> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>
> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
> new file mode 100644
> index 000000000000..30e4e4c8aac7
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
> @@ -0,0 +1,46 @@
> +## @file
> +# This package defines Usb network specific interfaces and library classes
> +# as well as configuration for standard edk2 packages.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x00010005
> + PACKAGE_NAME = UsbNetworkPkg
> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
> + PACKAGE_VERSION = 0.1
> +
> +[Includes]
> + Include
> +
> +[Protocols]
> + ## Include/Protocol/EdkIIUsbEthernet.h
> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
> +
> +[Guids]
> + ## Usb Network package token space GUID
> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
> +
> +[PcdsFeatureFlag]
> +
> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
> +
> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
> +
> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
> +
> +[PcdsFixedAtBuild, PcdsPatchableInModule]
> + ## Support rate limiting
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
> +
> + ## The rate limiting Credit value is check in rate limiter event.
> + # It is to control the RateLimitingCreditCount max value.
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
> +
> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> new file mode 100644
> index 000000000000..a3316b1d4a89
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> @@ -0,0 +1,9 @@
> +## @file
> +# Global DSC definitions to be included into project DSC file.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Components.X64]
> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> new file mode 100644
> index 000000000000..544df8404c64
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> new file mode 100644
> index 000000000000..85a309bcf567
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> @@ -0,0 +1,23 @@
> +## @file
> +# Global switches enable/disable project features.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
> + DEFINE PEI=IA32
> + DEFINE DXE=X64
> +!else
> + DEFINE PEI=COMMON
> + DEFINE DXE=COMMON
> +!endif
> +
> +[Packages]
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[PcdsFeatureFlag]
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> new file mode 100644
> index 000000000000..10616d97edb4
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> new file mode 100644
> index 000000000000..8923102bc350
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> @@ -0,0 +1,49 @@
> +## @file
> +# This is Usb Network Common driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = NetworkCommon
> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = NetworkCommonEntry
> +
> +[Sources]
> + DriverBinding.c
> + DriverBinding.h
> + ComponentName.c
> + PxeFunction.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Pcd]
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> new file mode 100644
> index 000000000000..64205e427745
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# This is Usb Rndis driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = UsbRndis
> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = UsbRndisEntry
> +
> +[Sources]
> + UsbRndis.c
> + UsbRndis.h
> + UsbRndisFunction.c
> + ComponentName.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> new file mode 100644
> index 000000000000..f54946c7aa69
> --- /dev/null
> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> @@ -0,0 +1,878 @@
> +/** @file
> + Header file contains code for USB Ethernet Protocol
> + definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
> +
> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
> +
> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
> +
> +#define USB_CDC_CLASS 0x02
> +#define USB_CDC_ACM_SUBCLASS 0x02
> +#define USB_CDC_ECM_SUBCLASS 0x06
> +#define USB_CDC_NCM_SUBCLASS 0x0D
> +#define USB_CDC_DATA_CLASS 0x0A
> +#define USB_CDC_DATA_SUBCLASS 0x00
> +#define USB_NO_CLASS_PROTOCOL 0x00
> +#define USB_NCM_NTB_PROTOCOL 0x01
> +#define USB_VENDOR_PROTOCOL 0xFF
> +
> +// Type Values for the DescriptorType Field
> +#define CS_INTERFACE 0x24
> +#define CS_ENDPOINT 0x25
> +
> +// Descriptor SubType in Functional Descriptors
> +#define HEADER_FUN_DESCRIPTOR 0x00
> +#define UNION_FUN_DESCRIPTOR 0x06
> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
> +
> +#define MAX_LAN_INTERFACE 0x10
> +
> +// Table 20: Class-Specific Notification Codes
> +#define USB_CDC_NETWORK_CONNECTION 0x00
> +
> +// 6.3.1 NetworkConnection
> +#define NETWORK_CONNECTED 0x01
> +#define NETWORK_DISCONNECT 0x00
> +
> +// USB Header functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT16 BcdCdc;
> +} USB_HEADER_FUN_DESCRIPTOR;
> +
> +// USB Union Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MasterInterface;
> + UINT8 SlaveInterface;
> +} USB_UNION_FUN_DESCRIPTOR;
> +
> +// USB Ethernet Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MacAddress;
> + UINT32 EthernetStatistics;
> + UINT16 MaxSegmentSize;
> + UINT16 NumberMcFilters;
> + UINT8 NumberPowerFilters;
> +} USB_ETHERNET_FUN_DESCRIPTOR;
> +
> +typedef struct {
> + UINT32 UsBitRate;
> + UINT32 DsBitRate;
> +} USB_CONNECT_SPEED_CHANGE;
> +
> +// Request Type Codes for USB Ethernet
> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
> +
> +// Class-Specific Request Codes for Ethernet subclass
> +// USB ECM 1.2 specification, Section 6.2
> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
> +#define SET_ETH_PACKET_FILTER_REQ 0x43
> +#define GET_ETH_STATISTIC_REQ 0x44
> +
> +// USB ECM command request length
> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
> +
> +// USB Ethernet Packet Filter Bitmap
> +// USB ECM 1.2 specification, Section 6.2.4
> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
> +
> +// USB Ethernet Statistics Feature Selector Codes
> +// USB ECM 1.2 specification, Section 6.2.5
> +#define USB_ETH_XMIT_OK 0x01
> +#define USB_ETH_RCV_OK 0x02
> +#define USB_ETH_XMIT_ERROR 0x03
> +#define USB_ETH_RCV_ERROR 0x04
> +#define USB_ETH_RCV_NO_BUFFER 0x05
> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
> +#define USB_ETH_RCV_CRC_ERROR 0x12
> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
> +#define USB_ETH_XMIT_DEFERRED 0x17
> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
> +#define USB_ETH_RCV_OVERRUN 0x19
> +#define USB_ETH_XMIT_UNDERRUN 0x1A
> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
> +
> +// NIC Information
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + UINT16 InterrupOpFlag;
> + UINT64 MappedAddr;
> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
> + UINT8 McastCount;
> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
> + UINT8 TxBufferCount;
> + UINT16 State;
> + BOOLEAN CanTransmit;
> + UINT16 ReceiveStatus;
> + UINT8 RxFilter;
> + UINT32 RxFrame;
> + UINT32 TxFrame;
> + UINT16 NetworkConnect;
> + UINT8 CableDetect;
> + UINT16 MaxSegmentSize;
> + EFI_MAC_ADDRESS MacAddr;
> + PXE_CPB_START_31 PxeStart;
> + PXE_CPB_INITIALIZE PxeInit;
> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
> + EFI_USB_DEVICE_REQUEST Request;
> + EFI_EVENT RateLimiter;
> + UINT32 RateLimitingCredit;
> + UINT32 RateLimitingCreditCount;
> + UINT32 RateLimitingPollTimer;
> + BOOLEAN RateLimitingEnable;
> +} NIC_DATA;
> +
> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Request
> + );
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + );
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + );
> +
> +typedef struct {
> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
> +} EDKII_USB_ETHERNET_UNDI;
> +
> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
> +// descriptor and specific requests.
> +struct _EDKII_USB_ETHERNET_PROTOCOL {
> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
> + // for calling the UNDI child functions
> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
> +};
> +
> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> new file mode 100644
> index 000000000000..0416ce132302
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> @@ -0,0 +1,266 @@
> +/** @file
> + Header file for for USB network common driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _DRIVER_BINDING_H_
> +#define _DRIVER_BINDING_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/NetworkInterfaceIdentifier.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +#define NETWORK_COMMON_DRIVER_VERSION 1
> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
> +#define RX_BUFFER_COUNT 32
> +#define TX_BUFFER_COUNT 32
> +#define MEMORY_REQUIRE 0
> +
> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
> + UINT16 Protocol;
> +} EthernetHeader;
> +#pragma pack()
> +
> +typedef struct {
> + UINTN Signature;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
> + EFI_HANDLE DeviceHandle;
> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + NIC_DATA NicInfo;
> + VOID *ReceiveBuffer;
> +} NIC_DEVICE;
> +
> +typedef VOID (*API_FUNC)(
> + PXE_CDB *,
> + NIC_DATA *
> + );
> +
> +extern PXE_SW_UNDI *gPxe;
> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + );
> +
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + );
> +
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + );
> +
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + );
> +
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + );
> +
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + );
> +
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +#endif
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> new file mode 100644
> index 000000000000..775807042460
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> @@ -0,0 +1,586 @@
> +/** @file
> + Header file for for USB Rndis driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _USB_RNDIS_H_
> +#define _USB_RNDIS_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
> + EFI_HANDLE UsbCdcDataHandle;
> + EFI_HANDLE UsbRndisHandle;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
> + EFI_USB_CONFIG_DESCRIPTOR *Config;
> + UINT8 NumOfInterface;
> + UINT8 BulkInEndpoint;
> + UINT8 BulkOutEndpoint;
> + UINT8 InterrupEndpoint;
> + EFI_MAC_ADDRESS MacAddress;
> + UINT32 RequestId;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + LIST_ENTRY ReceivePacketList;
> +} USB_RNDIS_DEVICE;
> +
> +#define USB_RNDIS_DRIVER_VERSION 1
> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
> +
> +#define LAN_BULKIN_CMD_CONTROL 1
> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
> +#define RNDIS_RESERVED_BYTE_LENGTH 8
> +
> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
> +
> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
> +
> +struct BIT_MAP {
> + unsigned int Src;
> + unsigned int Dst;
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + );
> +
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + );
> +
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + );
> +
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN BOOLEAN *PatternActive
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *Statistic
> + );
> +
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + );
> +
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + );
> +
> +#define RNDIS_MAJOR_VERSION 0x00000001
> +#define RNDIS_MINOR_VERSION 0x00000000
> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
> +
> +#define RNDIS_PACKET_MSG 0x00000001
> +#define RNDIS_INITIALIZE_MSG 0x00000002
> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
> +#define RNDIS_HLT_MSG 0x00000003
> +#define RNDIS_QUERY_MSG 0x00000004
> +#define RNDIS_QUERY_CMPLT 0x80000004
> +#define RNDIS_SET_MSG 0x00000005
> +#define RNDIS_SET_CMPLT 0x80000005
> +#define RNDIS_RESET_MSG 0x00000006
> +#define RNDIS_RESET_CMPLT 0x80000006
> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
> +#define RNDIS_KEEPALIVE_MSG 0x00000008
> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
> +
> +#define RNDIS_STATUS_SUCCESS 0x00000000
> +#define RNDIS_STATUS_FAILURE 0xC0000001
> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
> +
> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
> +
> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
> +
> +//
> +// General Objects
> +//
> +// Taken from NTDDNDIS.H
> +#define OID_GEN_SUPPORTED_LIST 0x00010101
> +#define OID_GEN_HARDWARE_STATUS 0x00010102
> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
> +#define OID_GEN_MEDIA_IN_USE 0x00010104
> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
> +#define OID_GEN_LINK_SPEED 0x00010107
> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
> +#define OID_GEN_VENDOR_ID 0x0001010C
> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
> +#define OID_GEN_DRIVER_VERSION 0x00010110
> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
> +#define OID_GEN_MAC_OPTIONS 0x00010113
> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
> +
> +#define OID_GEN_XMIT_OK 0x00020101
> +#define OID_GEN_RCV_OK 0x00020102
> +#define OID_GEN_XMIT_ERROR 0x00020103
> +#define OID_GEN_RCV_ERROR 0x00020104
> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
> +
> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
> +
> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
> +//
> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
> +//
> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
> +#define NDIS_PACKET_TYPE_SMT 0x0040
> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
> +#define NDIS_PACKET_TYPE_GROUP 0x1000
> +
> +#pragma pack(1)
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> +} REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 MaxTransferSize;
> +} REMOTE_NDIS_INITIALIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_HALT_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_QUERY_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_SET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Reserved;
> +} REMOTE_NDIS_RESET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 StatusBufferLength;
> + UINT32 StatusBufferOffset;
> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
> +
> +typedef struct {
> + UINT32 DiagStatus;
> + UINT32 ErrorOffset;
> +} RNDIS_DIAGNOSTIC_INFO;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_KEEPALIVE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 DeviceFlags;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + UINT64 Reserved;
> +} REMOTE_NDIS_INITIALIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> +} REMOTE_NDIS_QUERY_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_SET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 AddressingReset;
> +} REMOTE_NDIS_RESET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 DataOffset;
> + UINT32 DataLength;
> + UINT32 OutOfBandDataOffset;
> + UINT32 OutOfBandDataLength;
> + UINT32 NumOutOfBandDataElements;
> + UINT32 PerPacketInfoOffset;
> + UINT32 PerPacketInfoLength;
> + UINT32 Reserved1;
> + UINT32 Reserved2;
> +} REMOTE_NDIS_PACKET_MSG;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} OUT_OF_BAND_DATA_RECORD;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} PER_PACKET_INFO_DATA_RECORD;
> +
> +typedef struct {
> + LIST_ENTRY PacketList;
> + UINT8 *OrgBuffer;
> + UINTN RemainingLength;
> + UINT8 *PacketStartBuffer; // Variable size data to follow
> +} PACKET_LIST;
> +
> +#pragma pack()
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> new file mode 100644
> index 000000000000..e83469e13079
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> @@ -0,0 +1,263 @@
> +/** @file
> + This file contains code for USB network common driver
> + component name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
> + {
> + "eng;en",
> + L"Network Common Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
> + NetworkCommonComponentNameGetDriverName,
> + NetworkCommonComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> + CHAR16 *HandleName;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
> +
> + if (!Language || !ControllerName) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (ChildHandle == NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Make sure this driver is currently managing ControllerHandle
> + //
> + Status = EfiTestManagedDevice (
> + Controller,
> + gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Make sure this driver produced ChildHandle
> + //
> + Status = EfiTestChildHandle (
> + Controller,
> + ChildHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
> +
> + if (!EFI_ERROR (Status)) {
> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *ControllerName = HandleName;
> +
> + if (gNetworkCommonControllerNameTable != NULL) {
> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
> + gNetworkCommonControllerNameTable = NULL;
> + }
> +
> + Status = AddUnicodeString2 (
> + "eng",
> + gNetworkCommonComponentName.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + TRUE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = AddUnicodeString2 (
> + "en",
> + gNetworkCommonComponentName2.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + FALSE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> new file mode 100644
> index 000000000000..23b791362091
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> @@ -0,0 +1,595 @@
> +/** @file
> + This file contains code for USB network binding driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +PXE_SW_UNDI *gPxe = NULL;
> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +UINT32 gRateLimitingCredit;
> +UINT32 gRateLimitingPollTimer;
> +BOOLEAN gRateLimitingEnable;
> +
> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
> + NetworkCommonSupported,
> + NetworkCommonDriverStart,
> + NetworkCommonDriverStop,
> + NETWORK_COMMON_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Create MAC Device Path
> +
> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
> + @retval EFI_SUCCESS MAC device path created successfully.
> +
> +**/
> +EFI_STATUS
> +CreateMacDevicePath (
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + MAC_ADDR_DEVICE_PATH MacAddrNode;
> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
> + UINT8 *DevicePath;
> + UINT16 TotalLength;
> + UINT16 BaseLength;
> +
> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
> +
> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
> + MacAddrNode.Header.Length[1] = 0;
> +
> + EndNode = BaseDev;
> +
> + while (!IsDevicePathEnd (EndNode)) {
> + EndNode = NextDevicePathNode (EndNode);
> + }
> +
> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
> + DevicePath += BaseLength;
> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
> + DevicePath += sizeof (MacAddrNode);
> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Network Common Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + EFI_MAC_ADDRESS MacAddress;
> + UINTN BulkDataSize;
> + NIC_DEVICE *NicDevice;
> + UINT8 *TmpPxePointer;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
> +
> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
> + ASSERT_EFI_ERROR (Status);
> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
> + if (!NicDevice) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + // for alignment adjustment
> + if (gPxe == NULL) {
> + TmpPxePointer = NULL;
> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
> + if (!TmpPxePointer) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + return EFI_OUT_OF_RESOURCES;
> + } else {
> + // check for paragraph alignment here
> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
> + } else {
> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
> + }
> +
> + if (!gPxe) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PxeStructInit (gPxe);
> + }
> + }
> +
> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
> +
> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
> +
> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
> +
> + NicDevice->NicInfo.UsbEth = UsbEth;
> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
> + NicDevice->NicInfo.CableDetect = 0;
> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
> +
> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
> +
> + NicDevice->NicInfo.TxBufferCount = 0;
> +
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
> + } else {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = CreateMacDevicePath (
> + &NicDevice->DevPath,
> + UsbEthPath,
> + &NicDevice->NicInfo
> + );
> +
> + if (EFI_ERROR (Status)) {
> + UpdateNicNum (NULL, gPxe);
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> + }
> +
> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
> + NicDevice->NiiProtocol.ImageSize = 0;
> + NicDevice->NiiProtocol.ImageAddr = 0;
> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
> +
> + NicDevice->NiiProtocol.StringId[0] = 'U';
> + NicDevice->NiiProtocol.StringId[1] = 'N';
> + NicDevice->NiiProtocol.StringId[2] = 'D';
> + NicDevice->NiiProtocol.StringId[3] = 'I';
> + NicDevice->DeviceHandle = NULL;
> +
> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
> + NicDevice->NicInfo.RateLimiter = NULL;
> +
> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &NicDevice->DeviceHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice->DevPath != NULL) {
> + FreePool (NicDevice->DevPath);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + NicDevice->DeviceHandle,
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AllChildrenStopped;
> + UINTN Index;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + NIC_DEVICE *NicDevice;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
> +
> + if (NumberOfChildren == 0) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + AllChildrenStopped = TRUE;
> +
> + for (Index = 0; Index < NumberOfChildren; Index++) {
> + Status = gBS->OpenProtocol (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + AllChildrenStopped = FALSE;
> + continue;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index]
> + );
> +
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index],
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> + } else {
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> + }
> + }
> +
> + if (!AllChildrenStopped) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Entrypoint of Network Common Driver.
> +
> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gNetworkCommonDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gNetworkCommonComponentName2,
> + NULL
> + );
> + return Status;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> new file mode 100644
> index 000000000000..687cabca4ce3
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> @@ -0,0 +1,1803 @@
> +/** @file
> + This file contains code for UNDI command based on UEFI specification.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +// API table, defined in UEFI specification
> +API_FUNC gUndiApiTable[] = {
> + UndiGetState,
> + UndiStart,
> + UndiStop,
> + UndiGetInitInfo,
> + UndiGetConfigInfo,
> + UndiInitialize,
> + UndiReset,
> + UndiShutdown,
> + UndiInterruptEnable,
> + UndiReceiveFilter,
> + UndiStationAddress,
> + UndiStatistics,
> + UndiMcastIp2Mac,
> + UndiNvData,
> + UndiGetStatus,
> + UndiFillHeader,
> + UndiTransmit,
> + UndiReceive
> +};
> +
> +/**
> + Callback function for enable Rate Limiter
> +
> + @param[in] Event Event whose notification function is being invoked
> + @param[in] Context Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +UndiRateLimiterCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + NIC_DATA *Nic = Context;
> +
> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
> + Nic->RateLimitingCreditCount++;
> + }
> +}
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_START_31 *Cpb;
> + EFI_STATUS Status;
> + BOOLEAN EventError;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
> +
> + Nic->PxeStart.Delay = Cpb->Delay;
> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
> + Nic->PxeStart.Block = Cpb->Block;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
> + EventError = FALSE;
> + Status = EFI_SUCCESS;
> + if (Nic->RateLimitingEnable == TRUE) {
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + UndiRateLimiterCallback,
> + Nic,
> + &Nic->RateLimiter
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = gBS->SetTimer (
> + Nic->RateLimiter,
> + TimerPeriodic,
> + Nic->RateLimitingPollTimer * 10000
> + );
> + if (EFI_ERROR (Status)) {
> + EventError = TRUE;
> + }
> + }
> + }
> +
> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + // Initial the state for UNDI start.
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + } else {
> + if (Nic->RateLimitingEnable == TRUE) {
> + if (!EventError) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + }
> +
> + if (Nic->RateLimiter) {
> + gBS->CloseEvent (&Nic->RateLimiter);
> + Nic->RateLimiter = 0;
> + }
> + }
> +
> + // Initial the state when UNDI start is fail
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
> + return;
> + }
> +
> + Nic->PxeStart.Delay = 0;
> + Nic->PxeStart.Virt2Phys = 0;
> + Nic->PxeStart.Block = 0;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = 0;
> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
> +
> + if (Nic->RateLimitingEnable == TRUE) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + gBS->CloseEvent (&Nic->RateLimiter);
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_INIT_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->MemoryRequired = MEMORY_REQUIRE;
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + Db->LinkSpeeds[0] = 10;
> + Db->LinkSpeeds[1] = 100;
> + Db->LinkSpeeds[2] = 1000;
> + Db->LinkSpeeds[3] = 0;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> + Db->IFtype = PXE_IFTYPE_ETHERNET;
> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
> +
> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_CONFIG_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->pci.BusType = PXE_BUSTYPE_USB;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_INITIALIZE *Cpb;
> + PXE_DB_INITIALIZE *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
> +
> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
> +
> + Cdb->StatCode = Initialize (Cdb, Nic);
> +
> + Db->MemoryUsed = MEMORY_REQUIRE;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> +
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + Nic->CanTransmit = FALSE;
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
> + }
> + }
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Initialize Network interface controller data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval Status A value of Pxe statcode.
> +
> +**/
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + UINTN Status;
> + UINT32 Index;
> + EFI_STATUS EfiStatus;
> +
> + Status = MapIt (
> + Nic,
> + Nic->PxeInit.MemoryAddr,
> + Nic->PxeInit.MemoryLength,
> + TO_AND_FROM_DEVICE,
> + (UINT64)(UINTN)&Nic->MappedAddr
> + );
> +
> + if (Status != 0) {
> + return (UINT16)Status;
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->BroadcastNodeAddress[Index] = 0xFF;
> + }
> +
> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = 0;
> + Nic->PermNodeAddress[Index] = 0;
> + Nic->BroadcastNodeAddress[Index] = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
> + if (EFI_ERROR (EfiStatus)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return (UINT16)Status;
> +}
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
> + Nic->InterrupOpFlag = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Nic->CanTransmit = FALSE;
> +
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + UINT16 NewFilter;
> + PXE_DB_RECEIVE_FILTERS *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> +
> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
> + if ((Cdb->DBsize != 0)) {
> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
> + }
> + }
> +
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
> + if (NewFilter == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Cdb->CPBsize != 0) {
> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if ((Cdb->CPBsize == 0)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + break;
> +
> + default:
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Set PXE receive filter.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] SetFilter PXE receive filter
> + @param[in] CpbAddr Command Parameter Block Address
> + @param[in] CpbSize Command Parameter Block Size
> +
> +**/
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_STATION_ADDRESS *Cpb;
> + PXE_DB_STATION_ADDRESS *Db;
> + UINT16 Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> + }
> +
> + if (Cdb->CPBaddr != 0) {
> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
> + }
> + }
> +
> + if (Cdb->DBaddr != 0) {
> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Return data for DB data.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> +**/
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + )
> +{
> + PXE_DB_STATISTICS *DbStatistic;
> + EFI_STATUS Status;
> +
> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
> +
> + if (DbSize == 0) {
> + return PXE_STATCODE_SUCCESS;
> + }
> +
> + DbStatistic->Supported = 0x802;
> + DbStatistic->Data[0x01] = Nic->RxFrame;
> + DbStatistic->Data[0x0B] = Nic->TxFrame;
> +
> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in, out] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
> + PXE_DB_MCAST_IP_TO_MAC *Db;
> + UINT8 *Tmp;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + return;
> + }
> +
> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
> +
> + if ((Tmp[0] & 0xF0) != 0xE0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
> + }
> +
> + Db->MAC[0] = 0x01;
> + Db->MAC[1] = 0x00;
> + Db->MAC[2] = 0x5E;
> + Db->MAC[3] = Tmp[1] & 0x7F;
> + Db->MAC[4] = Tmp[2];
> + Db->MAC[5] = Tmp[3];
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_STATUS *Db;
> + PXE_DB_GET_STATUS TmpGetStatus;
> + UINT16 NumEntries;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + TmpGetStatus.RxFrameLen = 0;
> + TmpGetStatus.reserved = 0;
> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
> + } else {
> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
> + if (Cdb->DBsize == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + NumEntries = Cdb->DBsize - sizeof (UINT64);
> + Cdb->DBsize = sizeof (UINT32) * 2;
> +
> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
> + if (Nic->TxBufferCount > 0) {
> + Nic->TxBufferCount--;
> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
> + }
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
> + if (Nic->ReceiveStatus != 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
> + }
> + }
> +
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_FILL_HEADER *CpbFillHeader;
> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
> + EthernetHeader *MacHeader;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
> +
> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
> + MacHeader->Protocol = CpbFill->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
> + }
> + } else {
> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
> + MacHeader->Protocol = CpbFillHeader->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk out command to transmit data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in] OpFlags Operation Flags.
> +
> +**/
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + )
> +{
> + EFI_STATUS Status;
> + PXE_CPB_TRANSMIT *Cpb;
> + UINT64 BulkOutData;
> + UINTN DataLength;
> + UINTN TransmitLength;
> + UINTN Map;
> + UINT32 Counter;
> + UINT16 StatCode;
> +
> + BulkOutData = 0;
> + Counter = 0;
> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
> +
> + if (Nic->CanTransmit) {
> + return PXE_STATCODE_BUSY;
> + }
> +
> + Nic->CanTransmit = TRUE;
> +
> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + Map = MapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + (UINT64)(UINTN)&BulkOutData
> + );
> +
> + if (Map != 0) {
> + Nic->CanTransmit = FALSE;
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
> + Nic->TxBufferCount++;
> + }
> +
> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
> +
> + while (1) {
> + if (Counter >= 3) {
> + StatCode = PXE_STATCODE_BUSY;
> + break;
> + }
> +
> + TransmitLength = DataLength;
> +
> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
> + if (EFI_ERROR (Status)) {
> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
> + break;
> + }
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + break;
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + Nic->TxFrame++;
> + StatCode = PXE_STATCODE_SUCCESS;
> + break;
> + }
> +
> + Counter++;
> + }
> +
> + UnMapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + BulkOutData
> + );
> +
> + Nic->CanTransmit = FALSE;
> +
> + return StatCode;
> +}
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk in command to receive data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in, out] DbAddr Data Block Address.
> +
> +**/
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + PXE_FRAME_TYPE FrameType;
> + PXE_CPB_RECEIVE *Cpb;
> + PXE_DB_RECEIVE *Db;
> + NIC_DEVICE *NicDevice;
> + UINT8 *BulkInData;
> + UINTN DataLength;
> + EthernetHeader *Header;
> + EFI_TPL OriginalTpl;
> +
> + FrameType = PXE_FRAME_TYPE_NONE;
> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
> + BulkInData = NicDevice->ReceiveBuffer;
> + DataLength = (UINTN)Nic->MaxSegmentSize;
> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
> +
> + if (!BulkInData) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
> + if (EFI_ERROR (Status)) {
> + Nic->ReceiveStatus = 0;
> + if (Nic->RateLimitingEnable == TRUE) {
> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + if (Nic->RateLimitingCreditCount != 0) {
> + Nic->RateLimitingCreditCount--;
> + }
> +
> + gBS->RestoreTPL (OriginalTpl);
> + }
> +
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Nic->RxFrame++;
> +
> + if (DataLength != 0) {
> + if (DataLength > Cpb->BufferLen) {
> + DataLength = (UINTN)Cpb->BufferLen;
> + }
> +
> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
> +
> + Header = (EthernetHeader *)BulkInData;
> +
> + Db->FrameLen = (UINT32)DataLength;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_UNICAST;
> + } else {
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_BROADCAST;
> + } else {
> + if ((Header->DestAddr[0] & 1) == 1) {
> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
> + } else {
> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
> + }
> + }
> + }
> +
> + Db->Type = FrameType;
> + Db->Protocol = Header->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
> + Db->DestAddr[Index] = Header->DestAddr[Index];
> + }
> + }
> +
> + if (FrameType == PXE_FRAME_TYPE_NONE) {
> + Nic->ReceiveStatus = 0;
> + } else {
> + Nic->ReceiveStatus = 1;
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Fill out PXE SW UNDI structure.
> +
> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
> + PxeSw->Fudge = 0;
> + PxeSw->IFcnt = 0;
> + PxeSw->IFcntExt = 0;
> + PxeSw->Rev = PXE_ROMID_REV;
> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
> + PxeSw->reserved1 = 0;
> +
> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
> + PXE_ROMID_IMP_FRAG_SUPPORTED |
> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
> +
> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
> + PxeSw->reserved2[0] = 0;
> + PxeSw->reserved2[1] = 0;
> + PxeSw->reserved2[2] = 0;
> + PxeSw->BusCnt = 1;
> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
> +}
> +
> +/**
> + Update NIC number.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + UINT16 NicNum;
> +
> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
> +
> + if (Nic == NULL) {
> + if (NicNum > 0) {
> + NicNum--;
> + }
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> + return;
> + }
> +
> + NicNum++;
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> +}
> +
> +/**
> + UNDI API table entry.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + )
> +{
> + PXE_CDB *CdbPtr;
> + NIC_DATA *Nic;
> +
> + if (Cdb == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Map virtual memory address for DMA. This field can be set to
> + zero if there is no mapping service.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[out] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + )
> +{
> + UINT64 *PhyAddr;
> +
> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
> +
> + if (Nic->PxeStart.Map_Mem == 0) {
> + *PhyAddr = MemAddr;
> + } else {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Un-map previously mapped virtual memory address. This field can be set
> + to zero only if the Map_Mem() service is also set to zero.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[in] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + )
> +{
> + if (Nic->PxeStart.UnMap_Mem != 0) {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
> new file mode 100644
> index 000000000000..b9ba170c135b
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
> @@ -0,0 +1,172 @@
> +/** @file
> + This file contains code for USB RNDIS Driver Component
> + Name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
> + {
> + "eng;en",
> + L"USB RNDIS Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
> + UsbRndisComponentNameGetDriverName,
> + UsbRndisComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gUsbRndisDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gUsbRndisComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> new file mode 100644
> index 000000000000..92830771e408
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> @@ -0,0 +1,886 @@
> +/** @file
> + This file contains code for USB Remote Network Driver
> + Interface Spec. Driver Binding
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
> + UsbRndisDriverSupported,
> + UsbRndisDriverStart,
> + UsbRndisDriverStop,
> + USB_RNDIS_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Check if this interface is USB Rndis SubType
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +
> +**/
> +BOOLEAN
> +IsSupportedDevice (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if this interface is USB Rndis SubType but not CDC Data interface
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +**/
> +BOOLEAN
> +IsRndisInterface (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
> +
> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> +
> + @retval EFI_SUCCESS Is the same device.
> + @retval EFI_UNSUPPORTED Is not the same device.
> +
> +**/
> +EFI_STATUS
> +IsSameDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
> + )
> +{
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
> + while (1) {
> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
> + {
> + return EFI_SUCCESS;
> + } else {
> + return EFI_UNSUPPORTED;
> + }
> + } else {
> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
> + }
> + }
> +
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
> +}
> +
> +/**
> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB CDC Data(UsbIo) installed.
> + @retval FALSE USB CDC Data(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbCdcData (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for CDC-DATA
> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB Rndis(UsbIo) installed
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis(UsbIo) installed.
> + @retval FALSE USB Rndis(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbRndis (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for Rndis
> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
> + For one device two USBIO will be installed each for CDC and RNDIS interface.
> +
> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +UpdateRndisDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + BOOLEAN IsRndisInterfaceFlag;
> +
> + IsRndisInterfaceFlag = FALSE;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEdkIIUsbEthProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthDevice
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
> + if (IsRndisInterfaceFlag == FALSE) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> +
> + if (!EFI_ERROR (Status)) {
> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> + FreePool (HandleBuffer);
> + return EFI_SUCCESS;
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> +
> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
> + and UsbIO protocol.
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
> +
> +**/
> +VOID
> +FindMatchingCdcData (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + UsbRndisDevice->UsbRndisHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
> + FreePool (HandleBuffer);
> + return;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> + if (!EFI_ERROR (Status)) {
> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + FreePool (HandleBuffer);
> + return;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +}
> +
> +/**
> +
> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
> +
> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FindMatchingRndisDev (
> + IN EFI_HANDLE CdcHandle,
> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
> + OUT EFI_HANDLE *RndisHandle
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + CdcHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
> + break;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + if (!EFI_ERROR (Status)) {
> + *RndisHandle = HandleBuffer[Index];
> + *CdcUsbIo = UsbIo;
> + FreePool (HandleBuffer);
> + return Status;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + USB Rndis Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + USB RNDIS Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_HANDLE RndisHandle;
> +
> + RndisHandle = ControllerHandle;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = UpdateRndisDevice (
> + UsbEthPath,
> + &UsbRndisDevice
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + return Status;
> + } else {
> + // Check if RnDis exist
> + Status = FindMatchingRndisDev (
> + ControllerHandle,
> + &UsbIo,
> + &RndisHandle
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> + }
> + }
> +
> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
> +
> + if (!UsbRndisDevice) {
> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Status = LoadAllDescriptor (
> + UsbIo,
> + &UsbRndisDevice->Config
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (
> + UsbIo,
> + &Interface
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
> + UsbRndisDevice->UsbCdcDataHandle = 0;
> + UsbRndisDevice->UsbIo = UsbIo;
> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
> +
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
> +
> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
> + UsbRndisDevice->PacketAlignmentFactor = 0;
> +
> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
> +
> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
> + FindMatchingCdcData (UsbRndisDevice);
> +
> + if (UsbRndisDevice->UsbIoCdcData) {
> + Status = gBS->InstallProtocolInterface (
> + &ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &(UsbRndisDevice->UsbEth)
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
> + return EFI_SUCCESS;
> + }
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + CheckandStopRndisDevice
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> +
> + @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
> +CheckandStopRndisDevice (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
> + return Status;
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + USB Rndis Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = CheckandStopRndisDevice (This, ControllerHandle);
> + return Status;
> + }
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
> +
> + Status = gBS->CloseProtocol (
> + UsbRndisDevice->UsbCdcDataHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + UsbRndisDevice->UsbCdcDataHandle
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
> + }
> +
> + Status = gBS->UninstallProtocolInterface (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + UsbEthProtocol
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Entrypoint of RNDIS Driver.
> +
> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
> +
> + return gBS->InstallMultipleProtocolInterfaces (
> + &gUsbRndisDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gUsbRndisDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gUsbRndisComponentName2,
> + NULL
> + );
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> new file mode 100644
> index 000000000000..e3fe737cdef1
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> @@ -0,0 +1,1718 @@
> +/** @file
> + This file contains code for USB Ethernet descriptor
> + and specific requests implement.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +UINT16 gStopBulkInCnt = 0;
> +UINT16 gBlockBulkInCnt = 0;
> +
> +/**
> + Load All of device descriptor.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[out] ConfigDesc A pointer to the configuration descriptor.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
> + buffer specified by DescriptorLength and Descriptor
> + is not large enough to hold the result of the request.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
> + status is returned in Status.
> +**/
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 TransStatus;
> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
> +
> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = gBS->AllocatePool (
> + EfiBootServicesData,
> + Tmp.TotalLength,
> + (VOID **)ConfigDesc
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbGetDescriptor (
> + UsbIo,
> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
> + 0,
> + Tmp.TotalLength,
> + *ConfigDesc,
> + &TransStatus
> + );
> + return Status;
> +}
> +
> +/**
> + Returns pointer to the next descriptor for the pack of USB descriptors
> + located in continues memory segment
> +
> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
> + @param[in, out] Offset A pointer to the sum of descriptor length.
> +
> + @retval TRUE The request executed successfully.
> + @retval FALSE No next descriptor.
> +
> +**/
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + )
> +{
> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
> + return FALSE;
> + }
> +
> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
> + return FALSE;
> + }
> +
> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
> + if ( *Offset >= Desc->TotalLength ) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Read Function descriptor
> +
> + @param[in] Config A pointer to all of configuration.
> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
> +
> + @retval EFI_SUCCESS The device capability descriptor was retrieved
> + successfully.
> + @retval EFI_UNSUPPORTED No supported.
> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Offset;
> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
> +
> + Status = EFI_NOT_FOUND;
> +
> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
> + if (Interface->DescriptorType == CS_INTERFACE) {
> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
> + switch (FunDescriptorType) {
> + case HEADER_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + case UNION_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
> + );
> + return EFI_SUCCESS;
> + case ETHERNET_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + default:
> + Status = EFI_UNSUPPORTED;
> + break;
> + }
> + }
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> +
> +**/
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Index;
> + UINT32 Result;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + if (Interface.NumEndpoints == 0 ) {
> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> + }
> +
> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
> + case USB_ENDPOINT_BULK:
> + if (Endpoint.EndpointAddress & BIT7) {
> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
> + } else {
> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
> + }
> +
> + break;
> + case USB_ENDPOINT_INTERRUPT:
> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
> + break;
> + }
> + }
> +}
> +
> +/**
> + Async USB transfer callback routine.
> +
> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
> + transfer completed successfully.
> + @param[in] DataLength The length of Data received or sent via the Asynchronous
> + Transfer, if transfer successfully completes.
> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
> + @param[in] Status Indicates the result of the asynchronous transfer.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + )
> +{
> + if ((Data == NULL) || (Context == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
> + CopyMem (
> + (EFI_USB_DEVICE_REQUEST *)Context,
> + (EFI_USB_DEVICE_REQUEST *)Data,
> + sizeof (EFI_USB_DEVICE_REQUEST)
> + );
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + UINTN DataLength;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + DataLength = 0;
> +
> + if (IsNewTransfer == TRUE) {
> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + PollingInterval,
> + DataLength,
> + InterruptCallback,
> + Requst
> + );
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + // Because of Stacked AsyncInterrupt request are not supported
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + 0,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> + } else {
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function is used to read USB interrupt transfer before the response RNDIS message.
> +
> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
> +
> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadRndisResponseInterrupt (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Data[2];
> + UINT32 UsbStatus;
> + UINTN DataLength;
> +
> + DataLength = 8;
> +
> + ZeroMem (Data, sizeof (Data));
> +
> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + &Data,
> + &DataLength,
> + 0x20,
> + &UsbStatus
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
> + CHAR16 *Data;
> + CHAR16 *DataPtr;
> + CHAR16 TmpStr[1];
> + UINT8 Index;
> + UINT8 Hi;
> + UINT8 Low;
> +
> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
> + }
> +
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
> + // To check USB Ethernet functional Descriptor
> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
> + UsbRndisDevice->UsbIo,
> + 0x409, // English-US Language ID
> + UsbEthDescriptor.MacAddress,
> + &Data
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + DataPtr = Data;
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Hi = (UINT8)StrHexToUintn (TmpStr);
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Low = (UINT8)StrHexToUintn (TmpStr);
> + MacAddress->Addr[Index] = (Hi << 4) | Low;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
> + @retval other Failed to retrieve the bulk transfer data size.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + )
> +{
> + EFI_STATUS Status;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbHeaderFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + HEADER_FUN_DESCRIPTOR,
> + UsbHeaderFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbUnionFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + UNION_FUN_DESCRIPTOR,
> + UsbUnionFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + This function get the Mac Address, Ethernet statistics, maximum segment size,
> + number of multicast filters, and number of pattern filters from Ethernet
> + functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbEthFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + ETHERNET_FUN_DESCRIPTOR,
> + UsbEthFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Value * 6;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + McastAddr,
> + Request.Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Length;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternFilter,
> + Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternActive,
> + USB_ETH_POWER_FILTER_LENGTH,
> + &TransStatus
> + );
> +}
> +
> +/**
> +
> + Converts PXE filter settings to RNDIS values
> +
> + @param[in] Value PXE filter data.
> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
> +
> +**/
> +VOID
> +ConvertFilter (
> + IN UINT16 Value,
> + OUT UINT16 *CdcFilter
> + )
> +{
> + UINT32 Index;
> + UINT32 Count;
> + static struct BIT_MAP Table[] = {
> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
> + };
> +
> + Count = sizeof (Table)/sizeof (Table[0]);
> +
> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
> + if (Table[Index].Src & Value) {
> + *CdcFilter |= Table[Index].Dst;
> + }
> + }
> +}
> +
> +/**
> +
> + Updates Filter settings on the device.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + UINT64 CpbAddr;
> + UINT32 CpbSize;
> + UINT16 SetFilter;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + CpbAddr = Cdb->CPBaddr;
> + CpbSize = Cdb->CPBsize;
> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + } else {
> + Nic->McastCount = 0;
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiStart is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
> +
> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
> + Status = RndisUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiReset (Cdb, Nic);
> + }
> +
> + Status = RndisUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiInitialize (Cdb, Nic);
> + }
> +
> + RndisUndiShutdown (Cdb, Nic);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when Undistop is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiGetInitInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + PXE_DB_GET_INIT_INFO *Db;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
> +
> + UsbEthDevice = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when RndisUndiGetConfigInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiInitialize is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
> +
> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> +
> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
> +
> + UsbRndisDevice->RequestId++;
> +
> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
> + return Status;
> + }
> +
> + // Only Wired Medium is supported
> + if (RndisInitMsgCmplt.Medium) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
> +
> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
> +
> + return Status;
> +}
> +
> +/**
> + This function is called when UndiReset is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
> +
> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
> +
> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
> +
> + UsbRndisDevice->RequestId = 1; // Let's start with 1
> +
> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiShutdown is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
> +
> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + Status = EFI_SUCCESS;
> + }
> +
> + UsbRndisDevice->RequestId = 1;
> + return Status;
> +}
> +
> +/**
> + Update the Media connection.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transmit the data after appending RNDIS header.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
> + if (RndisPacketMsg == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
> +
> + CopyMem (
> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
> + BulkOutData,
> + *DataLength
> + );
> +
> + TransferLength = RndisPacketMsg->MessageLength;
> +
> + Status = RndisTransmitDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
> +
> + FreePool (RndisPacketMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Receives and removes RNDIS header and returns the raw data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
> + @retval EFI_NOT_FOUND No buffer was found in the list.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> + VOID *Buffer;
> + PACKET_LIST *HeadPacket;
> + PACKET_LIST *PacketList;
> +
> + // Check if there is any outstanding packet to receive
> + // The buffer allocated has a linked List followed by the packet.
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + Buffer = NULL;
> + HeadPacket = NULL;
> +
> + while (1) {
> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
> + if (Buffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
> + PacketList = (PACKET_LIST *)Buffer;
> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
> + // Save the original address for freeing it up
> + PacketList->OrgBuffer = (UINT8 *)Buffer;
> + TransferLength = UsbRndisDevice->MaxTransferSize;
> +
> + Status = RndisReceiveDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
> + FreePool (Buffer);
> + break;
> + }
> +
> + // Collect all the RNDIS packet in Linked list.
> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
> + (TransferLength >= RndisPacketMsg->MessageLength))
> + {
> + // Insert Packet
> + PacketList->RemainingLength = TransferLength;
> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
> + } else {
> + FreePool (Buffer);
> + }
> + }
> +
> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
> +
> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
> +
> + // Check whether the packet is valid RNDIS packet.
> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
> + {
> + if (*DataLength >= RndisPacketMsg->DataLength) {
> + CopyMem (
> + BulkInData,
> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
> + RndisPacketMsg->DataLength
> + );
> +
> + *DataLength = RndisPacketMsg->DataLength;
> +
> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
> +
> + return EFI_SUCCESS;
> + } else {
> + *DataLength = RndisPacketMsg->DataLength;
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + }
> +
> + RemoveEntryList (&HeadPacket->PacketList);
> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
> + point to this function.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's control endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> +
> +**/
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + )
> +{
> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
> + EFI_USB_DEVICE_REQUEST DevReq;
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> + UINT32 SaveResponseType;
> + UINT32 SaveResponseLength;
> + UINT32 Index;
> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
> +
> + SaveResponseType = 0;
> + SaveResponseLength = 0;
> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
> +
> + if (RndisMsgResponse) {
> + SaveResponseType = RndisMsgResponse->MessageType;
> + SaveResponseLength = RndisMsgResponse->MessageLength;
> + }
> +
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsg,
> + RndisMsg->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
> +
> + // Error or no response expected
> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
> + return Status;
> + }
> +
> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
> + ReadRndisResponseInterrupt (UsbRndisDevice);
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsgResponse,
> + RndisMsgResponse->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
> +
> + PrintRndisMsg (RndisMsgResponse);
> +
> + if (!EFI_ERROR (Status)) {
> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
> +
> + RndisMsgResponse->MessageType = SaveResponseType;
> + RndisMsgResponse->MessageLength = SaveResponseLength;
> + continue;
> + }
> + }
> +
> + return Status;
> + }
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
> +
> + return EFI_TIMEOUT;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkOutEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_TX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (Status == EFI_SUCCESS) {
> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + UsbStatus = 0;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + // Use gStopBulkInCnt to stop BulkIn command
> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkInEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_RX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + } else {
> + gStopBulkInCnt--;
> + }
> + } else {
> + Status = EFI_TIMEOUT;
> + *TransferLength = 0;
> + gBlockBulkInCnt++;
> + }
> +
> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + gBlockBulkInCnt = 0;
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Prints RNDIS Header and Data
> +
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> +
> +**/
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + )
> +{
> + UINTN Length;
> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
> +
> + Length = 0;
> +
> + switch (RndisMsg->MessageType) {
> + case RNDIS_PACKET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
> + break;
> + case RNDIS_INITIALIZE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + break;
> + case RNDIS_INITIALIZE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> + break;
> + case RNDIS_HLT_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
> + break;
> + case RNDIS_QUERY_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
> + break;
> + case RNDIS_QUERY_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
> + break;
> + case RNDIS_SET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_MSG);
> + break;
> + case RNDIS_SET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
> + break;
> + case RNDIS_RESET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
> + break;
> + case RNDIS_RESET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
> + break;
> + case RNDIS_INDICATE_STATUS_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
> + break;
> + case RNDIS_KEEPALIVE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
> + break;
> + case RNDIS_KEEPALIVE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
> + }
> +
> + if (Length) {
> + UINTN Index = 0;
> + for ( ; Length; Length -= 4, Index++) {
> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
> + if (((Index % 4) == 3) && (Index != 0)) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> +
> + if ((Length < 8) && (Length > 4)) {
> + UINT32 Data32;
> + Index++;
> + Data32 = *((UINT32 *)RndisMsg + Index);
> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
> + break;
> + }
> + }
> +
> + if (Index % 4) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> + }
> +}
> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..cb70684f0bf1
> --- /dev/null
> +++ b/UsbNetworkPkg/ReadMe.md
> @@ -0,0 +1,65 @@
> +# UsbNetworkPkg
> +
> +This document is intend to provide package information, include the interface details.
> +
> +# INDEX
> + * [Introduction](#introduction)
> + * [Components](#components)
> + * [[NetworkCommon]](#networkcommon)
> + * [[UsbCdcEcm]](#usbcdcecm)
> + * [[UsbCdcNcm]](#usbcdcncm)
> + * [[UsbRndis]](#usbrndis)
> +
> +# Introduction
> +UsbNetworkPkg provides network functions for USB LAN devices.
> +
> +# Components
> +Below module is included in this package:<br>
> +- NetworkCommon
> +- UsbCdcEcm
> +- UsbCdcNcm
> +- UsbRndis
> +
> +## [NetworkCommon]
> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
> +
> +## Required Components
> +- NetworkPkg
> +
> +## [UsbCdcEcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x06|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbCdcNcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x0D|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbRndis]
> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x02|0xFF|
> +|0xEF|0x04|0x01|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
> new file mode 100644
> index 000000000000..f8ccccdb0830
> --- /dev/null
> +++ b/UsbNetworkPkg/ReleaseNotes.md
> @@ -0,0 +1,11 @@
> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
> +
> +# Release History<!-- omit in toc -->
> +- [1.00](#100)
> +
> +## 1.00
> +
> +**Release Date:** Mar 10, 2022
> +
> +**New Features**
> +- UsbNetworkPkg first release.
> --
> 2.35.1.windows.2
> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-03-28 11:40 ` Rebecca Cran
@ 2023-03-29 2:11 ` RichardHo [何明忠]
0 siblings, 0 replies; 11+ messages in thread
From: RichardHo [何明忠] @ 2023-03-29 2:11 UTC (permalink / raw)
To: Rebecca Cran, devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Tinh Nguyen,
Tony Lo (羅金松)
Hi Rebecca,
I will change the files to ".dsc.inc" and ".fdf.inc" next.
In DSC file :
!include UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
!include UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
In FDF file:
!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
Thanks,
Richard
-----Original Message-----
From: Rebecca Cran <rebecca@bsdio.com>
Sent: 2023年3月28日 7:41 PM
To: Richard Ho (何明忠) <RichardHo@ami.com>; devel@edk2.groups.io
Cc: Andrew Fish <afish@apple.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Michael D Kinney <michael.d.kinney@intel.com>; Michael Kubacki <mikuback@linux.microsoft.com>; Zhiguang Liu <zhiguang.liu@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>; Tinh Nguyen <tinhnguyen@os.amperecomputing.com>; Tony Lo (羅金松) <TonyLo@ami.com>
Subject: [EXTERNAL] Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
**CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**
The include files should have the suffix ".dsc.inc" or ".fdf.inc", not
".inc.dsc" and ".inc.fdf".
How are the include files expected to be used?
I've tried including them in OvmfPkg/OvmfPkgX64.dsc and
OvmfPkg/OvmfPkgX64.fdf but am having trouble figuring out where in those
files the various lines should be located.
--
Rebecca Cran
On 3/9/23 12:51 AM, Richard Ho (何明忠) wrote:
> This driver provides UEFI driver for USB RNDIS device
>
> Signed-off-by: Richard Ho <richardho@ami.com>
> Cc: Andrew Fish <afish@apple.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
> Reviewed-by: Tony Lo <tonylo@ami.com>
> ---
> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
> UsbNetworkPkg/ReadMe.md | 65 +
> UsbNetworkPkg/ReleaseNotes.md | 11 +
> 18 files changed, 7452 insertions(+)
> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> create mode 100644 UsbNetworkPkg/ReadMe.md
> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>
> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
> new file mode 100644
> index 000000000000..30e4e4c8aac7
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
> @@ -0,0 +1,46 @@
> +## @file
> +# This package defines Usb network specific interfaces and library classes
> +# as well as configuration for standard edk2 packages.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x00010005
> + PACKAGE_NAME = UsbNetworkPkg
> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
> + PACKAGE_VERSION = 0.1
> +
> +[Includes]
> + Include
> +
> +[Protocols]
> + ## Include/Protocol/EdkIIUsbEthernet.h
> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
> +
> +[Guids]
> + ## Usb Network package token space GUID
> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
> +
> +[PcdsFeatureFlag]
> +
> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
> +
> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
> +
> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
> +
> +[PcdsFixedAtBuild, PcdsPatchableInModule]
> + ## Support rate limiting
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
> +
> + ## The rate limiting Credit value is check in rate limiter event.
> + # It is to control the RateLimitingCreditCount max value.
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
> +
> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> new file mode 100644
> index 000000000000..a3316b1d4a89
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> @@ -0,0 +1,9 @@
> +## @file
> +# Global DSC definitions to be included into project DSC file.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Components.X64]
> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> new file mode 100644
> index 000000000000..544df8404c64
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> new file mode 100644
> index 000000000000..85a309bcf567
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> @@ -0,0 +1,23 @@
> +## @file
> +# Global switches enable/disable project features.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
> + DEFINE PEI=IA32
> + DEFINE DXE=X64
> +!else
> + DEFINE PEI=COMMON
> + DEFINE DXE=COMMON
> +!endif
> +
> +[Packages]
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[PcdsFeatureFlag]
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> new file mode 100644
> index 000000000000..10616d97edb4
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> new file mode 100644
> index 000000000000..8923102bc350
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> @@ -0,0 +1,49 @@
> +## @file
> +# This is Usb Network Common driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = NetworkCommon
> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = NetworkCommonEntry
> +
> +[Sources]
> + DriverBinding.c
> + DriverBinding.h
> + ComponentName.c
> + PxeFunction.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Pcd]
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> new file mode 100644
> index 000000000000..64205e427745
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# This is Usb Rndis driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = UsbRndis
> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = UsbRndisEntry
> +
> +[Sources]
> + UsbRndis.c
> + UsbRndis.h
> + UsbRndisFunction.c
> + ComponentName.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> new file mode 100644
> index 000000000000..f54946c7aa69
> --- /dev/null
> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> @@ -0,0 +1,878 @@
> +/** @file
> + Header file contains code for USB Ethernet Protocol
> + definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
> +
> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
> +
> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
> +
> +#define USB_CDC_CLASS 0x02
> +#define USB_CDC_ACM_SUBCLASS 0x02
> +#define USB_CDC_ECM_SUBCLASS 0x06
> +#define USB_CDC_NCM_SUBCLASS 0x0D
> +#define USB_CDC_DATA_CLASS 0x0A
> +#define USB_CDC_DATA_SUBCLASS 0x00
> +#define USB_NO_CLASS_PROTOCOL 0x00
> +#define USB_NCM_NTB_PROTOCOL 0x01
> +#define USB_VENDOR_PROTOCOL 0xFF
> +
> +// Type Values for the DescriptorType Field
> +#define CS_INTERFACE 0x24
> +#define CS_ENDPOINT 0x25
> +
> +// Descriptor SubType in Functional Descriptors
> +#define HEADER_FUN_DESCRIPTOR 0x00
> +#define UNION_FUN_DESCRIPTOR 0x06
> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
> +
> +#define MAX_LAN_INTERFACE 0x10
> +
> +// Table 20: Class-Specific Notification Codes
> +#define USB_CDC_NETWORK_CONNECTION 0x00
> +
> +// 6.3.1 NetworkConnection
> +#define NETWORK_CONNECTED 0x01
> +#define NETWORK_DISCONNECT 0x00
> +
> +// USB Header functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT16 BcdCdc;
> +} USB_HEADER_FUN_DESCRIPTOR;
> +
> +// USB Union Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MasterInterface;
> + UINT8 SlaveInterface;
> +} USB_UNION_FUN_DESCRIPTOR;
> +
> +// USB Ethernet Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MacAddress;
> + UINT32 EthernetStatistics;
> + UINT16 MaxSegmentSize;
> + UINT16 NumberMcFilters;
> + UINT8 NumberPowerFilters;
> +} USB_ETHERNET_FUN_DESCRIPTOR;
> +
> +typedef struct {
> + UINT32 UsBitRate;
> + UINT32 DsBitRate;
> +} USB_CONNECT_SPEED_CHANGE;
> +
> +// Request Type Codes for USB Ethernet
> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
> +
> +// Class-Specific Request Codes for Ethernet subclass
> +// USB ECM 1.2 specification, Section 6.2
> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
> +#define SET_ETH_PACKET_FILTER_REQ 0x43
> +#define GET_ETH_STATISTIC_REQ 0x44
> +
> +// USB ECM command request length
> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
> +
> +// USB Ethernet Packet Filter Bitmap
> +// USB ECM 1.2 specification, Section 6.2.4
> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
> +
> +// USB Ethernet Statistics Feature Selector Codes
> +// USB ECM 1.2 specification, Section 6.2.5
> +#define USB_ETH_XMIT_OK 0x01
> +#define USB_ETH_RCV_OK 0x02
> +#define USB_ETH_XMIT_ERROR 0x03
> +#define USB_ETH_RCV_ERROR 0x04
> +#define USB_ETH_RCV_NO_BUFFER 0x05
> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
> +#define USB_ETH_RCV_CRC_ERROR 0x12
> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
> +#define USB_ETH_XMIT_DEFERRED 0x17
> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
> +#define USB_ETH_RCV_OVERRUN 0x19
> +#define USB_ETH_XMIT_UNDERRUN 0x1A
> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
> +
> +// NIC Information
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + UINT16 InterrupOpFlag;
> + UINT64 MappedAddr;
> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
> + UINT8 McastCount;
> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
> + UINT8 TxBufferCount;
> + UINT16 State;
> + BOOLEAN CanTransmit;
> + UINT16 ReceiveStatus;
> + UINT8 RxFilter;
> + UINT32 RxFrame;
> + UINT32 TxFrame;
> + UINT16 NetworkConnect;
> + UINT8 CableDetect;
> + UINT16 MaxSegmentSize;
> + EFI_MAC_ADDRESS MacAddr;
> + PXE_CPB_START_31 PxeStart;
> + PXE_CPB_INITIALIZE PxeInit;
> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
> + EFI_USB_DEVICE_REQUEST Request;
> + EFI_EVENT RateLimiter;
> + UINT32 RateLimitingCredit;
> + UINT32 RateLimitingCreditCount;
> + UINT32 RateLimitingPollTimer;
> + BOOLEAN RateLimitingEnable;
> +} NIC_DATA;
> +
> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Request
> + );
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + );
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + );
> +
> +typedef struct {
> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
> +} EDKII_USB_ETHERNET_UNDI;
> +
> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
> +// descriptor and specific requests.
> +struct _EDKII_USB_ETHERNET_PROTOCOL {
> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
> + // for calling the UNDI child functions
> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
> +};
> +
> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> new file mode 100644
> index 000000000000..0416ce132302
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> @@ -0,0 +1,266 @@
> +/** @file
> + Header file for for USB network common driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _DRIVER_BINDING_H_
> +#define _DRIVER_BINDING_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/NetworkInterfaceIdentifier.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +#define NETWORK_COMMON_DRIVER_VERSION 1
> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
> +#define RX_BUFFER_COUNT 32
> +#define TX_BUFFER_COUNT 32
> +#define MEMORY_REQUIRE 0
> +
> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
> + UINT16 Protocol;
> +} EthernetHeader;
> +#pragma pack()
> +
> +typedef struct {
> + UINTN Signature;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
> + EFI_HANDLE DeviceHandle;
> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + NIC_DATA NicInfo;
> + VOID *ReceiveBuffer;
> +} NIC_DEVICE;
> +
> +typedef VOID (*API_FUNC)(
> + PXE_CDB *,
> + NIC_DATA *
> + );
> +
> +extern PXE_SW_UNDI *gPxe;
> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + );
> +
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + );
> +
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + );
> +
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + );
> +
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + );
> +
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + );
> +
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +#endif
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> new file mode 100644
> index 000000000000..775807042460
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> @@ -0,0 +1,586 @@
> +/** @file
> + Header file for for USB Rndis driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _USB_RNDIS_H_
> +#define _USB_RNDIS_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
> + EFI_HANDLE UsbCdcDataHandle;
> + EFI_HANDLE UsbRndisHandle;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
> + EFI_USB_CONFIG_DESCRIPTOR *Config;
> + UINT8 NumOfInterface;
> + UINT8 BulkInEndpoint;
> + UINT8 BulkOutEndpoint;
> + UINT8 InterrupEndpoint;
> + EFI_MAC_ADDRESS MacAddress;
> + UINT32 RequestId;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + LIST_ENTRY ReceivePacketList;
> +} USB_RNDIS_DEVICE;
> +
> +#define USB_RNDIS_DRIVER_VERSION 1
> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
> +
> +#define LAN_BULKIN_CMD_CONTROL 1
> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
> +#define RNDIS_RESERVED_BYTE_LENGTH 8
> +
> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
> +
> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
> +
> +struct BIT_MAP {
> + unsigned int Src;
> + unsigned int Dst;
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + );
> +
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + );
> +
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + );
> +
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN BOOLEAN *PatternActive
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *Statistic
> + );
> +
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + );
> +
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + );
> +
> +#define RNDIS_MAJOR_VERSION 0x00000001
> +#define RNDIS_MINOR_VERSION 0x00000000
> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
> +
> +#define RNDIS_PACKET_MSG 0x00000001
> +#define RNDIS_INITIALIZE_MSG 0x00000002
> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
> +#define RNDIS_HLT_MSG 0x00000003
> +#define RNDIS_QUERY_MSG 0x00000004
> +#define RNDIS_QUERY_CMPLT 0x80000004
> +#define RNDIS_SET_MSG 0x00000005
> +#define RNDIS_SET_CMPLT 0x80000005
> +#define RNDIS_RESET_MSG 0x00000006
> +#define RNDIS_RESET_CMPLT 0x80000006
> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
> +#define RNDIS_KEEPALIVE_MSG 0x00000008
> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
> +
> +#define RNDIS_STATUS_SUCCESS 0x00000000
> +#define RNDIS_STATUS_FAILURE 0xC0000001
> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
> +
> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
> +
> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
> +
> +//
> +// General Objects
> +//
> +// Taken from NTDDNDIS.H
> +#define OID_GEN_SUPPORTED_LIST 0x00010101
> +#define OID_GEN_HARDWARE_STATUS 0x00010102
> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
> +#define OID_GEN_MEDIA_IN_USE 0x00010104
> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
> +#define OID_GEN_LINK_SPEED 0x00010107
> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
> +#define OID_GEN_VENDOR_ID 0x0001010C
> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
> +#define OID_GEN_DRIVER_VERSION 0x00010110
> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
> +#define OID_GEN_MAC_OPTIONS 0x00010113
> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
> +
> +#define OID_GEN_XMIT_OK 0x00020101
> +#define OID_GEN_RCV_OK 0x00020102
> +#define OID_GEN_XMIT_ERROR 0x00020103
> +#define OID_GEN_RCV_ERROR 0x00020104
> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
> +
> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
> +
> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
> +//
> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
> +//
> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
> +#define NDIS_PACKET_TYPE_SMT 0x0040
> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
> +#define NDIS_PACKET_TYPE_GROUP 0x1000
> +
> +#pragma pack(1)
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> +} REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 MaxTransferSize;
> +} REMOTE_NDIS_INITIALIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_HALT_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_QUERY_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_SET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Reserved;
> +} REMOTE_NDIS_RESET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 StatusBufferLength;
> + UINT32 StatusBufferOffset;
> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
> +
> +typedef struct {
> + UINT32 DiagStatus;
> + UINT32 ErrorOffset;
> +} RNDIS_DIAGNOSTIC_INFO;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_KEEPALIVE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 DeviceFlags;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + UINT64 Reserved;
> +} REMOTE_NDIS_INITIALIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> +} REMOTE_NDIS_QUERY_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_SET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 AddressingReset;
> +} REMOTE_NDIS_RESET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 DataOffset;
> + UINT32 DataLength;
> + UINT32 OutOfBandDataOffset;
> + UINT32 OutOfBandDataLength;
> + UINT32 NumOutOfBandDataElements;
> + UINT32 PerPacketInfoOffset;
> + UINT32 PerPacketInfoLength;
> + UINT32 Reserved1;
> + UINT32 Reserved2;
> +} REMOTE_NDIS_PACKET_MSG;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} OUT_OF_BAND_DATA_RECORD;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} PER_PACKET_INFO_DATA_RECORD;
> +
> +typedef struct {
> + LIST_ENTRY PacketList;
> + UINT8 *OrgBuffer;
> + UINTN RemainingLength;
> + UINT8 *PacketStartBuffer; // Variable size data to follow
> +} PACKET_LIST;
> +
> +#pragma pack()
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> new file mode 100644
> index 000000000000..e83469e13079
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> @@ -0,0 +1,263 @@
> +/** @file
> + This file contains code for USB network common driver
> + component name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
> + {
> + "eng;en",
> + L"Network Common Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
> + NetworkCommonComponentNameGetDriverName,
> + NetworkCommonComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> + CHAR16 *HandleName;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
> +
> + if (!Language || !ControllerName) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (ChildHandle == NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Make sure this driver is currently managing ControllerHandle
> + //
> + Status = EfiTestManagedDevice (
> + Controller,
> + gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Make sure this driver produced ChildHandle
> + //
> + Status = EfiTestChildHandle (
> + Controller,
> + ChildHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
> +
> + if (!EFI_ERROR (Status)) {
> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *ControllerName = HandleName;
> +
> + if (gNetworkCommonControllerNameTable != NULL) {
> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
> + gNetworkCommonControllerNameTable = NULL;
> + }
> +
> + Status = AddUnicodeString2 (
> + "eng",
> + gNetworkCommonComponentName.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + TRUE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = AddUnicodeString2 (
> + "en",
> + gNetworkCommonComponentName2.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + FALSE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> new file mode 100644
> index 000000000000..23b791362091
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> @@ -0,0 +1,595 @@
> +/** @file
> + This file contains code for USB network binding driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +PXE_SW_UNDI *gPxe = NULL;
> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +UINT32 gRateLimitingCredit;
> +UINT32 gRateLimitingPollTimer;
> +BOOLEAN gRateLimitingEnable;
> +
> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
> + NetworkCommonSupported,
> + NetworkCommonDriverStart,
> + NetworkCommonDriverStop,
> + NETWORK_COMMON_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Create MAC Device Path
> +
> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
> + @retval EFI_SUCCESS MAC device path created successfully.
> +
> +**/
> +EFI_STATUS
> +CreateMacDevicePath (
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + MAC_ADDR_DEVICE_PATH MacAddrNode;
> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
> + UINT8 *DevicePath;
> + UINT16 TotalLength;
> + UINT16 BaseLength;
> +
> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
> +
> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
> + MacAddrNode.Header.Length[1] = 0;
> +
> + EndNode = BaseDev;
> +
> + while (!IsDevicePathEnd (EndNode)) {
> + EndNode = NextDevicePathNode (EndNode);
> + }
> +
> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
> + DevicePath += BaseLength;
> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
> + DevicePath += sizeof (MacAddrNode);
> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Network Common Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + EFI_MAC_ADDRESS MacAddress;
> + UINTN BulkDataSize;
> + NIC_DEVICE *NicDevice;
> + UINT8 *TmpPxePointer;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
> +
> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
> + ASSERT_EFI_ERROR (Status);
> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
> + if (!NicDevice) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + // for alignment adjustment
> + if (gPxe == NULL) {
> + TmpPxePointer = NULL;
> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
> + if (!TmpPxePointer) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + return EFI_OUT_OF_RESOURCES;
> + } else {
> + // check for paragraph alignment here
> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
> + } else {
> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
> + }
> +
> + if (!gPxe) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PxeStructInit (gPxe);
> + }
> + }
> +
> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
> +
> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
> +
> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
> +
> + NicDevice->NicInfo.UsbEth = UsbEth;
> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
> + NicDevice->NicInfo.CableDetect = 0;
> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
> +
> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
> +
> + NicDevice->NicInfo.TxBufferCount = 0;
> +
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
> + } else {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = CreateMacDevicePath (
> + &NicDevice->DevPath,
> + UsbEthPath,
> + &NicDevice->NicInfo
> + );
> +
> + if (EFI_ERROR (Status)) {
> + UpdateNicNum (NULL, gPxe);
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> + }
> +
> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
> + NicDevice->NiiProtocol.ImageSize = 0;
> + NicDevice->NiiProtocol.ImageAddr = 0;
> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
> +
> + NicDevice->NiiProtocol.StringId[0] = 'U';
> + NicDevice->NiiProtocol.StringId[1] = 'N';
> + NicDevice->NiiProtocol.StringId[2] = 'D';
> + NicDevice->NiiProtocol.StringId[3] = 'I';
> + NicDevice->DeviceHandle = NULL;
> +
> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
> + NicDevice->NicInfo.RateLimiter = NULL;
> +
> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &NicDevice->DeviceHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice->DevPath != NULL) {
> + FreePool (NicDevice->DevPath);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + NicDevice->DeviceHandle,
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AllChildrenStopped;
> + UINTN Index;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + NIC_DEVICE *NicDevice;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
> +
> + if (NumberOfChildren == 0) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + AllChildrenStopped = TRUE;
> +
> + for (Index = 0; Index < NumberOfChildren; Index++) {
> + Status = gBS->OpenProtocol (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + AllChildrenStopped = FALSE;
> + continue;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index]
> + );
> +
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index],
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> + } else {
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> + }
> + }
> +
> + if (!AllChildrenStopped) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Entrypoint of Network Common Driver.
> +
> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gNetworkCommonDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gNetworkCommonComponentName2,
> + NULL
> + );
> + return Status;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> new file mode 100644
> index 000000000000..687cabca4ce3
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> @@ -0,0 +1,1803 @@
> +/** @file
> + This file contains code for UNDI command based on UEFI specification.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +// API table, defined in UEFI specification
> +API_FUNC gUndiApiTable[] = {
> + UndiGetState,
> + UndiStart,
> + UndiStop,
> + UndiGetInitInfo,
> + UndiGetConfigInfo,
> + UndiInitialize,
> + UndiReset,
> + UndiShutdown,
> + UndiInterruptEnable,
> + UndiReceiveFilter,
> + UndiStationAddress,
> + UndiStatistics,
> + UndiMcastIp2Mac,
> + UndiNvData,
> + UndiGetStatus,
> + UndiFillHeader,
> + UndiTransmit,
> + UndiReceive
> +};
> +
> +/**
> + Callback function for enable Rate Limiter
> +
> + @param[in] Event Event whose notification function is being invoked
> + @param[in] Context Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +UndiRateLimiterCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + NIC_DATA *Nic = Context;
> +
> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
> + Nic->RateLimitingCreditCount++;
> + }
> +}
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_START_31 *Cpb;
> + EFI_STATUS Status;
> + BOOLEAN EventError;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
> +
> + Nic->PxeStart.Delay = Cpb->Delay;
> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
> + Nic->PxeStart.Block = Cpb->Block;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
> + EventError = FALSE;
> + Status = EFI_SUCCESS;
> + if (Nic->RateLimitingEnable == TRUE) {
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + UndiRateLimiterCallback,
> + Nic,
> + &Nic->RateLimiter
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = gBS->SetTimer (
> + Nic->RateLimiter,
> + TimerPeriodic,
> + Nic->RateLimitingPollTimer * 10000
> + );
> + if (EFI_ERROR (Status)) {
> + EventError = TRUE;
> + }
> + }
> + }
> +
> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + // Initial the state for UNDI start.
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + } else {
> + if (Nic->RateLimitingEnable == TRUE) {
> + if (!EventError) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + }
> +
> + if (Nic->RateLimiter) {
> + gBS->CloseEvent (&Nic->RateLimiter);
> + Nic->RateLimiter = 0;
> + }
> + }
> +
> + // Initial the state when UNDI start is fail
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
> + return;
> + }
> +
> + Nic->PxeStart.Delay = 0;
> + Nic->PxeStart.Virt2Phys = 0;
> + Nic->PxeStart.Block = 0;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = 0;
> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
> +
> + if (Nic->RateLimitingEnable == TRUE) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + gBS->CloseEvent (&Nic->RateLimiter);
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_INIT_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->MemoryRequired = MEMORY_REQUIRE;
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + Db->LinkSpeeds[0] = 10;
> + Db->LinkSpeeds[1] = 100;
> + Db->LinkSpeeds[2] = 1000;
> + Db->LinkSpeeds[3] = 0;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> + Db->IFtype = PXE_IFTYPE_ETHERNET;
> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
> +
> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_CONFIG_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->pci.BusType = PXE_BUSTYPE_USB;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_INITIALIZE *Cpb;
> + PXE_DB_INITIALIZE *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
> +
> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
> +
> + Cdb->StatCode = Initialize (Cdb, Nic);
> +
> + Db->MemoryUsed = MEMORY_REQUIRE;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> +
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + Nic->CanTransmit = FALSE;
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
> + }
> + }
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Initialize Network interface controller data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval Status A value of Pxe statcode.
> +
> +**/
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + UINTN Status;
> + UINT32 Index;
> + EFI_STATUS EfiStatus;
> +
> + Status = MapIt (
> + Nic,
> + Nic->PxeInit.MemoryAddr,
> + Nic->PxeInit.MemoryLength,
> + TO_AND_FROM_DEVICE,
> + (UINT64)(UINTN)&Nic->MappedAddr
> + );
> +
> + if (Status != 0) {
> + return (UINT16)Status;
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->BroadcastNodeAddress[Index] = 0xFF;
> + }
> +
> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = 0;
> + Nic->PermNodeAddress[Index] = 0;
> + Nic->BroadcastNodeAddress[Index] = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
> + if (EFI_ERROR (EfiStatus)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return (UINT16)Status;
> +}
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
> + Nic->InterrupOpFlag = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Nic->CanTransmit = FALSE;
> +
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + UINT16 NewFilter;
> + PXE_DB_RECEIVE_FILTERS *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> +
> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
> + if ((Cdb->DBsize != 0)) {
> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
> + }
> + }
> +
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
> + if (NewFilter == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Cdb->CPBsize != 0) {
> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if ((Cdb->CPBsize == 0)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + break;
> +
> + default:
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Set PXE receive filter.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] SetFilter PXE receive filter
> + @param[in] CpbAddr Command Parameter Block Address
> + @param[in] CpbSize Command Parameter Block Size
> +
> +**/
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_STATION_ADDRESS *Cpb;
> + PXE_DB_STATION_ADDRESS *Db;
> + UINT16 Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> + }
> +
> + if (Cdb->CPBaddr != 0) {
> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
> + }
> + }
> +
> + if (Cdb->DBaddr != 0) {
> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Return data for DB data.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> +**/
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + )
> +{
> + PXE_DB_STATISTICS *DbStatistic;
> + EFI_STATUS Status;
> +
> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
> +
> + if (DbSize == 0) {
> + return PXE_STATCODE_SUCCESS;
> + }
> +
> + DbStatistic->Supported = 0x802;
> + DbStatistic->Data[0x01] = Nic->RxFrame;
> + DbStatistic->Data[0x0B] = Nic->TxFrame;
> +
> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in, out] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
> + PXE_DB_MCAST_IP_TO_MAC *Db;
> + UINT8 *Tmp;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + return;
> + }
> +
> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
> +
> + if ((Tmp[0] & 0xF0) != 0xE0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
> + }
> +
> + Db->MAC[0] = 0x01;
> + Db->MAC[1] = 0x00;
> + Db->MAC[2] = 0x5E;
> + Db->MAC[3] = Tmp[1] & 0x7F;
> + Db->MAC[4] = Tmp[2];
> + Db->MAC[5] = Tmp[3];
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_STATUS *Db;
> + PXE_DB_GET_STATUS TmpGetStatus;
> + UINT16 NumEntries;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + TmpGetStatus.RxFrameLen = 0;
> + TmpGetStatus.reserved = 0;
> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
> + } else {
> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
> + if (Cdb->DBsize == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + NumEntries = Cdb->DBsize - sizeof (UINT64);
> + Cdb->DBsize = sizeof (UINT32) * 2;
> +
> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
> + if (Nic->TxBufferCount > 0) {
> + Nic->TxBufferCount--;
> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
> + }
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
> + if (Nic->ReceiveStatus != 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
> + }
> + }
> +
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_FILL_HEADER *CpbFillHeader;
> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
> + EthernetHeader *MacHeader;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
> +
> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
> + MacHeader->Protocol = CpbFill->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
> + }
> + } else {
> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
> + MacHeader->Protocol = CpbFillHeader->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk out command to transmit data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in] OpFlags Operation Flags.
> +
> +**/
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + )
> +{
> + EFI_STATUS Status;
> + PXE_CPB_TRANSMIT *Cpb;
> + UINT64 BulkOutData;
> + UINTN DataLength;
> + UINTN TransmitLength;
> + UINTN Map;
> + UINT32 Counter;
> + UINT16 StatCode;
> +
> + BulkOutData = 0;
> + Counter = 0;
> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
> +
> + if (Nic->CanTransmit) {
> + return PXE_STATCODE_BUSY;
> + }
> +
> + Nic->CanTransmit = TRUE;
> +
> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + Map = MapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + (UINT64)(UINTN)&BulkOutData
> + );
> +
> + if (Map != 0) {
> + Nic->CanTransmit = FALSE;
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
> + Nic->TxBufferCount++;
> + }
> +
> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
> +
> + while (1) {
> + if (Counter >= 3) {
> + StatCode = PXE_STATCODE_BUSY;
> + break;
> + }
> +
> + TransmitLength = DataLength;
> +
> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
> + if (EFI_ERROR (Status)) {
> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
> + break;
> + }
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + break;
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + Nic->TxFrame++;
> + StatCode = PXE_STATCODE_SUCCESS;
> + break;
> + }
> +
> + Counter++;
> + }
> +
> + UnMapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + BulkOutData
> + );
> +
> + Nic->CanTransmit = FALSE;
> +
> + return StatCode;
> +}
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk in command to receive data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in, out] DbAddr Data Block Address.
> +
> +**/
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + PXE_FRAME_TYPE FrameType;
> + PXE_CPB_RECEIVE *Cpb;
> + PXE_DB_RECEIVE *Db;
> + NIC_DEVICE *NicDevice;
> + UINT8 *BulkInData;
> + UINTN DataLength;
> + EthernetHeader *Header;
> + EFI_TPL OriginalTpl;
> +
> + FrameType = PXE_FRAME_TYPE_NONE;
> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
> + BulkInData = NicDevice->ReceiveBuffer;
> + DataLength = (UINTN)Nic->MaxSegmentSize;
> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
> +
> + if (!BulkInData) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
> + if (EFI_ERROR (Status)) {
> + Nic->ReceiveStatus = 0;
> + if (Nic->RateLimitingEnable == TRUE) {
> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + if (Nic->RateLimitingCreditCount != 0) {
> + Nic->RateLimitingCreditCount--;
> + }
> +
> + gBS->RestoreTPL (OriginalTpl);
> + }
> +
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Nic->RxFrame++;
> +
> + if (DataLength != 0) {
> + if (DataLength > Cpb->BufferLen) {
> + DataLength = (UINTN)Cpb->BufferLen;
> + }
> +
> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
> +
> + Header = (EthernetHeader *)BulkInData;
> +
> + Db->FrameLen = (UINT32)DataLength;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_UNICAST;
> + } else {
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_BROADCAST;
> + } else {
> + if ((Header->DestAddr[0] & 1) == 1) {
> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
> + } else {
> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
> + }
> + }
> + }
> +
> + Db->Type = FrameType;
> + Db->Protocol = Header->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
> + Db->DestAddr[Index] = Header->DestAddr[Index];
> + }
> + }
> +
> + if (FrameType == PXE_FRAME_TYPE_NONE) {
> + Nic->ReceiveStatus = 0;
> + } else {
> + Nic->ReceiveStatus = 1;
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Fill out PXE SW UNDI structure.
> +
> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
> + PxeSw->Fudge = 0;
> + PxeSw->IFcnt = 0;
> + PxeSw->IFcntExt = 0;
> + PxeSw->Rev = PXE_ROMID_REV;
> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
> + PxeSw->reserved1 = 0;
> +
> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
> + PXE_ROMID_IMP_FRAG_SUPPORTED |
> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
> +
> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
> + PxeSw->reserved2[0] = 0;
> + PxeSw->reserved2[1] = 0;
> + PxeSw->reserved2[2] = 0;
> + PxeSw->BusCnt = 1;
> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
> +}
> +
> +/**
> + Update NIC number.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + UINT16 NicNum;
> +
> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
> +
> + if (Nic == NULL) {
> + if (NicNum > 0) {
> + NicNum--;
> + }
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> + return;
> + }
> +
> + NicNum++;
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> +}
> +
> +/**
> + UNDI API table entry.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + )
> +{
> + PXE_CDB *CdbPtr;
> + NIC_DATA *Nic;
> +
> + if (Cdb == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Map virtual memory address for DMA. This field can be set to
> + zero if there is no mapping service.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[out] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + )
> +{
> + UINT64 *PhyAddr;
> +
> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
> +
> + if (Nic->PxeStart.Map_Mem == 0) {
> + *PhyAddr = MemAddr;
> + } else {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Un-map previously mapped virtual memory address. This field can be set
> + to zero only if the Map_Mem() service is also set to zero.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[in] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + )
> +{
> + if (Nic->PxeStart.UnMap_Mem != 0) {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
> new file mode 100644
> index 000000000000..b9ba170c135b
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
> @@ -0,0 +1,172 @@
> +/** @file
> + This file contains code for USB RNDIS Driver Component
> + Name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
> + {
> + "eng;en",
> + L"USB RNDIS Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
> + UsbRndisComponentNameGetDriverName,
> + UsbRndisComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gUsbRndisDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gUsbRndisComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> new file mode 100644
> index 000000000000..92830771e408
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> @@ -0,0 +1,886 @@
> +/** @file
> + This file contains code for USB Remote Network Driver
> + Interface Spec. Driver Binding
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
> + UsbRndisDriverSupported,
> + UsbRndisDriverStart,
> + UsbRndisDriverStop,
> + USB_RNDIS_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Check if this interface is USB Rndis SubType
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +
> +**/
> +BOOLEAN
> +IsSupportedDevice (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if this interface is USB Rndis SubType but not CDC Data interface
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +**/
> +BOOLEAN
> +IsRndisInterface (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
> +
> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> +
> + @retval EFI_SUCCESS Is the same device.
> + @retval EFI_UNSUPPORTED Is not the same device.
> +
> +**/
> +EFI_STATUS
> +IsSameDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
> + )
> +{
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
> + while (1) {
> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
> + {
> + return EFI_SUCCESS;
> + } else {
> + return EFI_UNSUPPORTED;
> + }
> + } else {
> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
> + }
> + }
> +
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
> +}
> +
> +/**
> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB CDC Data(UsbIo) installed.
> + @retval FALSE USB CDC Data(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbCdcData (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for CDC-DATA
> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB Rndis(UsbIo) installed
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis(UsbIo) installed.
> + @retval FALSE USB Rndis(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbRndis (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for Rndis
> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
> + For one device two USBIO will be installed each for CDC and RNDIS interface.
> +
> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +UpdateRndisDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + BOOLEAN IsRndisInterfaceFlag;
> +
> + IsRndisInterfaceFlag = FALSE;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEdkIIUsbEthProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthDevice
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
> + if (IsRndisInterfaceFlag == FALSE) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> +
> + if (!EFI_ERROR (Status)) {
> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> + FreePool (HandleBuffer);
> + return EFI_SUCCESS;
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> +
> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
> + and UsbIO protocol.
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
> +
> +**/
> +VOID
> +FindMatchingCdcData (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + UsbRndisDevice->UsbRndisHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
> + FreePool (HandleBuffer);
> + return;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> + if (!EFI_ERROR (Status)) {
> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + FreePool (HandleBuffer);
> + return;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +}
> +
> +/**
> +
> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
> +
> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FindMatchingRndisDev (
> + IN EFI_HANDLE CdcHandle,
> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
> + OUT EFI_HANDLE *RndisHandle
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + CdcHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
> + break;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + if (!EFI_ERROR (Status)) {
> + *RndisHandle = HandleBuffer[Index];
> + *CdcUsbIo = UsbIo;
> + FreePool (HandleBuffer);
> + return Status;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + USB Rndis Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + USB RNDIS Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_HANDLE RndisHandle;
> +
> + RndisHandle = ControllerHandle;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = UpdateRndisDevice (
> + UsbEthPath,
> + &UsbRndisDevice
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + return Status;
> + } else {
> + // Check if RnDis exist
> + Status = FindMatchingRndisDev (
> + ControllerHandle,
> + &UsbIo,
> + &RndisHandle
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> + }
> + }
> +
> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
> +
> + if (!UsbRndisDevice) {
> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Status = LoadAllDescriptor (
> + UsbIo,
> + &UsbRndisDevice->Config
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (
> + UsbIo,
> + &Interface
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
> + UsbRndisDevice->UsbCdcDataHandle = 0;
> + UsbRndisDevice->UsbIo = UsbIo;
> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
> +
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
> +
> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
> + UsbRndisDevice->PacketAlignmentFactor = 0;
> +
> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
> +
> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
> + FindMatchingCdcData (UsbRndisDevice);
> +
> + if (UsbRndisDevice->UsbIoCdcData) {
> + Status = gBS->InstallProtocolInterface (
> + &ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &(UsbRndisDevice->UsbEth)
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
> + return EFI_SUCCESS;
> + }
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + CheckandStopRndisDevice
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> +
> + @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
> +CheckandStopRndisDevice (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
> + return Status;
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + USB Rndis Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = CheckandStopRndisDevice (This, ControllerHandle);
> + return Status;
> + }
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
> +
> + Status = gBS->CloseProtocol (
> + UsbRndisDevice->UsbCdcDataHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + UsbRndisDevice->UsbCdcDataHandle
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
> + }
> +
> + Status = gBS->UninstallProtocolInterface (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + UsbEthProtocol
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Entrypoint of RNDIS Driver.
> +
> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
> +
> + return gBS->InstallMultipleProtocolInterfaces (
> + &gUsbRndisDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gUsbRndisDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gUsbRndisComponentName2,
> + NULL
> + );
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> new file mode 100644
> index 000000000000..e3fe737cdef1
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> @@ -0,0 +1,1718 @@
> +/** @file
> + This file contains code for USB Ethernet descriptor
> + and specific requests implement.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +UINT16 gStopBulkInCnt = 0;
> +UINT16 gBlockBulkInCnt = 0;
> +
> +/**
> + Load All of device descriptor.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[out] ConfigDesc A pointer to the configuration descriptor.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
> + buffer specified by DescriptorLength and Descriptor
> + is not large enough to hold the result of the request.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
> + status is returned in Status.
> +**/
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 TransStatus;
> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
> +
> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = gBS->AllocatePool (
> + EfiBootServicesData,
> + Tmp.TotalLength,
> + (VOID **)ConfigDesc
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbGetDescriptor (
> + UsbIo,
> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
> + 0,
> + Tmp.TotalLength,
> + *ConfigDesc,
> + &TransStatus
> + );
> + return Status;
> +}
> +
> +/**
> + Returns pointer to the next descriptor for the pack of USB descriptors
> + located in continues memory segment
> +
> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
> + @param[in, out] Offset A pointer to the sum of descriptor length.
> +
> + @retval TRUE The request executed successfully.
> + @retval FALSE No next descriptor.
> +
> +**/
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + )
> +{
> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
> + return FALSE;
> + }
> +
> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
> + return FALSE;
> + }
> +
> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
> + if ( *Offset >= Desc->TotalLength ) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Read Function descriptor
> +
> + @param[in] Config A pointer to all of configuration.
> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
> +
> + @retval EFI_SUCCESS The device capability descriptor was retrieved
> + successfully.
> + @retval EFI_UNSUPPORTED No supported.
> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Offset;
> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
> +
> + Status = EFI_NOT_FOUND;
> +
> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
> + if (Interface->DescriptorType == CS_INTERFACE) {
> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
> + switch (FunDescriptorType) {
> + case HEADER_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + case UNION_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
> + );
> + return EFI_SUCCESS;
> + case ETHERNET_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + default:
> + Status = EFI_UNSUPPORTED;
> + break;
> + }
> + }
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> +
> +**/
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Index;
> + UINT32 Result;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + if (Interface.NumEndpoints == 0 ) {
> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> + }
> +
> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
> + case USB_ENDPOINT_BULK:
> + if (Endpoint.EndpointAddress & BIT7) {
> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
> + } else {
> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
> + }
> +
> + break;
> + case USB_ENDPOINT_INTERRUPT:
> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
> + break;
> + }
> + }
> +}
> +
> +/**
> + Async USB transfer callback routine.
> +
> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
> + transfer completed successfully.
> + @param[in] DataLength The length of Data received or sent via the Asynchronous
> + Transfer, if transfer successfully completes.
> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
> + @param[in] Status Indicates the result of the asynchronous transfer.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + )
> +{
> + if ((Data == NULL) || (Context == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
> + CopyMem (
> + (EFI_USB_DEVICE_REQUEST *)Context,
> + (EFI_USB_DEVICE_REQUEST *)Data,
> + sizeof (EFI_USB_DEVICE_REQUEST)
> + );
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + UINTN DataLength;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + DataLength = 0;
> +
> + if (IsNewTransfer == TRUE) {
> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + PollingInterval,
> + DataLength,
> + InterruptCallback,
> + Requst
> + );
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + // Because of Stacked AsyncInterrupt request are not supported
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + 0,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> + } else {
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function is used to read USB interrupt transfer before the response RNDIS message.
> +
> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
> +
> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadRndisResponseInterrupt (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Data[2];
> + UINT32 UsbStatus;
> + UINTN DataLength;
> +
> + DataLength = 8;
> +
> + ZeroMem (Data, sizeof (Data));
> +
> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + &Data,
> + &DataLength,
> + 0x20,
> + &UsbStatus
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
> + CHAR16 *Data;
> + CHAR16 *DataPtr;
> + CHAR16 TmpStr[1];
> + UINT8 Index;
> + UINT8 Hi;
> + UINT8 Low;
> +
> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
> + }
> +
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
> + // To check USB Ethernet functional Descriptor
> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
> + UsbRndisDevice->UsbIo,
> + 0x409, // English-US Language ID
> + UsbEthDescriptor.MacAddress,
> + &Data
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + DataPtr = Data;
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Hi = (UINT8)StrHexToUintn (TmpStr);
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Low = (UINT8)StrHexToUintn (TmpStr);
> + MacAddress->Addr[Index] = (Hi << 4) | Low;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
> + @retval other Failed to retrieve the bulk transfer data size.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + )
> +{
> + EFI_STATUS Status;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbHeaderFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + HEADER_FUN_DESCRIPTOR,
> + UsbHeaderFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbUnionFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + UNION_FUN_DESCRIPTOR,
> + UsbUnionFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + This function get the Mac Address, Ethernet statistics, maximum segment size,
> + number of multicast filters, and number of pattern filters from Ethernet
> + functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbEthFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + ETHERNET_FUN_DESCRIPTOR,
> + UsbEthFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Value * 6;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + McastAddr,
> + Request.Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Length;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternFilter,
> + Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternActive,
> + USB_ETH_POWER_FILTER_LENGTH,
> + &TransStatus
> + );
> +}
> +
> +/**
> +
> + Converts PXE filter settings to RNDIS values
> +
> + @param[in] Value PXE filter data.
> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
> +
> +**/
> +VOID
> +ConvertFilter (
> + IN UINT16 Value,
> + OUT UINT16 *CdcFilter
> + )
> +{
> + UINT32 Index;
> + UINT32 Count;
> + static struct BIT_MAP Table[] = {
> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
> + };
> +
> + Count = sizeof (Table)/sizeof (Table[0]);
> +
> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
> + if (Table[Index].Src & Value) {
> + *CdcFilter |= Table[Index].Dst;
> + }
> + }
> +}
> +
> +/**
> +
> + Updates Filter settings on the device.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + UINT64 CpbAddr;
> + UINT32 CpbSize;
> + UINT16 SetFilter;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + CpbAddr = Cdb->CPBaddr;
> + CpbSize = Cdb->CPBsize;
> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + } else {
> + Nic->McastCount = 0;
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiStart is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
> +
> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
> + Status = RndisUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiReset (Cdb, Nic);
> + }
> +
> + Status = RndisUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiInitialize (Cdb, Nic);
> + }
> +
> + RndisUndiShutdown (Cdb, Nic);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when Undistop is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiGetInitInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + PXE_DB_GET_INIT_INFO *Db;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
> +
> + UsbEthDevice = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when RndisUndiGetConfigInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiInitialize is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
> +
> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> +
> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
> +
> + UsbRndisDevice->RequestId++;
> +
> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
> + return Status;
> + }
> +
> + // Only Wired Medium is supported
> + if (RndisInitMsgCmplt.Medium) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
> +
> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
> +
> + return Status;
> +}
> +
> +/**
> + This function is called when UndiReset is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
> +
> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
> +
> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
> +
> + UsbRndisDevice->RequestId = 1; // Let's start with 1
> +
> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiShutdown is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
> +
> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + Status = EFI_SUCCESS;
> + }
> +
> + UsbRndisDevice->RequestId = 1;
> + return Status;
> +}
> +
> +/**
> + Update the Media connection.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transmit the data after appending RNDIS header.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
> + if (RndisPacketMsg == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
> +
> + CopyMem (
> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
> + BulkOutData,
> + *DataLength
> + );
> +
> + TransferLength = RndisPacketMsg->MessageLength;
> +
> + Status = RndisTransmitDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
> +
> + FreePool (RndisPacketMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Receives and removes RNDIS header and returns the raw data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
> + @retval EFI_NOT_FOUND No buffer was found in the list.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> + VOID *Buffer;
> + PACKET_LIST *HeadPacket;
> + PACKET_LIST *PacketList;
> +
> + // Check if there is any outstanding packet to receive
> + // The buffer allocated has a linked List followed by the packet.
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + Buffer = NULL;
> + HeadPacket = NULL;
> +
> + while (1) {
> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
> + if (Buffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
> + PacketList = (PACKET_LIST *)Buffer;
> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
> + // Save the original address for freeing it up
> + PacketList->OrgBuffer = (UINT8 *)Buffer;
> + TransferLength = UsbRndisDevice->MaxTransferSize;
> +
> + Status = RndisReceiveDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
> + FreePool (Buffer);
> + break;
> + }
> +
> + // Collect all the RNDIS packet in Linked list.
> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
> + (TransferLength >= RndisPacketMsg->MessageLength))
> + {
> + // Insert Packet
> + PacketList->RemainingLength = TransferLength;
> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
> + } else {
> + FreePool (Buffer);
> + }
> + }
> +
> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
> +
> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
> +
> + // Check whether the packet is valid RNDIS packet.
> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
> + {
> + if (*DataLength >= RndisPacketMsg->DataLength) {
> + CopyMem (
> + BulkInData,
> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
> + RndisPacketMsg->DataLength
> + );
> +
> + *DataLength = RndisPacketMsg->DataLength;
> +
> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
> +
> + return EFI_SUCCESS;
> + } else {
> + *DataLength = RndisPacketMsg->DataLength;
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + }
> +
> + RemoveEntryList (&HeadPacket->PacketList);
> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
> + point to this function.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's control endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> +
> +**/
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + )
> +{
> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
> + EFI_USB_DEVICE_REQUEST DevReq;
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> + UINT32 SaveResponseType;
> + UINT32 SaveResponseLength;
> + UINT32 Index;
> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
> +
> + SaveResponseType = 0;
> + SaveResponseLength = 0;
> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
> +
> + if (RndisMsgResponse) {
> + SaveResponseType = RndisMsgResponse->MessageType;
> + SaveResponseLength = RndisMsgResponse->MessageLength;
> + }
> +
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsg,
> + RndisMsg->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
> +
> + // Error or no response expected
> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
> + return Status;
> + }
> +
> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
> + ReadRndisResponseInterrupt (UsbRndisDevice);
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsgResponse,
> + RndisMsgResponse->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
> +
> + PrintRndisMsg (RndisMsgResponse);
> +
> + if (!EFI_ERROR (Status)) {
> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
> +
> + RndisMsgResponse->MessageType = SaveResponseType;
> + RndisMsgResponse->MessageLength = SaveResponseLength;
> + continue;
> + }
> + }
> +
> + return Status;
> + }
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
> +
> + return EFI_TIMEOUT;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkOutEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_TX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (Status == EFI_SUCCESS) {
> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + UsbStatus = 0;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + // Use gStopBulkInCnt to stop BulkIn command
> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkInEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_RX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + } else {
> + gStopBulkInCnt--;
> + }
> + } else {
> + Status = EFI_TIMEOUT;
> + *TransferLength = 0;
> + gBlockBulkInCnt++;
> + }
> +
> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + gBlockBulkInCnt = 0;
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Prints RNDIS Header and Data
> +
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> +
> +**/
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + )
> +{
> + UINTN Length;
> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
> +
> + Length = 0;
> +
> + switch (RndisMsg->MessageType) {
> + case RNDIS_PACKET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
> + break;
> + case RNDIS_INITIALIZE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + break;
> + case RNDIS_INITIALIZE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> + break;
> + case RNDIS_HLT_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
> + break;
> + case RNDIS_QUERY_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
> + break;
> + case RNDIS_QUERY_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
> + break;
> + case RNDIS_SET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_MSG);
> + break;
> + case RNDIS_SET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
> + break;
> + case RNDIS_RESET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
> + break;
> + case RNDIS_RESET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
> + break;
> + case RNDIS_INDICATE_STATUS_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
> + break;
> + case RNDIS_KEEPALIVE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
> + break;
> + case RNDIS_KEEPALIVE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
> + }
> +
> + if (Length) {
> + UINTN Index = 0;
> + for ( ; Length; Length -= 4, Index++) {
> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
> + if (((Index % 4) == 3) && (Index != 0)) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> +
> + if ((Length < 8) && (Length > 4)) {
> + UINT32 Data32;
> + Index++;
> + Data32 = *((UINT32 *)RndisMsg + Index);
> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
> + break;
> + }
> + }
> +
> + if (Index % 4) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> + }
> +}
> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..cb70684f0bf1
> --- /dev/null
> +++ b/UsbNetworkPkg/ReadMe.md
> @@ -0,0 +1,65 @@
> +# UsbNetworkPkg
> +
> +This document is intend to provide package information, include the interface details.
> +
> +# INDEX
> + * [Introduction](#introduction)
> + * [Components](#components)
> + * [[NetworkCommon]](#networkcommon)
> + * [[UsbCdcEcm]](#usbcdcecm)
> + * [[UsbCdcNcm]](#usbcdcncm)
> + * [[UsbRndis]](#usbrndis)
> +
> +# Introduction
> +UsbNetworkPkg provides network functions for USB LAN devices.
> +
> +# Components
> +Below module is included in this package:<br>
> +- NetworkCommon
> +- UsbCdcEcm
> +- UsbCdcNcm
> +- UsbRndis
> +
> +## [NetworkCommon]
> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
> +
> +## Required Components
> +- NetworkPkg
> +
> +## [UsbCdcEcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x06|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbCdcNcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x0D|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbRndis]
> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x02|0xFF|
> +|0xEF|0x04|0x01|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
> new file mode 100644
> index 000000000000..f8ccccdb0830
> --- /dev/null
> +++ b/UsbNetworkPkg/ReleaseNotes.md
> @@ -0,0 +1,11 @@
> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
> +
> +# Release History<!-- omit in toc -->
> +- [1.00](#100)
> +
> +## 1.00
> +
> +**Release Date:** Mar 10, 2022
> +
> +**New Features**
> +- UsbNetworkPkg first release.
> --
> 2.35.1.windows.2
> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-03-09 7:51 [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
` (3 preceding siblings ...)
2023-03-28 11:40 ` Rebecca Cran
@ 2023-04-07 1:57 ` Rebecca Cran
2023-04-07 2:49 ` RichardHo [何明忠]
4 siblings, 1 reply; 11+ messages in thread
From: Rebecca Cran @ 2023-04-07 1:57 UTC (permalink / raw)
To: Richard Ho (何明忠), devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Tinh Nguyen,
Tony Lo (羅金松)
Your patches are still coming through rather mangled, unfortunately.
You should be sending them as 8bit, not quoted-printable - the
BaseTools/Scripts/SetupGit.py script will configure the settings for you.
Also, there should be a cover letter with the patch series: that script
configures "git format-patch" to generate one.
If you've already run SetupGit.py, could you tell me what .git/config in
your edk2 clone contains, please?
--
Rebecca Cran
On 3/9/23 12:51 AM, Richard Ho (何明忠) wrote:
> This driver provides UEFI driver for USB RNDIS device
>
> Signed-off-by: Richard Ho <richardho@ami.com>
> Cc: Andrew Fish <afish@apple.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
> Reviewed-by: Tony Lo <tonylo@ami.com>
> ---
> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
> UsbNetworkPkg/ReadMe.md | 65 +
> UsbNetworkPkg/ReleaseNotes.md | 11 +
> 18 files changed, 7452 insertions(+)
> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> create mode 100644 UsbNetworkPkg/ReadMe.md
> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>
> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
> new file mode 100644
> index 000000000000..30e4e4c8aac7
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
> @@ -0,0 +1,46 @@
> +## @file
> +# This package defines Usb network specific interfaces and library classes
> +# as well as configuration for standard edk2 packages.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x00010005
> + PACKAGE_NAME = UsbNetworkPkg
> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
> + PACKAGE_VERSION = 0.1
> +
> +[Includes]
> + Include
> +
> +[Protocols]
> + ## Include/Protocol/EdkIIUsbEthernet.h
> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
> +
> +[Guids]
> + ## Usb Network package token space GUID
> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
> +
> +[PcdsFeatureFlag]
> +
> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
> +
> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
> +
> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
> +
> +[PcdsFixedAtBuild, PcdsPatchableInModule]
> + ## Support rate limiting
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
> +
> + ## The rate limiting Credit value is check in rate limiter event.
> + # It is to control the RateLimitingCreditCount max value.
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
> +
> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> new file mode 100644
> index 000000000000..a3316b1d4a89
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> @@ -0,0 +1,9 @@
> +## @file
> +# Global DSC definitions to be included into project DSC file.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Components.X64]
> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> new file mode 100644
> index 000000000000..544df8404c64
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> new file mode 100644
> index 000000000000..85a309bcf567
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> @@ -0,0 +1,23 @@
> +## @file
> +# Global switches enable/disable project features.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
> + DEFINE PEI=IA32
> + DEFINE DXE=X64
> +!else
> + DEFINE PEI=COMMON
> + DEFINE DXE=COMMON
> +!endif
> +
> +[Packages]
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[PcdsFeatureFlag]
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> new file mode 100644
> index 000000000000..10616d97edb4
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> new file mode 100644
> index 000000000000..8923102bc350
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> @@ -0,0 +1,49 @@
> +## @file
> +# This is Usb Network Common driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = NetworkCommon
> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = NetworkCommonEntry
> +
> +[Sources]
> + DriverBinding.c
> + DriverBinding.h
> + ComponentName.c
> + PxeFunction.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Pcd]
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> new file mode 100644
> index 000000000000..64205e427745
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# This is Usb Rndis driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = UsbRndis
> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = UsbRndisEntry
> +
> +[Sources]
> + UsbRndis.c
> + UsbRndis.h
> + UsbRndisFunction.c
> + ComponentName.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> new file mode 100644
> index 000000000000..f54946c7aa69
> --- /dev/null
> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> @@ -0,0 +1,878 @@
> +/** @file
> + Header file contains code for USB Ethernet Protocol
> + definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
> +
> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
> +
> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
> +
> +#define USB_CDC_CLASS 0x02
> +#define USB_CDC_ACM_SUBCLASS 0x02
> +#define USB_CDC_ECM_SUBCLASS 0x06
> +#define USB_CDC_NCM_SUBCLASS 0x0D
> +#define USB_CDC_DATA_CLASS 0x0A
> +#define USB_CDC_DATA_SUBCLASS 0x00
> +#define USB_NO_CLASS_PROTOCOL 0x00
> +#define USB_NCM_NTB_PROTOCOL 0x01
> +#define USB_VENDOR_PROTOCOL 0xFF
> +
> +// Type Values for the DescriptorType Field
> +#define CS_INTERFACE 0x24
> +#define CS_ENDPOINT 0x25
> +
> +// Descriptor SubType in Functional Descriptors
> +#define HEADER_FUN_DESCRIPTOR 0x00
> +#define UNION_FUN_DESCRIPTOR 0x06
> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
> +
> +#define MAX_LAN_INTERFACE 0x10
> +
> +// Table 20: Class-Specific Notification Codes
> +#define USB_CDC_NETWORK_CONNECTION 0x00
> +
> +// 6.3.1 NetworkConnection
> +#define NETWORK_CONNECTED 0x01
> +#define NETWORK_DISCONNECT 0x00
> +
> +// USB Header functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT16 BcdCdc;
> +} USB_HEADER_FUN_DESCRIPTOR;
> +
> +// USB Union Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MasterInterface;
> + UINT8 SlaveInterface;
> +} USB_UNION_FUN_DESCRIPTOR;
> +
> +// USB Ethernet Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MacAddress;
> + UINT32 EthernetStatistics;
> + UINT16 MaxSegmentSize;
> + UINT16 NumberMcFilters;
> + UINT8 NumberPowerFilters;
> +} USB_ETHERNET_FUN_DESCRIPTOR;
> +
> +typedef struct {
> + UINT32 UsBitRate;
> + UINT32 DsBitRate;
> +} USB_CONNECT_SPEED_CHANGE;
> +
> +// Request Type Codes for USB Ethernet
> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
> +
> +// Class-Specific Request Codes for Ethernet subclass
> +// USB ECM 1.2 specification, Section 6.2
> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
> +#define SET_ETH_PACKET_FILTER_REQ 0x43
> +#define GET_ETH_STATISTIC_REQ 0x44
> +
> +// USB ECM command request length
> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
> +
> +// USB Ethernet Packet Filter Bitmap
> +// USB ECM 1.2 specification, Section 6.2.4
> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
> +
> +// USB Ethernet Statistics Feature Selector Codes
> +// USB ECM 1.2 specification, Section 6.2.5
> +#define USB_ETH_XMIT_OK 0x01
> +#define USB_ETH_RCV_OK 0x02
> +#define USB_ETH_XMIT_ERROR 0x03
> +#define USB_ETH_RCV_ERROR 0x04
> +#define USB_ETH_RCV_NO_BUFFER 0x05
> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
> +#define USB_ETH_RCV_CRC_ERROR 0x12
> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
> +#define USB_ETH_XMIT_DEFERRED 0x17
> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
> +#define USB_ETH_RCV_OVERRUN 0x19
> +#define USB_ETH_XMIT_UNDERRUN 0x1A
> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
> +
> +// NIC Information
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + UINT16 InterrupOpFlag;
> + UINT64 MappedAddr;
> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
> + UINT8 McastCount;
> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
> + UINT8 TxBufferCount;
> + UINT16 State;
> + BOOLEAN CanTransmit;
> + UINT16 ReceiveStatus;
> + UINT8 RxFilter;
> + UINT32 RxFrame;
> + UINT32 TxFrame;
> + UINT16 NetworkConnect;
> + UINT8 CableDetect;
> + UINT16 MaxSegmentSize;
> + EFI_MAC_ADDRESS MacAddr;
> + PXE_CPB_START_31 PxeStart;
> + PXE_CPB_INITIALIZE PxeInit;
> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
> + EFI_USB_DEVICE_REQUEST Request;
> + EFI_EVENT RateLimiter;
> + UINT32 RateLimitingCredit;
> + UINT32 RateLimitingCreditCount;
> + UINT32 RateLimitingPollTimer;
> + BOOLEAN RateLimitingEnable;
> +} NIC_DATA;
> +
> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Request
> + );
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + );
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + );
> +
> +typedef struct {
> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
> +} EDKII_USB_ETHERNET_UNDI;
> +
> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
> +// descriptor and specific requests.
> +struct _EDKII_USB_ETHERNET_PROTOCOL {
> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
> + // for calling the UNDI child functions
> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
> +};
> +
> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> new file mode 100644
> index 000000000000..0416ce132302
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> @@ -0,0 +1,266 @@
> +/** @file
> + Header file for for USB network common driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _DRIVER_BINDING_H_
> +#define _DRIVER_BINDING_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/NetworkInterfaceIdentifier.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +#define NETWORK_COMMON_DRIVER_VERSION 1
> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
> +#define RX_BUFFER_COUNT 32
> +#define TX_BUFFER_COUNT 32
> +#define MEMORY_REQUIRE 0
> +
> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
> + UINT16 Protocol;
> +} EthernetHeader;
> +#pragma pack()
> +
> +typedef struct {
> + UINTN Signature;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
> + EFI_HANDLE DeviceHandle;
> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + NIC_DATA NicInfo;
> + VOID *ReceiveBuffer;
> +} NIC_DEVICE;
> +
> +typedef VOID (*API_FUNC)(
> + PXE_CDB *,
> + NIC_DATA *
> + );
> +
> +extern PXE_SW_UNDI *gPxe;
> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + );
> +
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + );
> +
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + );
> +
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + );
> +
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + );
> +
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + );
> +
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +#endif
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> new file mode 100644
> index 000000000000..775807042460
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> @@ -0,0 +1,586 @@
> +/** @file
> + Header file for for USB Rndis driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _USB_RNDIS_H_
> +#define _USB_RNDIS_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
> + EFI_HANDLE UsbCdcDataHandle;
> + EFI_HANDLE UsbRndisHandle;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
> + EFI_USB_CONFIG_DESCRIPTOR *Config;
> + UINT8 NumOfInterface;
> + UINT8 BulkInEndpoint;
> + UINT8 BulkOutEndpoint;
> + UINT8 InterrupEndpoint;
> + EFI_MAC_ADDRESS MacAddress;
> + UINT32 RequestId;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + LIST_ENTRY ReceivePacketList;
> +} USB_RNDIS_DEVICE;
> +
> +#define USB_RNDIS_DRIVER_VERSION 1
> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
> +
> +#define LAN_BULKIN_CMD_CONTROL 1
> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
> +#define RNDIS_RESERVED_BYTE_LENGTH 8
> +
> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
> +
> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
> +
> +struct BIT_MAP {
> + unsigned int Src;
> + unsigned int Dst;
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + );
> +
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + );
> +
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + );
> +
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN BOOLEAN *PatternActive
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *Statistic
> + );
> +
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + );
> +
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + );
> +
> +#define RNDIS_MAJOR_VERSION 0x00000001
> +#define RNDIS_MINOR_VERSION 0x00000000
> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
> +
> +#define RNDIS_PACKET_MSG 0x00000001
> +#define RNDIS_INITIALIZE_MSG 0x00000002
> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
> +#define RNDIS_HLT_MSG 0x00000003
> +#define RNDIS_QUERY_MSG 0x00000004
> +#define RNDIS_QUERY_CMPLT 0x80000004
> +#define RNDIS_SET_MSG 0x00000005
> +#define RNDIS_SET_CMPLT 0x80000005
> +#define RNDIS_RESET_MSG 0x00000006
> +#define RNDIS_RESET_CMPLT 0x80000006
> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
> +#define RNDIS_KEEPALIVE_MSG 0x00000008
> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
> +
> +#define RNDIS_STATUS_SUCCESS 0x00000000
> +#define RNDIS_STATUS_FAILURE 0xC0000001
> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
> +
> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
> +
> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
> +
> +//
> +// General Objects
> +//
> +// Taken from NTDDNDIS.H
> +#define OID_GEN_SUPPORTED_LIST 0x00010101
> +#define OID_GEN_HARDWARE_STATUS 0x00010102
> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
> +#define OID_GEN_MEDIA_IN_USE 0x00010104
> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
> +#define OID_GEN_LINK_SPEED 0x00010107
> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
> +#define OID_GEN_VENDOR_ID 0x0001010C
> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
> +#define OID_GEN_DRIVER_VERSION 0x00010110
> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
> +#define OID_GEN_MAC_OPTIONS 0x00010113
> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
> +
> +#define OID_GEN_XMIT_OK 0x00020101
> +#define OID_GEN_RCV_OK 0x00020102
> +#define OID_GEN_XMIT_ERROR 0x00020103
> +#define OID_GEN_RCV_ERROR 0x00020104
> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
> +
> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
> +
> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
> +//
> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
> +//
> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
> +#define NDIS_PACKET_TYPE_SMT 0x0040
> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
> +#define NDIS_PACKET_TYPE_GROUP 0x1000
> +
> +#pragma pack(1)
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> +} REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 MaxTransferSize;
> +} REMOTE_NDIS_INITIALIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_HALT_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_QUERY_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_SET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Reserved;
> +} REMOTE_NDIS_RESET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 StatusBufferLength;
> + UINT32 StatusBufferOffset;
> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
> +
> +typedef struct {
> + UINT32 DiagStatus;
> + UINT32 ErrorOffset;
> +} RNDIS_DIAGNOSTIC_INFO;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_KEEPALIVE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 DeviceFlags;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + UINT64 Reserved;
> +} REMOTE_NDIS_INITIALIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> +} REMOTE_NDIS_QUERY_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_SET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 AddressingReset;
> +} REMOTE_NDIS_RESET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 DataOffset;
> + UINT32 DataLength;
> + UINT32 OutOfBandDataOffset;
> + UINT32 OutOfBandDataLength;
> + UINT32 NumOutOfBandDataElements;
> + UINT32 PerPacketInfoOffset;
> + UINT32 PerPacketInfoLength;
> + UINT32 Reserved1;
> + UINT32 Reserved2;
> +} REMOTE_NDIS_PACKET_MSG;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} OUT_OF_BAND_DATA_RECORD;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} PER_PACKET_INFO_DATA_RECORD;
> +
> +typedef struct {
> + LIST_ENTRY PacketList;
> + UINT8 *OrgBuffer;
> + UINTN RemainingLength;
> + UINT8 *PacketStartBuffer; // Variable size data to follow
> +} PACKET_LIST;
> +
> +#pragma pack()
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> new file mode 100644
> index 000000000000..e83469e13079
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> @@ -0,0 +1,263 @@
> +/** @file
> + This file contains code for USB network common driver
> + component name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
> + {
> + "eng;en",
> + L"Network Common Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
> + NetworkCommonComponentNameGetDriverName,
> + NetworkCommonComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> + CHAR16 *HandleName;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
> +
> + if (!Language || !ControllerName) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (ChildHandle == NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Make sure this driver is currently managing ControllerHandle
> + //
> + Status = EfiTestManagedDevice (
> + Controller,
> + gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Make sure this driver produced ChildHandle
> + //
> + Status = EfiTestChildHandle (
> + Controller,
> + ChildHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
> +
> + if (!EFI_ERROR (Status)) {
> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *ControllerName = HandleName;
> +
> + if (gNetworkCommonControllerNameTable != NULL) {
> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
> + gNetworkCommonControllerNameTable = NULL;
> + }
> +
> + Status = AddUnicodeString2 (
> + "eng",
> + gNetworkCommonComponentName.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + TRUE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = AddUnicodeString2 (
> + "en",
> + gNetworkCommonComponentName2.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + FALSE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> new file mode 100644
> index 000000000000..23b791362091
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> @@ -0,0 +1,595 @@
> +/** @file
> + This file contains code for USB network binding driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +PXE_SW_UNDI *gPxe = NULL;
> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +UINT32 gRateLimitingCredit;
> +UINT32 gRateLimitingPollTimer;
> +BOOLEAN gRateLimitingEnable;
> +
> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
> + NetworkCommonSupported,
> + NetworkCommonDriverStart,
> + NetworkCommonDriverStop,
> + NETWORK_COMMON_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Create MAC Device Path
> +
> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
> + @retval EFI_SUCCESS MAC device path created successfully.
> +
> +**/
> +EFI_STATUS
> +CreateMacDevicePath (
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + MAC_ADDR_DEVICE_PATH MacAddrNode;
> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
> + UINT8 *DevicePath;
> + UINT16 TotalLength;
> + UINT16 BaseLength;
> +
> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
> +
> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
> + MacAddrNode.Header.Length[1] = 0;
> +
> + EndNode = BaseDev;
> +
> + while (!IsDevicePathEnd (EndNode)) {
> + EndNode = NextDevicePathNode (EndNode);
> + }
> +
> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
> + DevicePath += BaseLength;
> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
> + DevicePath += sizeof (MacAddrNode);
> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Network Common Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + EFI_MAC_ADDRESS MacAddress;
> + UINTN BulkDataSize;
> + NIC_DEVICE *NicDevice;
> + UINT8 *TmpPxePointer;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
> +
> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
> + ASSERT_EFI_ERROR (Status);
> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
> + if (!NicDevice) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + // for alignment adjustment
> + if (gPxe == NULL) {
> + TmpPxePointer = NULL;
> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
> + if (!TmpPxePointer) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + return EFI_OUT_OF_RESOURCES;
> + } else {
> + // check for paragraph alignment here
> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
> + } else {
> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
> + }
> +
> + if (!gPxe) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PxeStructInit (gPxe);
> + }
> + }
> +
> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
> +
> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
> +
> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
> +
> + NicDevice->NicInfo.UsbEth = UsbEth;
> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
> + NicDevice->NicInfo.CableDetect = 0;
> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
> +
> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
> +
> + NicDevice->NicInfo.TxBufferCount = 0;
> +
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
> + } else {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = CreateMacDevicePath (
> + &NicDevice->DevPath,
> + UsbEthPath,
> + &NicDevice->NicInfo
> + );
> +
> + if (EFI_ERROR (Status)) {
> + UpdateNicNum (NULL, gPxe);
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> + }
> +
> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
> + NicDevice->NiiProtocol.ImageSize = 0;
> + NicDevice->NiiProtocol.ImageAddr = 0;
> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
> +
> + NicDevice->NiiProtocol.StringId[0] = 'U';
> + NicDevice->NiiProtocol.StringId[1] = 'N';
> + NicDevice->NiiProtocol.StringId[2] = 'D';
> + NicDevice->NiiProtocol.StringId[3] = 'I';
> + NicDevice->DeviceHandle = NULL;
> +
> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
> + NicDevice->NicInfo.RateLimiter = NULL;
> +
> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &NicDevice->DeviceHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice->DevPath != NULL) {
> + FreePool (NicDevice->DevPath);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + NicDevice->DeviceHandle,
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AllChildrenStopped;
> + UINTN Index;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + NIC_DEVICE *NicDevice;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
> +
> + if (NumberOfChildren == 0) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + AllChildrenStopped = TRUE;
> +
> + for (Index = 0; Index < NumberOfChildren; Index++) {
> + Status = gBS->OpenProtocol (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + AllChildrenStopped = FALSE;
> + continue;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index]
> + );
> +
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index],
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> + } else {
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> + }
> + }
> +
> + if (!AllChildrenStopped) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Entrypoint of Network Common Driver.
> +
> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gNetworkCommonDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gNetworkCommonComponentName2,
> + NULL
> + );
> + return Status;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> new file mode 100644
> index 000000000000..687cabca4ce3
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> @@ -0,0 +1,1803 @@
> +/** @file
> + This file contains code for UNDI command based on UEFI specification.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +// API table, defined in UEFI specification
> +API_FUNC gUndiApiTable[] = {
> + UndiGetState,
> + UndiStart,
> + UndiStop,
> + UndiGetInitInfo,
> + UndiGetConfigInfo,
> + UndiInitialize,
> + UndiReset,
> + UndiShutdown,
> + UndiInterruptEnable,
> + UndiReceiveFilter,
> + UndiStationAddress,
> + UndiStatistics,
> + UndiMcastIp2Mac,
> + UndiNvData,
> + UndiGetStatus,
> + UndiFillHeader,
> + UndiTransmit,
> + UndiReceive
> +};
> +
> +/**
> + Callback function for enable Rate Limiter
> +
> + @param[in] Event Event whose notification function is being invoked
> + @param[in] Context Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +UndiRateLimiterCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + NIC_DATA *Nic = Context;
> +
> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
> + Nic->RateLimitingCreditCount++;
> + }
> +}
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_START_31 *Cpb;
> + EFI_STATUS Status;
> + BOOLEAN EventError;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
> +
> + Nic->PxeStart.Delay = Cpb->Delay;
> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
> + Nic->PxeStart.Block = Cpb->Block;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
> + EventError = FALSE;
> + Status = EFI_SUCCESS;
> + if (Nic->RateLimitingEnable == TRUE) {
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + UndiRateLimiterCallback,
> + Nic,
> + &Nic->RateLimiter
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = gBS->SetTimer (
> + Nic->RateLimiter,
> + TimerPeriodic,
> + Nic->RateLimitingPollTimer * 10000
> + );
> + if (EFI_ERROR (Status)) {
> + EventError = TRUE;
> + }
> + }
> + }
> +
> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + // Initial the state for UNDI start.
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + } else {
> + if (Nic->RateLimitingEnable == TRUE) {
> + if (!EventError) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + }
> +
> + if (Nic->RateLimiter) {
> + gBS->CloseEvent (&Nic->RateLimiter);
> + Nic->RateLimiter = 0;
> + }
> + }
> +
> + // Initial the state when UNDI start is fail
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
> + return;
> + }
> +
> + Nic->PxeStart.Delay = 0;
> + Nic->PxeStart.Virt2Phys = 0;
> + Nic->PxeStart.Block = 0;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = 0;
> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
> +
> + if (Nic->RateLimitingEnable == TRUE) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + gBS->CloseEvent (&Nic->RateLimiter);
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_INIT_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->MemoryRequired = MEMORY_REQUIRE;
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + Db->LinkSpeeds[0] = 10;
> + Db->LinkSpeeds[1] = 100;
> + Db->LinkSpeeds[2] = 1000;
> + Db->LinkSpeeds[3] = 0;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> + Db->IFtype = PXE_IFTYPE_ETHERNET;
> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
> +
> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_CONFIG_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->pci.BusType = PXE_BUSTYPE_USB;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_INITIALIZE *Cpb;
> + PXE_DB_INITIALIZE *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
> +
> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
> +
> + Cdb->StatCode = Initialize (Cdb, Nic);
> +
> + Db->MemoryUsed = MEMORY_REQUIRE;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> +
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + Nic->CanTransmit = FALSE;
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
> + }
> + }
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Initialize Network interface controller data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval Status A value of Pxe statcode.
> +
> +**/
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + UINTN Status;
> + UINT32 Index;
> + EFI_STATUS EfiStatus;
> +
> + Status = MapIt (
> + Nic,
> + Nic->PxeInit.MemoryAddr,
> + Nic->PxeInit.MemoryLength,
> + TO_AND_FROM_DEVICE,
> + (UINT64)(UINTN)&Nic->MappedAddr
> + );
> +
> + if (Status != 0) {
> + return (UINT16)Status;
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->BroadcastNodeAddress[Index] = 0xFF;
> + }
> +
> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = 0;
> + Nic->PermNodeAddress[Index] = 0;
> + Nic->BroadcastNodeAddress[Index] = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
> + if (EFI_ERROR (EfiStatus)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return (UINT16)Status;
> +}
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
> + Nic->InterrupOpFlag = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Nic->CanTransmit = FALSE;
> +
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + UINT16 NewFilter;
> + PXE_DB_RECEIVE_FILTERS *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> +
> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
> + if ((Cdb->DBsize != 0)) {
> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
> + }
> + }
> +
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
> + if (NewFilter == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Cdb->CPBsize != 0) {
> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if ((Cdb->CPBsize == 0)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + break;
> +
> + default:
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Set PXE receive filter.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] SetFilter PXE receive filter
> + @param[in] CpbAddr Command Parameter Block Address
> + @param[in] CpbSize Command Parameter Block Size
> +
> +**/
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_STATION_ADDRESS *Cpb;
> + PXE_DB_STATION_ADDRESS *Db;
> + UINT16 Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> + }
> +
> + if (Cdb->CPBaddr != 0) {
> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
> + }
> + }
> +
> + if (Cdb->DBaddr != 0) {
> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Return data for DB data.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> +**/
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + )
> +{
> + PXE_DB_STATISTICS *DbStatistic;
> + EFI_STATUS Status;
> +
> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
> +
> + if (DbSize == 0) {
> + return PXE_STATCODE_SUCCESS;
> + }
> +
> + DbStatistic->Supported = 0x802;
> + DbStatistic->Data[0x01] = Nic->RxFrame;
> + DbStatistic->Data[0x0B] = Nic->TxFrame;
> +
> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in, out] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
> + PXE_DB_MCAST_IP_TO_MAC *Db;
> + UINT8 *Tmp;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + return;
> + }
> +
> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
> +
> + if ((Tmp[0] & 0xF0) != 0xE0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
> + }
> +
> + Db->MAC[0] = 0x01;
> + Db->MAC[1] = 0x00;
> + Db->MAC[2] = 0x5E;
> + Db->MAC[3] = Tmp[1] & 0x7F;
> + Db->MAC[4] = Tmp[2];
> + Db->MAC[5] = Tmp[3];
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_STATUS *Db;
> + PXE_DB_GET_STATUS TmpGetStatus;
> + UINT16 NumEntries;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + TmpGetStatus.RxFrameLen = 0;
> + TmpGetStatus.reserved = 0;
> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
> + } else {
> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
> + if (Cdb->DBsize == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + NumEntries = Cdb->DBsize - sizeof (UINT64);
> + Cdb->DBsize = sizeof (UINT32) * 2;
> +
> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
> + if (Nic->TxBufferCount > 0) {
> + Nic->TxBufferCount--;
> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
> + }
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
> + if (Nic->ReceiveStatus != 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
> + }
> + }
> +
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_FILL_HEADER *CpbFillHeader;
> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
> + EthernetHeader *MacHeader;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
> +
> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
> + MacHeader->Protocol = CpbFill->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
> + }
> + } else {
> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
> + MacHeader->Protocol = CpbFillHeader->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk out command to transmit data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in] OpFlags Operation Flags.
> +
> +**/
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + )
> +{
> + EFI_STATUS Status;
> + PXE_CPB_TRANSMIT *Cpb;
> + UINT64 BulkOutData;
> + UINTN DataLength;
> + UINTN TransmitLength;
> + UINTN Map;
> + UINT32 Counter;
> + UINT16 StatCode;
> +
> + BulkOutData = 0;
> + Counter = 0;
> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
> +
> + if (Nic->CanTransmit) {
> + return PXE_STATCODE_BUSY;
> + }
> +
> + Nic->CanTransmit = TRUE;
> +
> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + Map = MapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + (UINT64)(UINTN)&BulkOutData
> + );
> +
> + if (Map != 0) {
> + Nic->CanTransmit = FALSE;
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
> + Nic->TxBufferCount++;
> + }
> +
> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
> +
> + while (1) {
> + if (Counter >= 3) {
> + StatCode = PXE_STATCODE_BUSY;
> + break;
> + }
> +
> + TransmitLength = DataLength;
> +
> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
> + if (EFI_ERROR (Status)) {
> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
> + break;
> + }
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + break;
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + Nic->TxFrame++;
> + StatCode = PXE_STATCODE_SUCCESS;
> + break;
> + }
> +
> + Counter++;
> + }
> +
> + UnMapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + BulkOutData
> + );
> +
> + Nic->CanTransmit = FALSE;
> +
> + return StatCode;
> +}
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk in command to receive data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in, out] DbAddr Data Block Address.
> +
> +**/
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + PXE_FRAME_TYPE FrameType;
> + PXE_CPB_RECEIVE *Cpb;
> + PXE_DB_RECEIVE *Db;
> + NIC_DEVICE *NicDevice;
> + UINT8 *BulkInData;
> + UINTN DataLength;
> + EthernetHeader *Header;
> + EFI_TPL OriginalTpl;
> +
> + FrameType = PXE_FRAME_TYPE_NONE;
> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
> + BulkInData = NicDevice->ReceiveBuffer;
> + DataLength = (UINTN)Nic->MaxSegmentSize;
> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
> +
> + if (!BulkInData) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
> + if (EFI_ERROR (Status)) {
> + Nic->ReceiveStatus = 0;
> + if (Nic->RateLimitingEnable == TRUE) {
> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + if (Nic->RateLimitingCreditCount != 0) {
> + Nic->RateLimitingCreditCount--;
> + }
> +
> + gBS->RestoreTPL (OriginalTpl);
> + }
> +
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Nic->RxFrame++;
> +
> + if (DataLength != 0) {
> + if (DataLength > Cpb->BufferLen) {
> + DataLength = (UINTN)Cpb->BufferLen;
> + }
> +
> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
> +
> + Header = (EthernetHeader *)BulkInData;
> +
> + Db->FrameLen = (UINT32)DataLength;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_UNICAST;
> + } else {
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_BROADCAST;
> + } else {
> + if ((Header->DestAddr[0] & 1) == 1) {
> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
> + } else {
> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
> + }
> + }
> + }
> +
> + Db->Type = FrameType;
> + Db->Protocol = Header->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
> + Db->DestAddr[Index] = Header->DestAddr[Index];
> + }
> + }
> +
> + if (FrameType == PXE_FRAME_TYPE_NONE) {
> + Nic->ReceiveStatus = 0;
> + } else {
> + Nic->ReceiveStatus = 1;
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Fill out PXE SW UNDI structure.
> +
> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
> + PxeSw->Fudge = 0;
> + PxeSw->IFcnt = 0;
> + PxeSw->IFcntExt = 0;
> + PxeSw->Rev = PXE_ROMID_REV;
> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
> + PxeSw->reserved1 = 0;
> +
> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
> + PXE_ROMID_IMP_FRAG_SUPPORTED |
> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
> +
> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
> + PxeSw->reserved2[0] = 0;
> + PxeSw->reserved2[1] = 0;
> + PxeSw->reserved2[2] = 0;
> + PxeSw->BusCnt = 1;
> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
> +}
> +
> +/**
> + Update NIC number.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + UINT16 NicNum;
> +
> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
> +
> + if (Nic == NULL) {
> + if (NicNum > 0) {
> + NicNum--;
> + }
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> + return;
> + }
> +
> + NicNum++;
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> +}
> +
> +/**
> + UNDI API table entry.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + )
> +{
> + PXE_CDB *CdbPtr;
> + NIC_DATA *Nic;
> +
> + if (Cdb == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Map virtual memory address for DMA. This field can be set to
> + zero if there is no mapping service.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[out] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + )
> +{
> + UINT64 *PhyAddr;
> +
> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
> +
> + if (Nic->PxeStart.Map_Mem == 0) {
> + *PhyAddr = MemAddr;
> + } else {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Un-map previously mapped virtual memory address. This field can be set
> + to zero only if the Map_Mem() service is also set to zero.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[in] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + )
> +{
> + if (Nic->PxeStart.UnMap_Mem != 0) {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
> new file mode 100644
> index 000000000000..b9ba170c135b
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
> @@ -0,0 +1,172 @@
> +/** @file
> + This file contains code for USB RNDIS Driver Component
> + Name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
> + {
> + "eng;en",
> + L"USB RNDIS Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
> + UsbRndisComponentNameGetDriverName,
> + UsbRndisComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gUsbRndisDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gUsbRndisComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> new file mode 100644
> index 000000000000..92830771e408
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> @@ -0,0 +1,886 @@
> +/** @file
> + This file contains code for USB Remote Network Driver
> + Interface Spec. Driver Binding
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
> + UsbRndisDriverSupported,
> + UsbRndisDriverStart,
> + UsbRndisDriverStop,
> + USB_RNDIS_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Check if this interface is USB Rndis SubType
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +
> +**/
> +BOOLEAN
> +IsSupportedDevice (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if this interface is USB Rndis SubType but not CDC Data interface
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +**/
> +BOOLEAN
> +IsRndisInterface (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
> +
> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> +
> + @retval EFI_SUCCESS Is the same device.
> + @retval EFI_UNSUPPORTED Is not the same device.
> +
> +**/
> +EFI_STATUS
> +IsSameDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
> + )
> +{
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
> + while (1) {
> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
> + {
> + return EFI_SUCCESS;
> + } else {
> + return EFI_UNSUPPORTED;
> + }
> + } else {
> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
> + }
> + }
> +
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
> +}
> +
> +/**
> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB CDC Data(UsbIo) installed.
> + @retval FALSE USB CDC Data(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbCdcData (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for CDC-DATA
> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB Rndis(UsbIo) installed
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis(UsbIo) installed.
> + @retval FALSE USB Rndis(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbRndis (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for Rndis
> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
> + For one device two USBIO will be installed each for CDC and RNDIS interface.
> +
> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +UpdateRndisDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + BOOLEAN IsRndisInterfaceFlag;
> +
> + IsRndisInterfaceFlag = FALSE;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEdkIIUsbEthProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthDevice
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
> + if (IsRndisInterfaceFlag == FALSE) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> +
> + if (!EFI_ERROR (Status)) {
> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> + FreePool (HandleBuffer);
> + return EFI_SUCCESS;
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> +
> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
> + and UsbIO protocol.
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
> +
> +**/
> +VOID
> +FindMatchingCdcData (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + UsbRndisDevice->UsbRndisHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
> + FreePool (HandleBuffer);
> + return;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> + if (!EFI_ERROR (Status)) {
> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + FreePool (HandleBuffer);
> + return;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +}
> +
> +/**
> +
> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
> +
> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FindMatchingRndisDev (
> + IN EFI_HANDLE CdcHandle,
> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
> + OUT EFI_HANDLE *RndisHandle
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + CdcHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
> + break;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + if (!EFI_ERROR (Status)) {
> + *RndisHandle = HandleBuffer[Index];
> + *CdcUsbIo = UsbIo;
> + FreePool (HandleBuffer);
> + return Status;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + USB Rndis Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + USB RNDIS Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_HANDLE RndisHandle;
> +
> + RndisHandle = ControllerHandle;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = UpdateRndisDevice (
> + UsbEthPath,
> + &UsbRndisDevice
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + return Status;
> + } else {
> + // Check if RnDis exist
> + Status = FindMatchingRndisDev (
> + ControllerHandle,
> + &UsbIo,
> + &RndisHandle
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> + }
> + }
> +
> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
> +
> + if (!UsbRndisDevice) {
> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Status = LoadAllDescriptor (
> + UsbIo,
> + &UsbRndisDevice->Config
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (
> + UsbIo,
> + &Interface
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
> + UsbRndisDevice->UsbCdcDataHandle = 0;
> + UsbRndisDevice->UsbIo = UsbIo;
> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
> +
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
> +
> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
> + UsbRndisDevice->PacketAlignmentFactor = 0;
> +
> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
> +
> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
> + FindMatchingCdcData (UsbRndisDevice);
> +
> + if (UsbRndisDevice->UsbIoCdcData) {
> + Status = gBS->InstallProtocolInterface (
> + &ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &(UsbRndisDevice->UsbEth)
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
> + return EFI_SUCCESS;
> + }
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + CheckandStopRndisDevice
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> +
> + @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
> +CheckandStopRndisDevice (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
> + return Status;
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + USB Rndis Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = CheckandStopRndisDevice (This, ControllerHandle);
> + return Status;
> + }
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
> +
> + Status = gBS->CloseProtocol (
> + UsbRndisDevice->UsbCdcDataHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + UsbRndisDevice->UsbCdcDataHandle
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
> + }
> +
> + Status = gBS->UninstallProtocolInterface (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + UsbEthProtocol
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Entrypoint of RNDIS Driver.
> +
> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
> +
> + return gBS->InstallMultipleProtocolInterfaces (
> + &gUsbRndisDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gUsbRndisDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gUsbRndisComponentName2,
> + NULL
> + );
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> new file mode 100644
> index 000000000000..e3fe737cdef1
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> @@ -0,0 +1,1718 @@
> +/** @file
> + This file contains code for USB Ethernet descriptor
> + and specific requests implement.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +UINT16 gStopBulkInCnt = 0;
> +UINT16 gBlockBulkInCnt = 0;
> +
> +/**
> + Load All of device descriptor.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[out] ConfigDesc A pointer to the configuration descriptor.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
> + buffer specified by DescriptorLength and Descriptor
> + is not large enough to hold the result of the request.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
> + status is returned in Status.
> +**/
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 TransStatus;
> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
> +
> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = gBS->AllocatePool (
> + EfiBootServicesData,
> + Tmp.TotalLength,
> + (VOID **)ConfigDesc
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbGetDescriptor (
> + UsbIo,
> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
> + 0,
> + Tmp.TotalLength,
> + *ConfigDesc,
> + &TransStatus
> + );
> + return Status;
> +}
> +
> +/**
> + Returns pointer to the next descriptor for the pack of USB descriptors
> + located in continues memory segment
> +
> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
> + @param[in, out] Offset A pointer to the sum of descriptor length.
> +
> + @retval TRUE The request executed successfully.
> + @retval FALSE No next descriptor.
> +
> +**/
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + )
> +{
> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
> + return FALSE;
> + }
> +
> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
> + return FALSE;
> + }
> +
> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
> + if ( *Offset >= Desc->TotalLength ) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Read Function descriptor
> +
> + @param[in] Config A pointer to all of configuration.
> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
> +
> + @retval EFI_SUCCESS The device capability descriptor was retrieved
> + successfully.
> + @retval EFI_UNSUPPORTED No supported.
> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Offset;
> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
> +
> + Status = EFI_NOT_FOUND;
> +
> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
> + if (Interface->DescriptorType == CS_INTERFACE) {
> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
> + switch (FunDescriptorType) {
> + case HEADER_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + case UNION_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
> + );
> + return EFI_SUCCESS;
> + case ETHERNET_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + default:
> + Status = EFI_UNSUPPORTED;
> + break;
> + }
> + }
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> +
> +**/
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Index;
> + UINT32 Result;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + if (Interface.NumEndpoints == 0 ) {
> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> + }
> +
> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
> + case USB_ENDPOINT_BULK:
> + if (Endpoint.EndpointAddress & BIT7) {
> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
> + } else {
> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
> + }
> +
> + break;
> + case USB_ENDPOINT_INTERRUPT:
> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
> + break;
> + }
> + }
> +}
> +
> +/**
> + Async USB transfer callback routine.
> +
> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
> + transfer completed successfully.
> + @param[in] DataLength The length of Data received or sent via the Asynchronous
> + Transfer, if transfer successfully completes.
> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
> + @param[in] Status Indicates the result of the asynchronous transfer.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + )
> +{
> + if ((Data == NULL) || (Context == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
> + CopyMem (
> + (EFI_USB_DEVICE_REQUEST *)Context,
> + (EFI_USB_DEVICE_REQUEST *)Data,
> + sizeof (EFI_USB_DEVICE_REQUEST)
> + );
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + UINTN DataLength;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + DataLength = 0;
> +
> + if (IsNewTransfer == TRUE) {
> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + PollingInterval,
> + DataLength,
> + InterruptCallback,
> + Requst
> + );
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + // Because of Stacked AsyncInterrupt request are not supported
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + 0,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> + } else {
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function is used to read USB interrupt transfer before the response RNDIS message.
> +
> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
> +
> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadRndisResponseInterrupt (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Data[2];
> + UINT32 UsbStatus;
> + UINTN DataLength;
> +
> + DataLength = 8;
> +
> + ZeroMem (Data, sizeof (Data));
> +
> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + &Data,
> + &DataLength,
> + 0x20,
> + &UsbStatus
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
> + CHAR16 *Data;
> + CHAR16 *DataPtr;
> + CHAR16 TmpStr[1];
> + UINT8 Index;
> + UINT8 Hi;
> + UINT8 Low;
> +
> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
> + }
> +
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
> + // To check USB Ethernet functional Descriptor
> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
> + UsbRndisDevice->UsbIo,
> + 0x409, // English-US Language ID
> + UsbEthDescriptor.MacAddress,
> + &Data
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + DataPtr = Data;
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Hi = (UINT8)StrHexToUintn (TmpStr);
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Low = (UINT8)StrHexToUintn (TmpStr);
> + MacAddress->Addr[Index] = (Hi << 4) | Low;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
> + @retval other Failed to retrieve the bulk transfer data size.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + )
> +{
> + EFI_STATUS Status;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbHeaderFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + HEADER_FUN_DESCRIPTOR,
> + UsbHeaderFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbUnionFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + UNION_FUN_DESCRIPTOR,
> + UsbUnionFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + This function get the Mac Address, Ethernet statistics, maximum segment size,
> + number of multicast filters, and number of pattern filters from Ethernet
> + functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbEthFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + ETHERNET_FUN_DESCRIPTOR,
> + UsbEthFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Value * 6;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + McastAddr,
> + Request.Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Length;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternFilter,
> + Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternActive,
> + USB_ETH_POWER_FILTER_LENGTH,
> + &TransStatus
> + );
> +}
> +
> +/**
> +
> + Converts PXE filter settings to RNDIS values
> +
> + @param[in] Value PXE filter data.
> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
> +
> +**/
> +VOID
> +ConvertFilter (
> + IN UINT16 Value,
> + OUT UINT16 *CdcFilter
> + )
> +{
> + UINT32 Index;
> + UINT32 Count;
> + static struct BIT_MAP Table[] = {
> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
> + };
> +
> + Count = sizeof (Table)/sizeof (Table[0]);
> +
> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
> + if (Table[Index].Src & Value) {
> + *CdcFilter |= Table[Index].Dst;
> + }
> + }
> +}
> +
> +/**
> +
> + Updates Filter settings on the device.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + UINT64 CpbAddr;
> + UINT32 CpbSize;
> + UINT16 SetFilter;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + CpbAddr = Cdb->CPBaddr;
> + CpbSize = Cdb->CPBsize;
> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + } else {
> + Nic->McastCount = 0;
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiStart is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
> +
> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
> + Status = RndisUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiReset (Cdb, Nic);
> + }
> +
> + Status = RndisUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiInitialize (Cdb, Nic);
> + }
> +
> + RndisUndiShutdown (Cdb, Nic);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when Undistop is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiGetInitInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + PXE_DB_GET_INIT_INFO *Db;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
> +
> + UsbEthDevice = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when RndisUndiGetConfigInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiInitialize is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
> +
> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> +
> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
> +
> + UsbRndisDevice->RequestId++;
> +
> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
> + return Status;
> + }
> +
> + // Only Wired Medium is supported
> + if (RndisInitMsgCmplt.Medium) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
> +
> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
> +
> + return Status;
> +}
> +
> +/**
> + This function is called when UndiReset is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
> +
> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
> +
> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
> +
> + UsbRndisDevice->RequestId = 1; // Let's start with 1
> +
> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiShutdown is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
> +
> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + Status = EFI_SUCCESS;
> + }
> +
> + UsbRndisDevice->RequestId = 1;
> + return Status;
> +}
> +
> +/**
> + Update the Media connection.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transmit the data after appending RNDIS header.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
> + if (RndisPacketMsg == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
> +
> + CopyMem (
> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
> + BulkOutData,
> + *DataLength
> + );
> +
> + TransferLength = RndisPacketMsg->MessageLength;
> +
> + Status = RndisTransmitDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
> +
> + FreePool (RndisPacketMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Receives and removes RNDIS header and returns the raw data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
> + @retval EFI_NOT_FOUND No buffer was found in the list.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> + VOID *Buffer;
> + PACKET_LIST *HeadPacket;
> + PACKET_LIST *PacketList;
> +
> + // Check if there is any outstanding packet to receive
> + // The buffer allocated has a linked List followed by the packet.
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + Buffer = NULL;
> + HeadPacket = NULL;
> +
> + while (1) {
> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
> + if (Buffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
> + PacketList = (PACKET_LIST *)Buffer;
> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
> + // Save the original address for freeing it up
> + PacketList->OrgBuffer = (UINT8 *)Buffer;
> + TransferLength = UsbRndisDevice->MaxTransferSize;
> +
> + Status = RndisReceiveDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
> + FreePool (Buffer);
> + break;
> + }
> +
> + // Collect all the RNDIS packet in Linked list.
> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
> + (TransferLength >= RndisPacketMsg->MessageLength))
> + {
> + // Insert Packet
> + PacketList->RemainingLength = TransferLength;
> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
> + } else {
> + FreePool (Buffer);
> + }
> + }
> +
> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
> +
> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
> +
> + // Check whether the packet is valid RNDIS packet.
> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
> + {
> + if (*DataLength >= RndisPacketMsg->DataLength) {
> + CopyMem (
> + BulkInData,
> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
> + RndisPacketMsg->DataLength
> + );
> +
> + *DataLength = RndisPacketMsg->DataLength;
> +
> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
> +
> + return EFI_SUCCESS;
> + } else {
> + *DataLength = RndisPacketMsg->DataLength;
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + }
> +
> + RemoveEntryList (&HeadPacket->PacketList);
> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
> + point to this function.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's control endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> +
> +**/
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + )
> +{
> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
> + EFI_USB_DEVICE_REQUEST DevReq;
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> + UINT32 SaveResponseType;
> + UINT32 SaveResponseLength;
> + UINT32 Index;
> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
> +
> + SaveResponseType = 0;
> + SaveResponseLength = 0;
> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
> +
> + if (RndisMsgResponse) {
> + SaveResponseType = RndisMsgResponse->MessageType;
> + SaveResponseLength = RndisMsgResponse->MessageLength;
> + }
> +
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsg,
> + RndisMsg->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
> +
> + // Error or no response expected
> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
> + return Status;
> + }
> +
> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
> + ReadRndisResponseInterrupt (UsbRndisDevice);
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsgResponse,
> + RndisMsgResponse->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
> +
> + PrintRndisMsg (RndisMsgResponse);
> +
> + if (!EFI_ERROR (Status)) {
> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
> +
> + RndisMsgResponse->MessageType = SaveResponseType;
> + RndisMsgResponse->MessageLength = SaveResponseLength;
> + continue;
> + }
> + }
> +
> + return Status;
> + }
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
> +
> + return EFI_TIMEOUT;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkOutEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_TX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (Status == EFI_SUCCESS) {
> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + UsbStatus = 0;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + // Use gStopBulkInCnt to stop BulkIn command
> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkInEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_RX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + } else {
> + gStopBulkInCnt--;
> + }
> + } else {
> + Status = EFI_TIMEOUT;
> + *TransferLength = 0;
> + gBlockBulkInCnt++;
> + }
> +
> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + gBlockBulkInCnt = 0;
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Prints RNDIS Header and Data
> +
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> +
> +**/
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + )
> +{
> + UINTN Length;
> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
> +
> + Length = 0;
> +
> + switch (RndisMsg->MessageType) {
> + case RNDIS_PACKET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
> + break;
> + case RNDIS_INITIALIZE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + break;
> + case RNDIS_INITIALIZE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> + break;
> + case RNDIS_HLT_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
> + break;
> + case RNDIS_QUERY_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
> + break;
> + case RNDIS_QUERY_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
> + break;
> + case RNDIS_SET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_MSG);
> + break;
> + case RNDIS_SET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
> + break;
> + case RNDIS_RESET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
> + break;
> + case RNDIS_RESET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
> + break;
> + case RNDIS_INDICATE_STATUS_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
> + break;
> + case RNDIS_KEEPALIVE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
> + break;
> + case RNDIS_KEEPALIVE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
> + }
> +
> + if (Length) {
> + UINTN Index = 0;
> + for ( ; Length; Length -= 4, Index++) {
> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
> + if (((Index % 4) == 3) && (Index != 0)) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> +
> + if ((Length < 8) && (Length > 4)) {
> + UINT32 Data32;
> + Index++;
> + Data32 = *((UINT32 *)RndisMsg + Index);
> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
> + break;
> + }
> + }
> +
> + if (Index % 4) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> + }
> +}
> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..cb70684f0bf1
> --- /dev/null
> +++ b/UsbNetworkPkg/ReadMe.md
> @@ -0,0 +1,65 @@
> +# UsbNetworkPkg
> +
> +This document is intend to provide package information, include the interface details.
> +
> +# INDEX
> + * [Introduction](#introduction)
> + * [Components](#components)
> + * [[NetworkCommon]](#networkcommon)
> + * [[UsbCdcEcm]](#usbcdcecm)
> + * [[UsbCdcNcm]](#usbcdcncm)
> + * [[UsbRndis]](#usbrndis)
> +
> +# Introduction
> +UsbNetworkPkg provides network functions for USB LAN devices.
> +
> +# Components
> +Below module is included in this package:<br>
> +- NetworkCommon
> +- UsbCdcEcm
> +- UsbCdcNcm
> +- UsbRndis
> +
> +## [NetworkCommon]
> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
> +
> +## Required Components
> +- NetworkPkg
> +
> +## [UsbCdcEcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x06|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbCdcNcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x0D|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbRndis]
> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x02|0xFF|
> +|0xEF|0x04|0x01|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
> new file mode 100644
> index 000000000000..f8ccccdb0830
> --- /dev/null
> +++ b/UsbNetworkPkg/ReleaseNotes.md
> @@ -0,0 +1,11 @@
> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
> +
> +# Release History<!-- omit in toc -->
> +- [1.00](#100)
> +
> +## 1.00
> +
> +**Release Date:** Mar 10, 2022
> +
> +**New Features**
> +- UsbNetworkPkg first release.
> --
> 2.35.1.windows.2
> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-04-07 1:57 ` Rebecca Cran
@ 2023-04-07 2:49 ` RichardHo [何明忠]
2023-04-07 2:52 ` [edk2-devel] " Rebecca Cran
2023-04-07 11:47 ` Rebecca Cran
0 siblings, 2 replies; 11+ messages in thread
From: RichardHo [何明忠] @ 2023-04-07 2:49 UTC (permalink / raw)
To: Rebecca Cran, devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Tinh Nguyen,
Tony Lo (羅金松)
Hi Rebecca,
I have already run the SetupGit.py before send the mail.
(Use git send-email --transfer-encoding=8bit --annotate --suppress-from --to devel@edk2.groups.io *.patch to send mail)
Below is my .git/config
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
abbrev = 12
attributesFile = D:/EDKII-Upstream/edk2/BaseTools/Conf/gitattributes
whitespace = cr-at-eol
[remote "origin"]
url = https://github.com/tianocore/edk2.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[am]
keepcr = True
signoff = True
[cherry-pick]
signoff = True
[color]
diff = True
grep = auto
[commit]
signoff = True
[diff]
algorithm = patience
orderFile = D:/EDKII-Upstream/edk2/BaseTools/Conf/diff.order
renames = copies
statGraphWidth = 20
[diff "ini"]
xfuncname = ^\\[[A-Za-z0-9_., ]+]
[format]
coverLetter = True
numbered = True
signoff = False
[log]
mailmap = True
[notes]
rewriteRef = refs/notes/commits
[sendemail]
chainreplyto = False
thread = True
transferEncoding = 8bit
to = devel@edk2.groups.io
Thanks,
Richard
-----Original Message-----
From: Rebecca Cran <rebecca@bsdio.com>
Sent: 2023年4月7日 9:57 AM
To: Richard Ho (何明忠) <RichardHo@ami.com>; devel@edk2.groups.io
Cc: Andrew Fish <afish@apple.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Michael D Kinney <michael.d.kinney@intel.com>; Michael Kubacki <mikuback@linux.microsoft.com>; Zhiguang Liu <zhiguang.liu@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>; Tinh Nguyen <tinhnguyen@os.amperecomputing.com>; Tony Lo (羅金松) <TonyLo@ami.com>
Subject: [EXTERNAL] Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
**CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**
Your patches are still coming through rather mangled, unfortunately.
You should be sending them as 8bit, not quoted-printable - the
BaseTools/Scripts/SetupGit.py script will configure the settings for you.
Also, there should be a cover letter with the patch series: that script
configures "git format-patch" to generate one.
If you've already run SetupGit.py, could you tell me what .git/config in
your edk2 clone contains, please?
--
Rebecca Cran
On 3/9/23 12:51 AM, Richard Ho (何明忠) wrote:
> This driver provides UEFI driver for USB RNDIS device
>
> Signed-off-by: Richard Ho <richardho@ami.com>
> Cc: Andrew Fish <afish@apple.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
> Reviewed-by: Tony Lo <tonylo@ami.com>
> ---
> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
> UsbNetworkPkg/ReadMe.md | 65 +
> UsbNetworkPkg/ReleaseNotes.md | 11 +
> 18 files changed, 7452 insertions(+)
> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> create mode 100644 UsbNetworkPkg/ReadMe.md
> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>
> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
> new file mode 100644
> index 000000000000..30e4e4c8aac7
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
> @@ -0,0 +1,46 @@
> +## @file
> +# This package defines Usb network specific interfaces and library classes
> +# as well as configuration for standard edk2 packages.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x00010005
> + PACKAGE_NAME = UsbNetworkPkg
> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
> + PACKAGE_VERSION = 0.1
> +
> +[Includes]
> + Include
> +
> +[Protocols]
> + ## Include/Protocol/EdkIIUsbEthernet.h
> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
> +
> +[Guids]
> + ## Usb Network package token space GUID
> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
> +
> +[PcdsFeatureFlag]
> +
> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
> +
> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
> +
> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
> +
> +[PcdsFixedAtBuild, PcdsPatchableInModule]
> + ## Support rate limiting
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
> +
> + ## The rate limiting Credit value is check in rate limiter event.
> + # It is to control the RateLimitingCreditCount max value.
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
> +
> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> new file mode 100644
> index 000000000000..a3316b1d4a89
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
> @@ -0,0 +1,9 @@
> +## @file
> +# Global DSC definitions to be included into project DSC file.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Components.X64]
> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> new file mode 100644
> index 000000000000..544df8404c64
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> new file mode 100644
> index 000000000000..85a309bcf567
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
> @@ -0,0 +1,23 @@
> +## @file
> +# Global switches enable/disable project features.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
> + DEFINE PEI=IA32
> + DEFINE DXE=X64
> +!else
> + DEFINE PEI=COMMON
> + DEFINE DXE=COMMON
> +!endif
> +
> +[Packages]
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[PcdsFeatureFlag]
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> new file mode 100644
> index 000000000000..10616d97edb4
> --- /dev/null
> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
> @@ -0,0 +1,20 @@
> +## @file
> +# List of Core Components.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> +!endif
> +
> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
> +!endif
> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> new file mode 100644
> index 000000000000..8923102bc350
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> @@ -0,0 +1,49 @@
> +## @file
> +# This is Usb Network Common driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = NetworkCommon
> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = NetworkCommonEntry
> +
> +[Sources]
> + DriverBinding.c
> + DriverBinding.h
> + ComponentName.c
> + PxeFunction.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Pcd]
> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> new file mode 100644
> index 000000000000..64205e427745
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# This is Usb Rndis driver for DXE phase.
> +#
> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = UsbRndis
> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = UsbRndisEntry
> +
> +[Sources]
> + UsbRndis.c
> + UsbRndis.h
> + UsbRndisFunction.c
> + ComponentName.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UsbNetworkPkg/UsbNetworkPkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + UefiBootServicesTableLib
> + UefiLib
> + DebugLib
> + UefiUsbLib
> + MemoryAllocationLib
> + BaseMemoryLib
> +
> +[Protocols]
> + gEfiUsbIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDriverBindingProtocolGuid
> + gEdkIIUsbEthProtocolGuid
> +
> +[Depex]
> + TRUE
> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> new file mode 100644
> index 000000000000..f54946c7aa69
> --- /dev/null
> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> @@ -0,0 +1,878 @@
> +/** @file
> + Header file contains code for USB Ethernet Protocol
> + definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
> +
> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
> +
> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
> +
> +#define USB_CDC_CLASS 0x02
> +#define USB_CDC_ACM_SUBCLASS 0x02
> +#define USB_CDC_ECM_SUBCLASS 0x06
> +#define USB_CDC_NCM_SUBCLASS 0x0D
> +#define USB_CDC_DATA_CLASS 0x0A
> +#define USB_CDC_DATA_SUBCLASS 0x00
> +#define USB_NO_CLASS_PROTOCOL 0x00
> +#define USB_NCM_NTB_PROTOCOL 0x01
> +#define USB_VENDOR_PROTOCOL 0xFF
> +
> +// Type Values for the DescriptorType Field
> +#define CS_INTERFACE 0x24
> +#define CS_ENDPOINT 0x25
> +
> +// Descriptor SubType in Functional Descriptors
> +#define HEADER_FUN_DESCRIPTOR 0x00
> +#define UNION_FUN_DESCRIPTOR 0x06
> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
> +
> +#define MAX_LAN_INTERFACE 0x10
> +
> +// Table 20: Class-Specific Notification Codes
> +#define USB_CDC_NETWORK_CONNECTION 0x00
> +
> +// 6.3.1 NetworkConnection
> +#define NETWORK_CONNECTED 0x01
> +#define NETWORK_DISCONNECT 0x00
> +
> +// USB Header functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT16 BcdCdc;
> +} USB_HEADER_FUN_DESCRIPTOR;
> +
> +// USB Union Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MasterInterface;
> + UINT8 SlaveInterface;
> +} USB_UNION_FUN_DESCRIPTOR;
> +
> +// USB Ethernet Functional Descriptor
> +typedef struct {
> + UINT8 FunctionLength;
> + UINT8 DescriptorType;
> + UINT8 DescriptorSubtype;
> + UINT8 MacAddress;
> + UINT32 EthernetStatistics;
> + UINT16 MaxSegmentSize;
> + UINT16 NumberMcFilters;
> + UINT8 NumberPowerFilters;
> +} USB_ETHERNET_FUN_DESCRIPTOR;
> +
> +typedef struct {
> + UINT32 UsBitRate;
> + UINT32 DsBitRate;
> +} USB_CONNECT_SPEED_CHANGE;
> +
> +// Request Type Codes for USB Ethernet
> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
> +
> +// Class-Specific Request Codes for Ethernet subclass
> +// USB ECM 1.2 specification, Section 6.2
> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
> +#define SET_ETH_PACKET_FILTER_REQ 0x43
> +#define GET_ETH_STATISTIC_REQ 0x44
> +
> +// USB ECM command request length
> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
> +
> +// USB Ethernet Packet Filter Bitmap
> +// USB ECM 1.2 specification, Section 6.2.4
> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
> +
> +// USB Ethernet Statistics Feature Selector Codes
> +// USB ECM 1.2 specification, Section 6.2.5
> +#define USB_ETH_XMIT_OK 0x01
> +#define USB_ETH_RCV_OK 0x02
> +#define USB_ETH_XMIT_ERROR 0x03
> +#define USB_ETH_RCV_ERROR 0x04
> +#define USB_ETH_RCV_NO_BUFFER 0x05
> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
> +#define USB_ETH_RCV_CRC_ERROR 0x12
> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
> +#define USB_ETH_XMIT_DEFERRED 0x17
> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
> +#define USB_ETH_RCV_OVERRUN 0x19
> +#define USB_ETH_XMIT_UNDERRUN 0x1A
> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
> +
> +// NIC Information
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + UINT16 InterrupOpFlag;
> + UINT64 MappedAddr;
> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
> + UINT8 McastCount;
> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
> + UINT8 TxBufferCount;
> + UINT16 State;
> + BOOLEAN CanTransmit;
> + UINT16 ReceiveStatus;
> + UINT8 RxFilter;
> + UINT32 RxFrame;
> + UINT32 TxFrame;
> + UINT16 NetworkConnect;
> + UINT8 CableDetect;
> + UINT16 MaxSegmentSize;
> + EFI_MAC_ADDRESS MacAddr;
> + PXE_CPB_START_31 PxeStart;
> + PXE_CPB_INITIALIZE PxeInit;
> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
> + EFI_USB_DEVICE_REQUEST Request;
> + EFI_EVENT RateLimiter;
> + UINT32 RateLimitingCredit;
> + UINT32 RateLimitingCreditCount;
> + UINT32 RateLimitingPollTimer;
> + BOOLEAN RateLimitingEnable;
> +} NIC_DATA;
> +
> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] PacketLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *Packet,
> + IN OUT UINTN *PacketLength
> + );
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Request
> + );
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + );
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + );
> +
> +typedef struct {
> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
> +} EDKII_USB_ETHERNET_UNDI;
> +
> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
> +// descriptor and specific requests.
> +struct _EDKII_USB_ETHERNET_PROTOCOL {
> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
> + // for calling the UNDI child functions
> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
> +};
> +
> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> new file mode 100644
> index 000000000000..0416ce132302
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> @@ -0,0 +1,266 @@
> +/** @file
> + Header file for for USB network common driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _DRIVER_BINDING_H_
> +#define _DRIVER_BINDING_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/NetworkInterfaceIdentifier.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +#define NETWORK_COMMON_DRIVER_VERSION 1
> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
> +#define RX_BUFFER_COUNT 32
> +#define TX_BUFFER_COUNT 32
> +#define MEMORY_REQUIRE 0
> +
> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
> + UINT16 Protocol;
> +} EthernetHeader;
> +#pragma pack()
> +
> +typedef struct {
> + UINTN Signature;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
> + EFI_HANDLE DeviceHandle;
> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> + NIC_DATA NicInfo;
> + VOID *ReceiveBuffer;
> +} NIC_DEVICE;
> +
> +typedef VOID (*API_FUNC)(
> + PXE_CDB *,
> + NIC_DATA *
> + );
> +
> +extern PXE_SW_UNDI *gPxe;
> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + );
> +
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + );
> +
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + );
> +
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + );
> +
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + );
> +
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + );
> +
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + );
> +
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + );
> +
> +#endif
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> new file mode 100644
> index 000000000000..775807042460
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> @@ -0,0 +1,586 @@
> +/** @file
> + Header file for for USB Rndis driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _USB_RNDIS_H_
> +#define _USB_RNDIS_H_
> +
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiUsbLib.h>
> +#include <Protocol/UsbIo.h>
> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 Signature;
> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
> + EFI_HANDLE UsbCdcDataHandle;
> + EFI_HANDLE UsbRndisHandle;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
> + EFI_USB_CONFIG_DESCRIPTOR *Config;
> + UINT8 NumOfInterface;
> + UINT8 BulkInEndpoint;
> + UINT8 BulkOutEndpoint;
> + UINT8 InterrupEndpoint;
> + EFI_MAC_ADDRESS MacAddress;
> + UINT32 RequestId;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + LIST_ENTRY ReceivePacketList;
> +} USB_RNDIS_DEVICE;
> +
> +#define USB_RNDIS_DRIVER_VERSION 1
> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
> +
> +#define LAN_BULKIN_CMD_CONTROL 1
> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
> +#define RNDIS_RESERVED_BYTE_LENGTH 8
> +
> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
> +
> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
> +
> +struct BIT_MAP {
> + unsigned int Src;
> + unsigned int Dst;
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + );
> +
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + );
> +
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + );
> +
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN BOOLEAN *PatternActive
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *Statistic
> + );
> +
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + );
> +
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + UINTN *TransferLength
> + );
> +
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + );
> +
> +#define RNDIS_MAJOR_VERSION 0x00000001
> +#define RNDIS_MINOR_VERSION 0x00000000
> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
> +
> +#define RNDIS_PACKET_MSG 0x00000001
> +#define RNDIS_INITIALIZE_MSG 0x00000002
> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
> +#define RNDIS_HLT_MSG 0x00000003
> +#define RNDIS_QUERY_MSG 0x00000004
> +#define RNDIS_QUERY_CMPLT 0x80000004
> +#define RNDIS_SET_MSG 0x00000005
> +#define RNDIS_SET_CMPLT 0x80000005
> +#define RNDIS_RESET_MSG 0x00000006
> +#define RNDIS_RESET_CMPLT 0x80000006
> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
> +#define RNDIS_KEEPALIVE_MSG 0x00000008
> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
> +
> +#define RNDIS_STATUS_SUCCESS 0x00000000
> +#define RNDIS_STATUS_FAILURE 0xC0000001
> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
> +
> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
> +
> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
> +
> +//
> +// General Objects
> +//
> +// Taken from NTDDNDIS.H
> +#define OID_GEN_SUPPORTED_LIST 0x00010101
> +#define OID_GEN_HARDWARE_STATUS 0x00010102
> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
> +#define OID_GEN_MEDIA_IN_USE 0x00010104
> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
> +#define OID_GEN_LINK_SPEED 0x00010107
> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
> +#define OID_GEN_VENDOR_ID 0x0001010C
> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
> +#define OID_GEN_DRIVER_VERSION 0x00010110
> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
> +#define OID_GEN_MAC_OPTIONS 0x00010113
> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
> +
> +#define OID_GEN_XMIT_OK 0x00020101
> +#define OID_GEN_RCV_OK 0x00020102
> +#define OID_GEN_XMIT_ERROR 0x00020103
> +#define OID_GEN_RCV_ERROR 0x00020104
> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
> +
> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
> +
> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
> +//
> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
> +//
> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
> +#define NDIS_PACKET_TYPE_SMT 0x0040
> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
> +#define NDIS_PACKET_TYPE_GROUP 0x1000
> +
> +#pragma pack(1)
> +
> +typedef struct _REMOTE_NDIS_MSG_HEADER {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> +} REMOTE_NDIS_MSG_HEADER;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 MaxTransferSize;
> +} REMOTE_NDIS_INITIALIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_HALT_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_QUERY_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_MSG;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_MSG QueryMsg;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Oid;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> + UINT32 Reserved;
> +} REMOTE_NDIS_SET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Reserved;
> +} REMOTE_NDIS_RESET_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 StatusBufferLength;
> + UINT32 StatusBufferOffset;
> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
> +
> +typedef struct {
> + UINT32 DiagStatus;
> + UINT32 ErrorOffset;
> +} RNDIS_DIAGNOSTIC_INFO;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> +} REMOTE_NDIS_KEEPALIVE_MSG;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 MajorVersion;
> + UINT32 MinorVersion;
> + UINT32 DeviceFlags;
> + UINT32 Medium;
> + UINT32 MaxPacketsPerTransfer;
> + UINT32 MaxTransferSize;
> + UINT32 PacketAlignmentFactor;
> + UINT64 Reserved;
> +} REMOTE_NDIS_INITIALIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> + UINT32 InformationBufferLength;
> + UINT32 InformationBufferOffset;
> +} REMOTE_NDIS_QUERY_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT8 Addr[6];
> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
> +
> +typedef struct {
> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> + UINT32 MaxTotalSize;
> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_SET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 Status;
> + UINT32 AddressingReset;
> +} REMOTE_NDIS_RESET_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 RequestID;
> + UINT32 Status;
> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
> +
> +typedef struct {
> + UINT32 MessageType;
> + UINT32 MessageLength;
> + UINT32 DataOffset;
> + UINT32 DataLength;
> + UINT32 OutOfBandDataOffset;
> + UINT32 OutOfBandDataLength;
> + UINT32 NumOutOfBandDataElements;
> + UINT32 PerPacketInfoOffset;
> + UINT32 PerPacketInfoLength;
> + UINT32 Reserved1;
> + UINT32 Reserved2;
> +} REMOTE_NDIS_PACKET_MSG;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} OUT_OF_BAND_DATA_RECORD;
> +
> +typedef struct {
> + UINT32 Size;
> + UINT32 Type;
> + UINT32 ClassInformationOffset;
> +} PER_PACKET_INFO_DATA_RECORD;
> +
> +typedef struct {
> + LIST_ENTRY PacketList;
> + UINT8 *OrgBuffer;
> + UINTN RemainingLength;
> + UINT8 *PacketStartBuffer; // Variable size data to follow
> +} PACKET_LIST;
> +
> +#pragma pack()
> +
> +#endif
> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> new file mode 100644
> index 000000000000..e83469e13079
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> @@ -0,0 +1,263 @@
> +/** @file
> + This file contains code for USB network common driver
> + component name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
> + {
> + "eng;en",
> + L"Network Common Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
> + NetworkCommonComponentNameGetDriverName,
> + NetworkCommonComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +NetworkCommonComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +NetworkCommonComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> + CHAR16 *HandleName;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
> +
> + if (!Language || !ControllerName) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (ChildHandle == NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Make sure this driver is currently managing ControllerHandle
> + //
> + Status = EfiTestManagedDevice (
> + Controller,
> + gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Make sure this driver produced ChildHandle
> + //
> + Status = EfiTestChildHandle (
> + Controller,
> + ChildHandle,
> + &gEdkIIUsbEthProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
> +
> + if (!EFI_ERROR (Status)) {
> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *ControllerName = HandleName;
> +
> + if (gNetworkCommonControllerNameTable != NULL) {
> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
> + gNetworkCommonControllerNameTable = NULL;
> + }
> +
> + Status = AddUnicodeString2 (
> + "eng",
> + gNetworkCommonComponentName.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + TRUE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = AddUnicodeString2 (
> + "en",
> + gNetworkCommonComponentName2.SupportedLanguages,
> + &gNetworkCommonControllerNameTable,
> + HandleName,
> + FALSE
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gNetworkCommonControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &gNetworkCommonComponentName)
> + );
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> new file mode 100644
> index 000000000000..23b791362091
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> @@ -0,0 +1,595 @@
> +/** @file
> + This file contains code for USB network binding driver
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +PXE_SW_UNDI *gPxe = NULL;
> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> +UINT32 gRateLimitingCredit;
> +UINT32 gRateLimitingPollTimer;
> +BOOLEAN gRateLimitingEnable;
> +
> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
> + NetworkCommonSupported,
> + NetworkCommonDriverStart,
> + NetworkCommonDriverStop,
> + NETWORK_COMMON_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Create MAC Device Path
> +
> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
> + @retval EFI_SUCCESS MAC device path created successfully.
> +
> +**/
> +EFI_STATUS
> +CreateMacDevicePath (
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + MAC_ADDR_DEVICE_PATH MacAddrNode;
> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
> + UINT8 *DevicePath;
> + UINT16 TotalLength;
> + UINT16 BaseLength;
> +
> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
> +
> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
> + MacAddrNode.Header.Length[1] = 0;
> +
> + EndNode = BaseDev;
> +
> + while (!IsDevicePathEnd (EndNode)) {
> + EndNode = NextDevicePathNode (EndNode);
> + }
> +
> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
> + DevicePath += BaseLength;
> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
> + DevicePath += sizeof (MacAddrNode);
> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Network Common Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +NetworkCommonSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + EFI_MAC_ADDRESS MacAddress;
> + UINTN BulkDataSize;
> + NIC_DEVICE *NicDevice;
> + UINT8 *TmpPxePointer;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
> +
> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
> + ASSERT_EFI_ERROR (Status);
> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
> + if (!NicDevice) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + // for alignment adjustment
> + if (gPxe == NULL) {
> + TmpPxePointer = NULL;
> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
> + if (!TmpPxePointer) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + return EFI_OUT_OF_RESOURCES;
> + } else {
> + // check for paragraph alignment here
> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
> + } else {
> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
> + }
> +
> + if (!gPxe) {
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PxeStructInit (gPxe);
> + }
> + }
> +
> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
> +
> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
> +
> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
> +
> + NicDevice->NicInfo.UsbEth = UsbEth;
> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
> + NicDevice->NicInfo.CableDetect = 0;
> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
> +
> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
> +
> + NicDevice->NicInfo.TxBufferCount = 0;
> +
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
> + } else {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = CreateMacDevicePath (
> + &NicDevice->DevPath,
> + UsbEthPath,
> + &NicDevice->NicInfo
> + );
> +
> + if (EFI_ERROR (Status)) {
> + UpdateNicNum (NULL, gPxe);
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> + }
> +
> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
> + NicDevice->NiiProtocol.ImageSize = 0;
> + NicDevice->NiiProtocol.ImageAddr = 0;
> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
> +
> + NicDevice->NiiProtocol.StringId[0] = 'U';
> + NicDevice->NiiProtocol.StringId[1] = 'N';
> + NicDevice->NiiProtocol.StringId[2] = 'D';
> + NicDevice->NiiProtocol.StringId[3] = 'I';
> + NicDevice->DeviceHandle = NULL;
> +
> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
> + NicDevice->NicInfo.RateLimiter = NULL;
> +
> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &NicDevice->DeviceHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + if (TmpPxePointer != NULL) {
> + FreePool (TmpPxePointer);
> + }
> +
> + if (NicDevice->DevPath != NULL) {
> + FreePool (NicDevice->DevPath);
> + }
> +
> + if (NicDevice != NULL) {
> + FreePool (NicDevice);
> + }
> +
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + NicDevice->DeviceHandle,
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Network Common Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +NetworkCommonDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN AllChildrenStopped;
> + UINTN Index;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> + NIC_DEVICE *NicDevice;
> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
> +
> + if (NumberOfChildren == 0) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ControllerHandle,
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_SUCCESS;
> + }
> +
> + AllChildrenStopped = TRUE;
> +
> + for (Index = 0; Index < NumberOfChildren; Index++) {
> + Status = gBS->OpenProtocol (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + (VOID **)&NiiProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + AllChildrenStopped = FALSE;
> + continue;
> + }
> +
> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index]
> + );
> +
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ChildHandleBuffer[Index],
> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> + &NicDevice->NiiProtocol,
> + &gEfiDevicePathProtocolGuid,
> + NicDevice->DevPath,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEth,
> + This->DriverBindingHandle,
> + ChildHandleBuffer[Index],
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> + );
> + } else {
> + FreePool (NicDevice->DevPath);
> + FreePool (NicDevice);
> + }
> + }
> +
> + if (!AllChildrenStopped) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Entrypoint of Network Common Driver.
> +
> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NetworkCommonEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &gNetworkCommonDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gNetworkCommonDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gNetworkCommonComponentName2,
> + NULL
> + );
> + return Status;
> +}
> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> new file mode 100644
> index 000000000000..687cabca4ce3
> --- /dev/null
> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> @@ -0,0 +1,1803 @@
> +/** @file
> + This file contains code for UNDI command based on UEFI specification.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "DriverBinding.h"
> +
> +// API table, defined in UEFI specification
> +API_FUNC gUndiApiTable[] = {
> + UndiGetState,
> + UndiStart,
> + UndiStop,
> + UndiGetInitInfo,
> + UndiGetConfigInfo,
> + UndiInitialize,
> + UndiReset,
> + UndiShutdown,
> + UndiInterruptEnable,
> + UndiReceiveFilter,
> + UndiStationAddress,
> + UndiStatistics,
> + UndiMcastIp2Mac,
> + UndiNvData,
> + UndiGetStatus,
> + UndiFillHeader,
> + UndiTransmit,
> + UndiReceive
> +};
> +
> +/**
> + Callback function for enable Rate Limiter
> +
> + @param[in] Event Event whose notification function is being invoked
> + @param[in] Context Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +UndiRateLimiterCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + NIC_DATA *Nic = Context;
> +
> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
> + Nic->RateLimitingCreditCount++;
> + }
> +}
> +
> +/**
> + This command is used to determine the operational state of the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetState (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from stopped to started.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_START_31 *Cpb;
> + EFI_STATUS Status;
> + BOOLEAN EventError;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
> +
> + Nic->PxeStart.Delay = Cpb->Delay;
> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
> + Nic->PxeStart.Block = Cpb->Block;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
> + EventError = FALSE;
> + Status = EFI_SUCCESS;
> + if (Nic->RateLimitingEnable == TRUE) {
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + UndiRateLimiterCallback,
> + Nic,
> + &Nic->RateLimiter
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = gBS->SetTimer (
> + Nic->RateLimiter,
> + TimerPeriodic,
> + Nic->RateLimitingPollTimer * 10000
> + );
> + if (EFI_ERROR (Status)) {
> + EventError = TRUE;
> + }
> + }
> + }
> +
> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + // Initial the state for UNDI start.
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + } else {
> + if (Nic->RateLimitingEnable == TRUE) {
> + if (!EventError) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + }
> +
> + if (Nic->RateLimiter) {
> + gBS->CloseEvent (&Nic->RateLimiter);
> + Nic->RateLimiter = 0;
> + }
> + }
> +
> + // Initial the state when UNDI start is fail
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + }
> +}
> +
> +/**
> + This command is used to change the UNDI operational state from started to stopped.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
> + return;
> + }
> +
> + Nic->PxeStart.Delay = 0;
> + Nic->PxeStart.Virt2Phys = 0;
> + Nic->PxeStart.Block = 0;
> + Nic->PxeStart.Map_Mem = 0;
> + Nic->PxeStart.UnMap_Mem = 0;
> + Nic->PxeStart.Sync_Mem = 0;
> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
> +
> + if (Nic->RateLimitingEnable == TRUE) {
> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> + gBS->CloseEvent (&Nic->RateLimiter);
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve initialization information that is
> + needed by drivers and applications to initialized UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_INIT_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->MemoryRequired = MEMORY_REQUIRE;
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + Db->LinkSpeeds[0] = 10;
> + Db->LinkSpeeds[1] = 100;
> + Db->LinkSpeeds[2] = 1000;
> + Db->LinkSpeeds[3] = 0;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> + Db->IFtype = PXE_IFTYPE_ETHERNET;
> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
> +
> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to retrieve configuration information about
> + the NIC being controlled by the UNDI.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_CONFIG_INFO *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->pci.BusType = PXE_BUSTYPE_USB;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command resets the network adapter and initializes UNDI using
> + the parameters supplied in the CPB.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_INITIALIZE *Cpb;
> + PXE_DB_INITIALIZE *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
> +
> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
> +
> + Cdb->StatCode = Initialize (Cdb, Nic);
> +
> + Db->MemoryUsed = MEMORY_REQUIRE;
> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> +
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + Nic->CanTransmit = FALSE;
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
> + }
> + }
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Initialize Network interface controller data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> + @retval Status A value of Pxe statcode.
> +
> +**/
> +UINT16
> +Initialize (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + UINTN Status;
> + UINT32 Index;
> + EFI_STATUS EfiStatus;
> +
> + Status = MapIt (
> + Nic,
> + Nic->PxeInit.MemoryAddr,
> + Nic->PxeInit.MemoryLength,
> + TO_AND_FROM_DEVICE,
> + (UINT64)(UINTN)&Nic->MappedAddr
> + );
> +
> + if (Status != 0) {
> + return (UINT16)Status;
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Nic->BroadcastNodeAddress[Index] = 0xFF;
> + }
> +
> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = 0;
> + Nic->PermNodeAddress[Index] = 0;
> + Nic->BroadcastNodeAddress[Index] = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
> + if (EFI_ERROR (EfiStatus)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return (UINT16)Status;
> +}
> +
> +/**
> + This command resets the network adapter and reinitializes the UNDI
> + with the same parameters provided in the Initialize command.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
> + Nic->InterrupOpFlag = 0;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Shutdown command resets the network adapter and leaves it in a
> + safe state for another driver to initialize.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Nic->CanTransmit = FALSE;
> +
> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Interrupt Enables command can be used to read and/or change
> + the current external interrupt enable settings.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiInterruptEnable (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and change receive filters and,
> + if supported, read and change the multicast MAC address filter list.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + UINT16 NewFilter;
> + PXE_DB_RECEIVE_FILTERS *Db;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> +
> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
> + if ((Cdb->DBsize != 0)) {
> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
> + }
> + }
> +
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
> + if (NewFilter == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Cdb->CPBsize != 0) {
> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if ((Cdb->CPBsize == 0)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
> + break;
> +
> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + break;
> +
> + default:
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + }
> +
> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Set PXE receive filter.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] SetFilter PXE receive filter
> + @param[in] CpbAddr Command Parameter Block Address
> + @param[in] CpbSize Command Parameter Block Size
> +
> +**/
> +UINT16
> +SetFilter (
> + IN NIC_DATA *Nic,
> + IN UINT16 SetFilter,
> + IN UINT64 CpbAddr,
> + IN UINT32 CpbSize
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + This command is used to get current station and broadcast MAC addresses
> + and, if supported, to change the current station MAC address.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStationAddress (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_STATION_ADDRESS *Cpb;
> + PXE_DB_STATION_ADDRESS *Db;
> + UINT16 Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> + }
> +
> + if (Cdb->CPBaddr != 0) {
> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
> + }
> + }
> +
> + if (Cdb->DBaddr != 0) {
> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and clear the NIC traffic statistics.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiStatistics (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + Return data for DB data.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] DbAddr Data Block Address.
> + @param[in] DbSize Data Block Size.
> +
> +**/
> +UINT16
> +Statistics (
> + IN NIC_DATA *Nic,
> + IN UINT64 DbAddr,
> + IN UINT16 DbSize
> + )
> +{
> + PXE_DB_STATISTICS *DbStatistic;
> + EFI_STATUS Status;
> +
> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
> +
> + if (DbSize == 0) {
> + return PXE_STATCODE_SUCCESS;
> + }
> +
> + DbStatistic->Supported = 0x802;
> + DbStatistic->Data[0x01] = Nic->RxFrame;
> + DbStatistic->Data[0x0B] = Nic->TxFrame;
> +
> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> +
> + @param[in, out] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiMcastIp2Mac (
> + IN OUT PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
> + PXE_DB_MCAST_IP_TO_MAC *Db;
> + UINT8 *Tmp;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + return;
> + }
> +
> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
> +
> + if ((Tmp[0] & 0xF0) != 0xE0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
> + }
> +
> + Db->MAC[0] = 0x01;
> + Db->MAC[1] = 0x00;
> + Db->MAC[2] = 0x5E;
> + Db->MAC[3] = Tmp[1] & 0x7F;
> + Db->MAC[4] = Tmp[2];
> + Db->MAC[5] = Tmp[3];
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to read and write (if supported by NIC H/W)
> + nonvolatile storage on the NIC.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiNvData (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> + }
> +}
> +
> +/**
> + This command returns the current interrupt status and/or the
> + transmitted buffer addresses and the current media status.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_DB_GET_STATUS *Db;
> + PXE_DB_GET_STATUS TmpGetStatus;
> + UINT16 NumEntries;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + TmpGetStatus.RxFrameLen = 0;
> + TmpGetStatus.reserved = 0;
> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
> +
> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
> + } else {
> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
> + if (Cdb->DBsize == 0) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + NumEntries = Cdb->DBsize - sizeof (UINT64);
> + Cdb->DBsize = sizeof (UINT32) * 2;
> +
> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
> + if (Nic->TxBufferCount > 0) {
> + Nic->TxBufferCount--;
> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
> + }
> + }
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
> + if (Nic->ReceiveStatus != 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
> + }
> + }
> +
> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
> + Nic->CableDetect = 0;
> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
> + Nic->CableDetect = 1;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
> + if (Nic->CableDetect == 0) {
> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + This command is used to fill the media header(s) in transmit packet(s).
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiFillHeader (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + PXE_CPB_FILL_HEADER *CpbFillHeader;
> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
> + EthernetHeader *MacHeader;
> + UINTN Index;
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
> +
> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
> + MacHeader->Protocol = CpbFill->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
> + }
> + } else {
> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
> +
> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
> + MacHeader->Protocol = CpbFillHeader->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
> + }
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> + }
> +}
> +
> +/**
> + The Transmit command is used to place a packet into the transmit queue.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk out command to transmit data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in] OpFlags Operation Flags.
> +
> +**/
> +UINT16
> +Transmit (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN UINT16 OpFlags
> + )
> +{
> + EFI_STATUS Status;
> + PXE_CPB_TRANSMIT *Cpb;
> + UINT64 BulkOutData;
> + UINTN DataLength;
> + UINTN TransmitLength;
> + UINTN Map;
> + UINT32 Counter;
> + UINT16 StatCode;
> +
> + BulkOutData = 0;
> + Counter = 0;
> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
> +
> + if (Nic->CanTransmit) {
> + return PXE_STATCODE_BUSY;
> + }
> +
> + Nic->CanTransmit = TRUE;
> +
> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + Map = MapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + (UINT64)(UINTN)&BulkOutData
> + );
> +
> + if (Map != 0) {
> + Nic->CanTransmit = FALSE;
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
> + Nic->TxBufferCount++;
> + }
> +
> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
> +
> + while (1) {
> + if (Counter >= 3) {
> + StatCode = PXE_STATCODE_BUSY;
> + break;
> + }
> +
> + TransmitLength = DataLength;
> +
> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
> + if (EFI_ERROR (Status)) {
> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
> + break;
> + }
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
> + break;
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + Nic->TxFrame++;
> + StatCode = PXE_STATCODE_SUCCESS;
> + break;
> + }
> +
> + Counter++;
> + }
> +
> + UnMapIt (
> + Nic,
> + Cpb->FrameAddr,
> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> + TO_DEVICE,
> + BulkOutData
> + );
> +
> + Nic->CanTransmit = FALSE;
> +
> + return StatCode;
> +}
> +
> +/**
> + When the network adapter has received a frame, this command is used
> + to copy the frame into driver/application storage.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> +**/
> +VOID
> +UndiReceive (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> + {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> + return;
> + } else {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> + }
> +
> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> + return;
> + }
> +
> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +
> + return;
> + }
> +
> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
> +
> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> + }
> +}
> +
> +/**
> + Use USB Ethernet Protocol Bulk in command to receive data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in, out] Nic A pointer to the Network interface controller data.
> + @param[in] CpbAddr Command Parameter Block Address.
> + @param[in, out] DbAddr Data Block Address.
> +
> +**/
> +UINT16
> +Receive (
> + IN PXE_CDB *Cdb,
> + IN OUT NIC_DATA *Nic,
> + IN UINT64 CpbAddr,
> + IN OUT UINT64 DbAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + PXE_FRAME_TYPE FrameType;
> + PXE_CPB_RECEIVE *Cpb;
> + PXE_DB_RECEIVE *Db;
> + NIC_DEVICE *NicDevice;
> + UINT8 *BulkInData;
> + UINTN DataLength;
> + EthernetHeader *Header;
> + EFI_TPL OriginalTpl;
> +
> + FrameType = PXE_FRAME_TYPE_NONE;
> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
> + BulkInData = NicDevice->ReceiveBuffer;
> + DataLength = (UINTN)Nic->MaxSegmentSize;
> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
> +
> + if (!BulkInData) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
> + if (EFI_ERROR (Status)) {
> + Nic->ReceiveStatus = 0;
> + if (Nic->RateLimitingEnable == TRUE) {
> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + if (Nic->RateLimitingCreditCount != 0) {
> + Nic->RateLimitingCreditCount--;
> + }
> +
> + gBS->RestoreTPL (OriginalTpl);
> + }
> +
> + return PXE_STATCODE_NO_DATA;
> + }
> +
> + Nic->RxFrame++;
> +
> + if (DataLength != 0) {
> + if (DataLength > Cpb->BufferLen) {
> + DataLength = (UINTN)Cpb->BufferLen;
> + }
> +
> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
> +
> + Header = (EthernetHeader *)BulkInData;
> +
> + Db->FrameLen = (UINT32)DataLength;
> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_UNICAST;
> + } else {
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
> + break;
> + }
> + }
> +
> + if (Index >= PXE_HWADDR_LEN_ETHER) {
> + FrameType = PXE_FRAME_TYPE_BROADCAST;
> + } else {
> + if ((Header->DestAddr[0] & 1) == 1) {
> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
> + } else {
> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
> + }
> + }
> + }
> +
> + Db->Type = FrameType;
> + Db->Protocol = Header->Protocol;
> +
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
> + Db->DestAddr[Index] = Header->DestAddr[Index];
> + }
> + }
> +
> + if (FrameType == PXE_FRAME_TYPE_NONE) {
> + Nic->ReceiveStatus = 0;
> + } else {
> + Nic->ReceiveStatus = 1;
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Fill out PXE SW UNDI structure.
> +
> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +PxeStructInit (
> + OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
> + PxeSw->Fudge = 0;
> + PxeSw->IFcnt = 0;
> + PxeSw->IFcntExt = 0;
> + PxeSw->Rev = PXE_ROMID_REV;
> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
> + PxeSw->reserved1 = 0;
> +
> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
> + PXE_ROMID_IMP_FRAG_SUPPORTED |
> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
> +
> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
> + PxeSw->reserved2[0] = 0;
> + PxeSw->reserved2[1] = 0;
> + PxeSw->reserved2[2] = 0;
> + PxeSw->BusCnt = 1;
> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
> +}
> +
> +/**
> + Update NIC number.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
> +
> +**/
> +VOID
> +UpdateNicNum (
> + IN NIC_DATA *Nic,
> + IN OUT PXE_SW_UNDI *PxeSw
> + )
> +{
> + UINT16 NicNum;
> +
> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
> +
> + if (Nic == NULL) {
> + if (NicNum > 0) {
> + NicNum--;
> + }
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> + return;
> + }
> +
> + NicNum++;
> +
> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
> +}
> +
> +/**
> + UNDI API table entry.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UndiApiEntry (
> + IN UINT64 Cdb
> + )
> +{
> + PXE_CDB *CdbPtr;
> + NIC_DATA *Nic;
> +
> + if (Cdb == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Map virtual memory address for DMA. This field can be set to
> + zero if there is no mapping service.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[out] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +UINTN
> +MapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + OUT UINT64 MappedAddr
> + )
> +{
> + UINT64 *PhyAddr;
> +
> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
> +
> + if (Nic->PxeStart.Map_Mem == 0) {
> + *PhyAddr = MemAddr;
> + } else {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return PXE_STATCODE_SUCCESS;
> +}
> +
> +/**
> + Un-map previously mapped virtual memory address. This field can be set
> + to zero only if the Map_Mem() service is also set to zero.
> +
> + @param[in] Nic A pointer to the Network interface controller data.
> + @param[in] MemAddr Virtual address to be mapped.
> + @param[in] Size Size of memory to be mapped.
> + @param[in] Direction Direction of data flow for this memory's usage:
> + cpu->device, device->cpu or both ways.
> + @param[in] MappedAddr Pointer to return the mapped device address.
> +
> +**/
> +VOID
> +UnMapIt (
> + IN NIC_DATA *Nic,
> + IN UINT64 MemAddr,
> + IN UINT32 Size,
> + IN UINT32 Direction,
> + IN UINT64 MappedAddr
> + )
> +{
> + if (Nic->PxeStart.UnMap_Mem != 0) {
> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
> + Nic->PxeStart.Unique_ID,
> + MemAddr,
> + Size,
> + Direction,
> + MappedAddr
> + );
> + }
> +
> + return;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
> new file mode 100644
> index 000000000000..b9ba170c135b
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
> @@ -0,0 +1,172 @@
> +/** @file
> + This file contains code for USB RNDIS Driver Component
> + Name definitions
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
> + {
> + "eng;en",
> + L"USB RNDIS Driver"
> + },
> + {
> + NULL,
> + NULL
> + }
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
> + UsbRndisComponentNameGetDriverName,
> + UsbRndisComponentNameGetControllerName,
> + "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
> + "en"
> +};
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Language 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[out] DriverName 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
> +UsbRndisComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + gUsbRndisDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gUsbRndisComponentName)
> + );
> +}
> +
> +/**
> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
> + @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
> +UsbRndisComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> new file mode 100644
> index 000000000000..92830771e408
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> @@ -0,0 +1,886 @@
> +/** @file
> + This file contains code for USB Remote Network Driver
> + Interface Spec. Driver Binding
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
> + UsbRndisDriverSupported,
> + UsbRndisDriverStart,
> + UsbRndisDriverStop,
> + USB_RNDIS_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +/**
> + Check if this interface is USB Rndis SubType
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +
> +**/
> +BOOLEAN
> +IsSupportedDevice (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if this interface is USB Rndis SubType but not CDC Data interface
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis SubType.
> + @retval FALSE Not USB Rndis SubType.
> +**/
> +BOOLEAN
> +IsRndisInterface (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for specific device/RNDIS and CDC-DATA
> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
> + )
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
> +
> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> +
> + @retval EFI_SUCCESS Is the same device.
> + @retval EFI_UNSUPPORTED Is not the same device.
> +
> +**/
> +EFI_STATUS
> +IsSameDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
> + )
> +{
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
> + while (1) {
> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
> + {
> + return EFI_SUCCESS;
> + } else {
> + return EFI_UNSUPPORTED;
> + }
> + } else {
> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
> + }
> + }
> +
> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
> +}
> +
> +/**
> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB CDC Data(UsbIo) installed.
> + @retval FALSE USB CDC Data(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbCdcData (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for CDC-DATA
> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Check if the USB Rndis(UsbIo) installed
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> +
> + @retval TRUE USB Rndis(UsbIo) installed.
> + @retval FALSE USB Rndis(UsbIo) did not installed.
> +
> +**/
> +BOOLEAN
> +IsUsbRndis (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // Check for Rndis
> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
> + {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
> + For one device two USBIO will be installed each for CDC and RNDIS interface.
> +
> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +UpdateRndisDevice (
> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + BOOLEAN IsRndisInterfaceFlag;
> +
> + IsRndisInterfaceFlag = FALSE;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEdkIIUsbEthProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthDevice
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
> + if (IsRndisInterfaceFlag == FALSE) {
> + continue;
> + }
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> +
> + if (!EFI_ERROR (Status)) {
> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> + FreePool (HandleBuffer);
> + return EFI_SUCCESS;
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> +
> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
> + and UsbIO protocol.
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
> +
> +**/
> +VOID
> +FindMatchingCdcData (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + UsbRndisDevice->UsbRndisHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
> +
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
> + FreePool (HandleBuffer);
> + return;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> + if (!EFI_ERROR (Status)) {
> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + FreePool (HandleBuffer);
> + return;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +}
> +
> +/**
> +
> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
> +
> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
> +
> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FindMatchingRndisDev (
> + IN EFI_HANDLE CdcHandle,
> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
> + OUT EFI_HANDLE *RndisHandle
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = gBS->HandleProtocol (
> + CdcHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbCdcDataPath
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiUsbIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->HandleProtocol (
> + HandleBuffer[Index],
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbRndisDataPath
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
> + break;
> + }
> +
> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> +
> + if (!EFI_ERROR (Status)) {
> + *RndisHandle = HandleBuffer[Index];
> + *CdcUsbIo = UsbIo;
> + FreePool (HandleBuffer);
> + return Status;
> + }
> + }
> + } // End of For loop
> +
> + FreePool (HandleBuffer);
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + USB Rndis Driver Binding Support.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to test.
> + @param[in] 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
> +UsbRndisDriverSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> +}
> +
> +/**
> + USB RNDIS Driver Binding Start.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
> + @retval other This driver does not support this device
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisDriverStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_HANDLE RndisHandle;
> +
> + RndisHandle = ControllerHandle;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID **)&UsbEthPath,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
> + if (IsUsbCdcData (UsbIo)) {
> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
> +
> + // Find the parent RNDIS and update the UsbIo for the CDC device
> + Status = UpdateRndisDevice (
> + UsbEthPath,
> + &UsbRndisDevice
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
> + UsbRndisDevice->UsbIoCdcData = UsbIo;
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + return Status;
> + } else {
> + // Check if RnDis exist
> + Status = FindMatchingRndisDev (
> + ControllerHandle,
> + &UsbIo,
> + &RndisHandle
> + );
> +
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return Status;
> + }
> + }
> + }
> +
> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
> +
> + if (!UsbRndisDevice) {
> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
> +
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Status = LoadAllDescriptor (
> + UsbIo,
> + &UsbRndisDevice->Config
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (
> + UsbIo,
> + &Interface
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
> + UsbRndisDevice->UsbCdcDataHandle = 0;
> + UsbRndisDevice->UsbIo = UsbIo;
> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
> +
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
> +
> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
> + UsbRndisDevice->PacketAlignmentFactor = 0;
> +
> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
> +
> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
> + FindMatchingCdcData (UsbRndisDevice);
> +
> + if (UsbRndisDevice->UsbIoCdcData) {
> + Status = gBS->InstallProtocolInterface (
> + &ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &(UsbRndisDevice->UsbEth)
> + );
> + if (EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> + return Status;
> + }
> +
> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
> + return EFI_SUCCESS;
> + }
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + CheckandStopRndisDevice
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to bind driver to.
> +
> + @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
> +CheckandStopRndisDevice (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **)&UsbIo,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (IsUsbRndis (UsbIo)) {
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
> + return Status;
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + USB Rndis Driver Binding Stop.
> +
> + @param[in] This Protocol instance pointer.
> + @param[in] ControllerHandle Handle of device to stop driver on
> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
> + children is zero stop the entire bus driver.
> + @param[in] 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
> +UsbRndisDriverStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
> +
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + (VOID **)&UsbEthProtocol,
> + This->DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + Status = CheckandStopRndisDevice (This, ControllerHandle);
> + return Status;
> + }
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
> +
> + Status = gBS->CloseProtocol (
> + UsbRndisDevice->UsbCdcDataHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + UsbRndisDevice->UsbCdcDataHandle
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
> + }
> +
> + Status = gBS->UninstallProtocolInterface (
> + ControllerHandle,
> + &gEdkIIUsbEthProtocolGuid,
> + UsbEthProtocol
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + ControllerHandle
> + );
> +
> + FreePool (UsbRndisDevice->Config);
> + FreePool (UsbRndisDevice);
> +
> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Entrypoint of RNDIS Driver.
> +
> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
> + Protocols together with Component Name Protocols.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisEntry (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
> +
> + return gBS->InstallMultipleProtocolInterfaces (
> + &gUsbRndisDriverBinding.DriverBindingHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gUsbRndisDriverBinding,
> + &gEfiComponentName2ProtocolGuid,
> + &gUsbRndisComponentName2,
> + NULL
> + );
> +}
> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> new file mode 100644
> index 000000000000..e3fe737cdef1
> --- /dev/null
> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> @@ -0,0 +1,1718 @@
> +/** @file
> + This file contains code for USB Ethernet descriptor
> + and specific requests implement.
> +
> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "UsbRndis.h"
> +
> +UINT16 gStopBulkInCnt = 0;
> +UINT16 gBlockBulkInCnt = 0;
> +
> +/**
> + Load All of device descriptor.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[out] ConfigDesc A pointer to the configuration descriptor.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
> + buffer specified by DescriptorLength and Descriptor
> + is not large enough to hold the result of the request.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
> + status is returned in Status.
> +**/
> +EFI_STATUS
> +LoadAllDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 TransStatus;
> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
> +
> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = gBS->AllocatePool (
> + EfiBootServicesData,
> + Tmp.TotalLength,
> + (VOID **)ConfigDesc
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbGetDescriptor (
> + UsbIo,
> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
> + 0,
> + Tmp.TotalLength,
> + *ConfigDesc,
> + &TransStatus
> + );
> + return Status;
> +}
> +
> +/**
> + Returns pointer to the next descriptor for the pack of USB descriptors
> + located in continues memory segment
> +
> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
> + @param[in, out] Offset A pointer to the sum of descriptor length.
> +
> + @retval TRUE The request executed successfully.
> + @retval FALSE No next descriptor.
> +
> +**/
> +BOOLEAN
> +NextDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> + IN OUT UINTN *Offset
> + )
> +{
> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
> + return FALSE;
> + }
> +
> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
> + return FALSE;
> + }
> +
> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
> + if ( *Offset >= Desc->TotalLength ) {
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Read Function descriptor
> +
> + @param[in] Config A pointer to all of configuration.
> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
> +
> + @retval EFI_SUCCESS The device capability descriptor was retrieved
> + successfully.
> + @retval EFI_UNSUPPORTED No supported.
> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +GetFunctionalDescriptor (
> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> + IN UINT8 FunDescriptorType,
> + OUT VOID *DataBuffer
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Offset;
> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
> +
> + Status = EFI_NOT_FOUND;
> +
> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
> + if (Interface->DescriptorType == CS_INTERFACE) {
> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
> + switch (FunDescriptorType) {
> + case HEADER_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + case UNION_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
> + );
> + return EFI_SUCCESS;
> + case ETHERNET_FUN_DESCRIPTOR:
> + CopyMem (
> + DataBuffer,
> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
> + );
> + return EFI_SUCCESS;
> + default:
> + Status = EFI_UNSUPPORTED;
> + break;
> + }
> + }
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
> +
> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> +
> +**/
> +VOID
> +GetEndpoint (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Index;
> + UINT32 Result;
> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + if (Interface.NumEndpoints == 0 ) {
> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> + }
> +
> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
> + return;
> + }
> +
> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
> + case USB_ENDPOINT_BULK:
> + if (Endpoint.EndpointAddress & BIT7) {
> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
> + } else {
> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
> + }
> +
> + break;
> + case USB_ENDPOINT_INTERRUPT:
> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
> + break;
> + }
> + }
> +}
> +
> +/**
> + Async USB transfer callback routine.
> +
> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
> + transfer completed successfully.
> + @param[in] DataLength The length of Data received or sent via the Asynchronous
> + Transfer, if transfer successfully completes.
> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
> + @param[in] Status Indicates the result of the asynchronous transfer.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InterruptCallback (
> + IN VOID *Data,
> + IN UINTN DataLength,
> + IN VOID *Context,
> + IN UINT32 Status
> + )
> +{
> + if ((Data == NULL) || (Context == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
> + CopyMem (
> + (EFI_USB_DEVICE_REQUEST *)Context,
> + (EFI_USB_DEVICE_REQUEST *)Data,
> + sizeof (EFI_USB_DEVICE_REQUEST)
> + );
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is used to manage a USB device with an interrupt transfer pipe.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
> + FALSE, the interrupt transfer is deleted from the device's interrupt
> + transfer queue.
> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
> + executed.This parameter is required when IsNewTransfer is TRUE. The
> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
> + The units are in milliseconds.
> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
> +
> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbRndisInterrupt (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN BOOLEAN IsNewTransfer,
> + IN UINTN PollingInterval,
> + IN EFI_USB_DEVICE_REQUEST *Requst
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + UINTN DataLength;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + DataLength = 0;
> +
> + if (IsNewTransfer == TRUE) {
> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + PollingInterval,
> + DataLength,
> + InterruptCallback,
> + Requst
> + );
> +
> + if (Status == EFI_INVALID_PARAMETER) {
> + // Because of Stacked AsyncInterrupt request are not supported
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + 0,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> + } else {
> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + IsNewTransfer,
> + 0,
> + 0,
> + NULL,
> + NULL
> + );
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function is used to read USB interrupt transfer before the response RNDIS message.
> +
> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
> +
> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadRndisResponseInterrupt (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Data[2];
> + UINT32 UsbStatus;
> + UINTN DataLength;
> +
> + DataLength = 8;
> +
> + ZeroMem (Data, sizeof (Data));
> +
> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
> + UsbRndisDevice->UsbIo,
> + UsbRndisDevice->InterrupEndpoint,
> + &Data,
> + &DataLength,
> + 0x20,
> + &UsbStatus
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Mac Address.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbEthMacAddress (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT EFI_MAC_ADDRESS *MacAddress
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
> + CHAR16 *Data;
> + CHAR16 *DataPtr;
> + CHAR16 TmpStr[1];
> + UINT8 Index;
> + UINT8 Hi;
> + UINT8 Low;
> +
> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
> + }
> +
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
> + // To check USB Ethernet functional Descriptor
> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
> + UsbRndisDevice->UsbIo,
> + 0x409, // English-US Language ID
> + UsbEthDescriptor.MacAddress,
> + &Data
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
> + return Status;
> + }
> +
> + DataPtr = Data;
> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Hi = (UINT8)StrHexToUintn (TmpStr);
> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> + DataPtr++;
> + Low = (UINT8)StrHexToUintn (TmpStr);
> + MacAddress->Addr[Index] = (Hi << 4) | Low;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet Bulk transfer data size.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] BulkSize A pointer to the Bulk transfer data size.
> +
> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
> + @retval other Failed to retrieve the bulk transfer data size.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbEthBulkSize (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT UINTN *BulkSize
> + )
> +{
> + EFI_STATUS Status;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
> +
> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
> +
> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
> +
> + Status = RndisControlMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> + );
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
> + UsbRndisDevice->RequestId++;
> + return Status;
> + }
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Header functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbHeaderFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbHeaderFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + HEADER_FUN_DESCRIPTOR,
> + UsbHeaderFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Union functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbUnionFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbUnionFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + UNION_FUN_DESCRIPTOR,
> + UsbUnionFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + Retrieves the USB Ethernet functional Descriptor.
> +
> + This function get the Mac Address, Ethernet statistics, maximum segment size,
> + number of multicast filters, and number of pattern filters from Ethernet
> + functional Descriptor.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
> +
> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisFunDescriptor (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + if (UsbEthFunDescriptor == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = GetFunctionalDescriptor (
> + UsbRndisDevice->Config,
> + ETHERNET_FUN_DESCRIPTOR,
> + UsbEthFunDescriptor
> + );
> + return Status;
> +}
> +
> +/**
> + This request sets the Ethernet device multicast filters as specified in the
> + sequential list of 48 bit Ethernet multicast addresses.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] McastAddr A pointer to the value of the multicast addresses.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisMcastFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN VOID *McastAddr
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Value * 6;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + McastAddr,
> + Request.Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request sets up the specified Ethernet power management pattern filter as
> + described in the data structure.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Number of filters.
> + @param[in] Length Size of the power management pattern filter data.
> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + IN UINT16 Length,
> + IN VOID *PatternFilter
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = Length;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternFilter,
> + Length,
> + &TransStatus
> + );
> +}
> +
> +/**
> + This request retrieves the status of the specified Ethernet power management
> + pattern filter from the device.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value The filter number.
> + @param[out] PatternActive A pointer to the pattern active boolean.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUsbRndisPowerFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value,
> + OUT BOOLEAN *PatternActive
> + )
> +{
> + EFI_USB_DEVICE_REQUEST Request;
> + UINT32 TransStatus;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> + Request.Value = Value;
> + Request.Index = UsbRndisDevice->NumOfInterface;
> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
> +
> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> + UsbRndisDevice->UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + PatternActive,
> + USB_ETH_POWER_FILTER_LENGTH,
> + &TransStatus
> + );
> +}
> +
> +/**
> +
> + Converts PXE filter settings to RNDIS values
> +
> + @param[in] Value PXE filter data.
> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
> +
> +**/
> +VOID
> +ConvertFilter (
> + IN UINT16 Value,
> + OUT UINT16 *CdcFilter
> + )
> +{
> + UINT32 Index;
> + UINT32 Count;
> + static struct BIT_MAP Table[] = {
> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
> + };
> +
> + Count = sizeof (Table)/sizeof (Table[0]);
> +
> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
> + if (Table[Index].Src & Value) {
> + *CdcFilter |= Table[Index].Dst;
> + }
> + }
> +}
> +
> +/**
> +
> + Updates Filter settings on the device.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceiveFilter (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *McastList;
> + UINT8 Count;
> + UINT8 Index1;
> + UINT8 Index2;
> + UINT64 CpbAddr;
> + UINT32 CpbSize;
> + UINT16 SetFilter;
> + PXE_CPB_RECEIVE_FILTERS *Cpb;
> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> +
> + Count = 0;
> + CpbAddr = Cdb->CPBaddr;
> + CpbSize = Cdb->CPBsize;
> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> +
> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> + Nic->RxFilter = (UINT8)SetFilter;
> +
> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
> + if (Cpb != NULL) {
> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> + } else {
> + Nic->McastCount = 0;
> + }
> +
> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + } else {
> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
> + if (EFI_ERROR (Status)) {
> + return PXE_STATCODE_INVALID_PARAMETER;
> + }
> +
> + if (Cpb != NULL) {
> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> + for (Index2 = 0; Index2 < 6; Index2++) {
> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> + }
> + }
> + }
> +
> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> + if (Cpb != NULL) {
> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
> + }
> +
> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> + FreePool (McastList);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to configure device Ethernet packet filter settings.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] Value Packet Filter Bitmap.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetUsbRndisPacketFilter (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 Value
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This request is used to retrieve a statistic based on the feature selector.
> +
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] FeatureSelector Value of the feature selector.
> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_TIMEOUT A timeout occurred executing the request.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetRndisStatistic (
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN UINT16 FeatureSelector,
> + OUT VOID *Statistic
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiStart is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStart (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
> +
> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
> + Status = RndisUndiReset (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiReset (Cdb, Nic);
> + }
> +
> + Status = RndisUndiInitialize (Cdb, Nic);
> + if (EFI_ERROR (Status)) {
> + RndisUndiInitialize (Cdb, Nic);
> + }
> +
> + RndisUndiShutdown (Cdb, Nic);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when Undistop is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiStop (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiGetInitInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetInitInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + PXE_DB_GET_INIT_INFO *Db;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
> +
> + UsbEthDevice = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> +
> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> +
> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when RndisUndiGetConfigInfo is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetConfigInfo (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiInitialize is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_UNSUPPORTED Not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiInitialize (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
> +
> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> +
> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
> +
> + UsbRndisDevice->RequestId++;
> +
> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
> + return Status;
> + }
> +
> + // Only Wired Medium is supported
> + if (RndisInitMsgCmplt.Medium) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
> +
> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
> +
> + return Status;
> +}
> +
> +/**
> + This function is called when UndiReset is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReset (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
> +
> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
> +
> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
> +
> + UsbRndisDevice->RequestId = 1; // Let's start with 1
> +
> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function is called when UndiShutdown is invoked.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiShutdown (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
> +
> + UsbEthDriver = Nic->UsbEth;
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> +
> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
> +
> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
> +
> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
> +
> + if (Status == EFI_DEVICE_ERROR) {
> + Status = EFI_SUCCESS;
> + }
> +
> + UsbRndisDevice->RequestId = 1;
> + return Status;
> +}
> +
> +/**
> + Update the Media connection.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiGetStatus (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transmit the data after appending RNDIS header.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiTransmit (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN VOID *BulkOutData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> +
> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> +
> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
> + if (RndisPacketMsg == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
> +
> + CopyMem (
> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
> + BulkOutData,
> + *DataLength
> + );
> +
> + TransferLength = RndisPacketMsg->MessageLength;
> +
> + Status = RndisTransmitDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
> +
> + FreePool (RndisPacketMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Receives and removes RNDIS header and returns the raw data.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
> + device or received from USB device.
> + @param[in, out] DataLength A pointer to the PacketLength.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
> + @retval EFI_NOT_FOUND No buffer was found in the list.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisUndiReceive (
> + IN PXE_CDB *Cdb,
> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> + IN OUT VOID *BulkInData,
> + IN OUT UINTN *DataLength
> + )
> +{
> + EFI_STATUS Status;
> + USB_RNDIS_DEVICE *UsbRndisDevice;
> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> + UINTN TransferLength;
> + VOID *Buffer;
> + PACKET_LIST *HeadPacket;
> + PACKET_LIST *PacketList;
> +
> + // Check if there is any outstanding packet to receive
> + // The buffer allocated has a linked List followed by the packet.
> +
> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> + Buffer = NULL;
> + HeadPacket = NULL;
> +
> + while (1) {
> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
> + if (Buffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
> + PacketList = (PACKET_LIST *)Buffer;
> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
> + // Save the original address for freeing it up
> + PacketList->OrgBuffer = (UINT8 *)Buffer;
> + TransferLength = UsbRndisDevice->MaxTransferSize;
> +
> + Status = RndisReceiveDataMsg (
> + UsbRndisDevice,
> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> + &TransferLength
> + );
> +
> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
> + FreePool (Buffer);
> + break;
> + }
> +
> + // Collect all the RNDIS packet in Linked list.
> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
> + (TransferLength >= RndisPacketMsg->MessageLength))
> + {
> + // Insert Packet
> + PacketList->RemainingLength = TransferLength;
> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
> + } else {
> + FreePool (Buffer);
> + }
> + }
> +
> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
> +
> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
> +
> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
> +
> + // Check whether the packet is valid RNDIS packet.
> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
> + {
> + if (*DataLength >= RndisPacketMsg->DataLength) {
> + CopyMem (
> + BulkInData,
> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
> + RndisPacketMsg->DataLength
> + );
> +
> + *DataLength = RndisPacketMsg->DataLength;
> +
> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
> +
> + return EFI_SUCCESS;
> + } else {
> + *DataLength = RndisPacketMsg->DataLength;
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + }
> +
> + RemoveEntryList (&HeadPacket->PacketList);
> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
> + point to this function.
> +
> + @param[in] Cdb A pointer to the command descriptor block.
> + @param[in] Nic A pointer to the Network interface controller data.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RndisDummyReturn (
> + IN PXE_CDB *Cdb,
> + IN NIC_DATA *Nic
> + )
> +{
> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's control endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
> +
> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
> +
> +**/
> +EFI_STATUS
> +RndisControlMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> + )
> +{
> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
> + EFI_USB_DEVICE_REQUEST DevReq;
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> + UINT32 SaveResponseType;
> + UINT32 SaveResponseLength;
> + UINT32 Index;
> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
> +
> + SaveResponseType = 0;
> + SaveResponseLength = 0;
> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
> +
> + if (RndisMsgResponse) {
> + SaveResponseType = RndisMsgResponse->MessageType;
> + SaveResponseLength = RndisMsgResponse->MessageLength;
> + }
> +
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataOut,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsg,
> + RndisMsg->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
> +
> + // Error or no response expected
> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
> + return Status;
> + }
> +
> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
> + ReadRndisResponseInterrupt (UsbRndisDevice);
> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> +
> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
> + DevReq.Value = 0;
> + DevReq.Index = 0;
> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &DevReq,
> + EfiUsbDataIn,
> + USB_ETHERNET_TRANSFER_TIMEOUT,
> + RndisMsgResponse,
> + RndisMsgResponse->MessageLength,
> + &UsbStatus
> + );
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
> +
> + PrintRndisMsg (RndisMsgResponse);
> +
> + if (!EFI_ERROR (Status)) {
> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
> +
> + RndisMsgResponse->MessageType = SaveResponseType;
> + RndisMsgResponse->MessageLength = SaveResponseLength;
> + continue;
> + }
> + }
> +
> + return Status;
> + }
> +
> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
> +
> + return EFI_TIMEOUT;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisTransmitDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkOutEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_TX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (Status == EFI_SUCCESS) {
> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function send the RNDIS command through the device's Data endpoint
> +
> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
> +
> + @retval EFI_SUCCESS The request executed successfully.
> +
> +**/
> +EFI_STATUS
> +RndisReceiveDataMsg (
> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
> + IN OUT UINTN *TransferLength
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> +
> + UsbStatus = 0;
> +
> + if (UsbRndisDevice->BulkInEndpoint == 0) {
> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> + }
> +
> + // Use gStopBulkInCnt to stop BulkIn command
> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> + UsbRndisDevice->UsbIoCdcData,
> + UsbRndisDevice->BulkInEndpoint,
> + RndisMsg,
> + TransferLength,
> + USB_RX_ETHERNET_BULK_TIMEOUT,
> + &UsbStatus
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + } else {
> + gStopBulkInCnt--;
> + }
> + } else {
> + Status = EFI_TIMEOUT;
> + *TransferLength = 0;
> + gBlockBulkInCnt++;
> + }
> +
> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> + gBlockBulkInCnt = 0;
> + }
> +
> + PrintRndisMsg (RndisMsg);
> +
> + return Status;
> +}
> +
> +/**
> + Prints RNDIS Header and Data
> +
> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
> +
> +**/
> +VOID
> +PrintRndisMsg (
> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> + )
> +{
> + UINTN Length;
> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
> +
> + Length = 0;
> +
> + switch (RndisMsg->MessageType) {
> + case RNDIS_PACKET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
> + break;
> + case RNDIS_INITIALIZE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> + break;
> + case RNDIS_INITIALIZE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> + break;
> + case RNDIS_HLT_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
> + break;
> + case RNDIS_QUERY_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
> + break;
> + case RNDIS_QUERY_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
> + break;
> + case RNDIS_SET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_MSG);
> + break;
> + case RNDIS_SET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
> + break;
> + case RNDIS_RESET_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
> + break;
> + case RNDIS_RESET_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
> + break;
> + case RNDIS_INDICATE_STATUS_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
> + break;
> + case RNDIS_KEEPALIVE_MSG:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
> + break;
> + case RNDIS_KEEPALIVE_CMPLT:
> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
> + }
> +
> + if (Length) {
> + UINTN Index = 0;
> + for ( ; Length; Length -= 4, Index++) {
> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
> + if (((Index % 4) == 3) && (Index != 0)) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> +
> + if ((Length < 8) && (Length > 4)) {
> + UINT32 Data32;
> + Index++;
> + Data32 = *((UINT32 *)RndisMsg + Index);
> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
> + break;
> + }
> + }
> +
> + if (Index % 4) {
> + DEBUG ((DEBUG_INFO, "\n"));
> + }
> + }
> +}
> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..cb70684f0bf1
> --- /dev/null
> +++ b/UsbNetworkPkg/ReadMe.md
> @@ -0,0 +1,65 @@
> +# UsbNetworkPkg
> +
> +This document is intend to provide package information, include the interface details.
> +
> +# INDEX
> + * [Introduction](#introduction)
> + * [Components](#components)
> + * [[NetworkCommon]](#networkcommon)
> + * [[UsbCdcEcm]](#usbcdcecm)
> + * [[UsbCdcNcm]](#usbcdcncm)
> + * [[UsbRndis]](#usbrndis)
> +
> +# Introduction
> +UsbNetworkPkg provides network functions for USB LAN devices.
> +
> +# Components
> +Below module is included in this package:<br>
> +- NetworkCommon
> +- UsbCdcEcm
> +- UsbCdcNcm
> +- UsbRndis
> +
> +## [NetworkCommon]
> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
> +
> +## Required Components
> +- NetworkPkg
> +
> +## [UsbCdcEcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x06|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbCdcNcm]
> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x0D|0x00|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> +## [UsbRndis]
> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
> +
> +The driver is compatible with the following USB class codes:
> +|Class Code|SubClass Code|Protocol Code|
> +|:--------:|:-----------:|:-----------:|
> +|0x02|0x02|0xFF|
> +|0xEF|0x04|0x01|
> +
> +## Required Components
> +- NetworkCommon
> +- MdeModulePkg(USB bus driver)
> +
> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
> new file mode 100644
> index 000000000000..f8ccccdb0830
> --- /dev/null
> +++ b/UsbNetworkPkg/ReleaseNotes.md
> @@ -0,0 +1,11 @@
> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
> +
> +# Release History<!-- omit in toc -->
> +- [1.00](#100)
> +
> +## 1.00
> +
> +**Release Date:** Mar 10, 2022
> +
> +**New Features**
> +- UsbNetworkPkg first release.
> --
> 2.35.1.windows.2
> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [edk2-devel] [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-04-07 2:49 ` RichardHo [何明忠]
@ 2023-04-07 2:52 ` Rebecca Cran
2023-04-07 11:47 ` Rebecca Cran
1 sibling, 0 replies; 11+ messages in thread
From: Rebecca Cran @ 2023-04-07 2:52 UTC (permalink / raw)
To: devel, richardho
Cc: Andrew Fish, Leif Lindholm, Kinney, Michael D, Michael Kubacki,
'Zhiguang Liu', gaoliming, Tinh Nguyen,
Tony Lo (羅金松)
Thanks. I wonder if it’s an issue with Git on Windows: I’ll do some testing tomorrow.
—
Rebecca
On Thu, Apr 6, 2023, at 8:49 PM, RichardHo [何明忠] via groups.io wrote:
> Hi Rebecca,
>
> I have already run the SetupGit.py before send the mail.
> (Use git send-email --transfer-encoding=8bit --annotate --suppress-from
> --to devel@edk2.groups.io *.patch to send mail)
>
> Below is my .git/config
>
> [core]
> repositoryformatversion = 0
> filemode = false
> bare = false
> logallrefupdates = true
> symlinks = false
> ignorecase = true
> abbrev = 12
> attributesFile = D:/EDKII-Upstream/edk2/BaseTools/Conf/gitattributes
> whitespace = cr-at-eol
> [remote "origin"]
> url = https://github.com/tianocore/edk2.git
> fetch = +refs/heads/*:refs/remotes/origin/*
> [branch "master"]
> remote = origin
> merge = refs/heads/master
> [am]
> keepcr = True
> signoff = True
> [cherry-pick]
> signoff = True
> [color]
> diff = True
> grep = auto
> [commit]
> signoff = True
> [diff]
> algorithm = patience
> orderFile = D:/EDKII-Upstream/edk2/BaseTools/Conf/diff.order
> renames = copies
> statGraphWidth = 20
> [diff "ini"]
> xfuncname = ^\\[[A-Za-z0-9_., ]+]
> [format]
> coverLetter = True
> numbered = True
> signoff = False
> [log]
> mailmap = True
> [notes]
> rewriteRef = refs/notes/commits
> [sendemail]
> chainreplyto = False
> thread = True
> transferEncoding = 8bit
> to = devel@edk2.groups.io
>
> Thanks,
> Richard
>
> -----Original Message-----
> From: Rebecca Cran <rebecca@bsdio.com>
> Sent: 2023年4月7日 9:57 AM
> To: Richard Ho (何明忠) <RichardHo@ami.com>; devel@edk2.groups.io
> Cc: Andrew Fish <afish@apple.com>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Michael D Kinney
> <michael.d.kinney@intel.com>; Michael Kubacki
> <mikuback@linux.microsoft.com>; Zhiguang Liu <zhiguang.liu@intel.com>;
> Liming Gao <gaoliming@byosoft.com.cn>; Tinh Nguyen
> <tinhnguyen@os.amperecomputing.com>; Tony Lo (羅金松) <TonyLo@ami.com>
> Subject: [EXTERNAL] Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB
> RNDIS devices support
>
>
> **CAUTION: The e-mail below is from an external source. Please exercise
> caution before opening attachments, clicking links, or following
> guidance.**
>
> Your patches are still coming through rather mangled, unfortunately.
>
> You should be sending them as 8bit, not quoted-printable - the
> BaseTools/Scripts/SetupGit.py script will configure the settings for you.
>
> Also, there should be a cover letter with the patch series: that script
> configures "git format-patch" to generate one.
>
>
> If you've already run SetupGit.py, could you tell me what .git/config in
> your edk2 clone contains, please?
>
>
> --
> Rebecca Cran
>
>
> On 3/9/23 12:51 AM, Richard Ho (何明忠) wrote:
>> This driver provides UEFI driver for USB RNDIS device
>>
>> Signed-off-by: Richard Ho <richardho@ami.com>
>> Cc: Andrew Fish <afish@apple.com>
>> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
>> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
>> Cc: Liming Gao <gaoliming@byosoft.com.cn>
>> Cc: Rebecca Cran <rebecca@bsdio.com>
>> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
>> Reviewed-by: Tony Lo <tonylo@ami.com>
>> ---
>> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
>> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
>> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
>> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
>> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
>> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
>> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
>> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
>> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
>> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
>> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
>> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
>> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
>> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
>> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
>> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
>> UsbNetworkPkg/ReadMe.md | 65 +
>> UsbNetworkPkg/ReleaseNotes.md | 11 +
>> 18 files changed, 7452 insertions(+)
>> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
>> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
>> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> create mode 100644 UsbNetworkPkg/ReadMe.md
>> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>>
>> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
>> new file mode 100644
>> index 000000000000..30e4e4c8aac7
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
>> @@ -0,0 +1,46 @@
>> +## @file
>> +# This package defines Usb network specific interfaces and library classes
>> +# as well as configuration for standard edk2 packages.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + DEC_SPECIFICATION = 0x00010005
>> + PACKAGE_NAME = UsbNetworkPkg
>> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
>> + PACKAGE_VERSION = 0.1
>> +
>> +[Includes]
>> + Include
>> +
>> +[Protocols]
>> + ## Include/Protocol/EdkIIUsbEthernet.h
>> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
>> +
>> +[Guids]
>> + ## Usb Network package token space GUID
>> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
>> +
>> +[PcdsFeatureFlag]
>> +
>> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
>> +
>> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
>> +
>> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
>> +
>> +[PcdsFixedAtBuild, PcdsPatchableInModule]
>> + ## Support rate limiting
>> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
>> +
>> + ## The rate limiting Credit value is check in rate limiter event.
>> + # It is to control the RateLimitingCreditCount max value.
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
>> +
>> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> new file mode 100644
>> index 000000000000..a3316b1d4a89
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> @@ -0,0 +1,9 @@
>> +## @file
>> +# Global DSC definitions to be included into project DSC file.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Components.X64]
>> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> new file mode 100644
>> index 000000000000..544df8404c64
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
>> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
>> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
>> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> +!endif
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> new file mode 100644
>> index 000000000000..85a309bcf567
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> @@ -0,0 +1,23 @@
>> +## @file
>> +# Global switches enable/disable project features.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
>> + DEFINE PEI=IA32
>> + DEFINE DXE=X64
>> +!else
>> + DEFINE PEI=COMMON
>> + DEFINE DXE=COMMON
>> +!endif
>> +
>> +[Packages]
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[PcdsFeatureFlag]
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
>> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> new file mode 100644
>> index 000000000000..10616d97edb4
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
>> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
>> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
>> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> +!endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> new file mode 100644
>> index 000000000000..8923102bc350
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> @@ -0,0 +1,49 @@
>> +## @file
>> +# This is Usb Network Common driver for DXE phase.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = NetworkCommon
>> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = NetworkCommonEntry
>> +
>> +[Sources]
>> + DriverBinding.c
>> + DriverBinding.h
>> + ComponentName.c
>> + PxeFunction.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + MdeModulePkg/MdeModulePkg.dec
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[LibraryClasses]
>> + UefiDriverEntryPoint
>> + UefiBootServicesTableLib
>> + UefiLib
>> + DebugLib
>> + UefiUsbLib
>> + MemoryAllocationLib
>> + BaseMemoryLib
>> +
>> +[Protocols]
>> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
>> + gEfiUsbIoProtocolGuid
>> + gEfiDevicePathProtocolGuid
>> + gEfiDriverBindingProtocolGuid
>> + gEdkIIUsbEthProtocolGuid
>> +
>> +[Pcd]
>> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> new file mode 100644
>> index 000000000000..64205e427745
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> @@ -0,0 +1,42 @@
>> +## @file
>> +# This is Usb Rndis driver for DXE phase.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = UsbRndis
>> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = UsbRndisEntry
>> +
>> +[Sources]
>> + UsbRndis.c
>> + UsbRndis.h
>> + UsbRndisFunction.c
>> + ComponentName.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[LibraryClasses]
>> + UefiDriverEntryPoint
>> + UefiBootServicesTableLib
>> + UefiLib
>> + DebugLib
>> + UefiUsbLib
>> + MemoryAllocationLib
>> + BaseMemoryLib
>> +
>> +[Protocols]
>> + gEfiUsbIoProtocolGuid
>> + gEfiDevicePathProtocolGuid
>> + gEfiDriverBindingProtocolGuid
>> + gEdkIIUsbEthProtocolGuid
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> new file mode 100644
>> index 000000000000..f54946c7aa69
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> @@ -0,0 +1,878 @@
>> +/** @file
>> + Header file contains code for USB Ethernet Protocol
>> + definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
>> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
>> +
>> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
>> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
>> +
>> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
>> +
>> +#define USB_CDC_CLASS 0x02
>> +#define USB_CDC_ACM_SUBCLASS 0x02
>> +#define USB_CDC_ECM_SUBCLASS 0x06
>> +#define USB_CDC_NCM_SUBCLASS 0x0D
>> +#define USB_CDC_DATA_CLASS 0x0A
>> +#define USB_CDC_DATA_SUBCLASS 0x00
>> +#define USB_NO_CLASS_PROTOCOL 0x00
>> +#define USB_NCM_NTB_PROTOCOL 0x01
>> +#define USB_VENDOR_PROTOCOL 0xFF
>> +
>> +// Type Values for the DescriptorType Field
>> +#define CS_INTERFACE 0x24
>> +#define CS_ENDPOINT 0x25
>> +
>> +// Descriptor SubType in Functional Descriptors
>> +#define HEADER_FUN_DESCRIPTOR 0x00
>> +#define UNION_FUN_DESCRIPTOR 0x06
>> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
>> +
>> +#define MAX_LAN_INTERFACE 0x10
>> +
>> +// Table 20: Class-Specific Notification Codes
>> +#define USB_CDC_NETWORK_CONNECTION 0x00
>> +
>> +// 6.3.1 NetworkConnection
>> +#define NETWORK_CONNECTED 0x01
>> +#define NETWORK_DISCONNECT 0x00
>> +
>> +// USB Header functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT16 BcdCdc;
>> +} USB_HEADER_FUN_DESCRIPTOR;
>> +
>> +// USB Union Functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT8 MasterInterface;
>> + UINT8 SlaveInterface;
>> +} USB_UNION_FUN_DESCRIPTOR;
>> +
>> +// USB Ethernet Functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT8 MacAddress;
>> + UINT32 EthernetStatistics;
>> + UINT16 MaxSegmentSize;
>> + UINT16 NumberMcFilters;
>> + UINT8 NumberPowerFilters;
>> +} USB_ETHERNET_FUN_DESCRIPTOR;
>> +
>> +typedef struct {
>> + UINT32 UsBitRate;
>> + UINT32 DsBitRate;
>> +} USB_CONNECT_SPEED_CHANGE;
>> +
>> +// Request Type Codes for USB Ethernet
>> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
>> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
>> +
>> +// Class-Specific Request Codes for Ethernet subclass
>> +// USB ECM 1.2 specification, Section 6.2
>> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
>> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
>> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
>> +#define SET_ETH_PACKET_FILTER_REQ 0x43
>> +#define GET_ETH_STATISTIC_REQ 0x44
>> +
>> +// USB ECM command request length
>> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
>> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
>> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
>> +
>> +// USB Ethernet Packet Filter Bitmap
>> +// USB ECM 1.2 specification, Section 6.2.4
>> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
>> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
>> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
>> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
>> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
>> +
>> +// USB Ethernet Statistics Feature Selector Codes
>> +// USB ECM 1.2 specification, Section 6.2.5
>> +#define USB_ETH_XMIT_OK 0x01
>> +#define USB_ETH_RCV_OK 0x02
>> +#define USB_ETH_XMIT_ERROR 0x03
>> +#define USB_ETH_RCV_ERROR 0x04
>> +#define USB_ETH_RCV_NO_BUFFER 0x05
>> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
>> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
>> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
>> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
>> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
>> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
>> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
>> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
>> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
>> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
>> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
>> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
>> +#define USB_ETH_RCV_CRC_ERROR 0x12
>> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
>> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
>> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
>> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
>> +#define USB_ETH_XMIT_DEFERRED 0x17
>> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
>> +#define USB_ETH_RCV_OVERRUN 0x19
>> +#define USB_ETH_XMIT_UNDERRUN 0x1A
>> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
>> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
>> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
>> +
>> +// NIC Information
>> +typedef struct {
>> + UINT32 Signature;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + UINT16 InterrupOpFlag;
>> + UINT64 MappedAddr;
>> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
>> + UINT8 McastCount;
>> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
>> + UINT8 TxBufferCount;
>> + UINT16 State;
>> + BOOLEAN CanTransmit;
>> + UINT16 ReceiveStatus;
>> + UINT8 RxFilter;
>> + UINT32 RxFrame;
>> + UINT32 TxFrame;
>> + UINT16 NetworkConnect;
>> + UINT8 CableDetect;
>> + UINT16 MaxSegmentSize;
>> + EFI_MAC_ADDRESS MacAddr;
>> + PXE_CPB_START_31 PxeStart;
>> + PXE_CPB_INITIALIZE PxeInit;
>> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
>> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
>> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
>> + EFI_USB_DEVICE_REQUEST Request;
>> + EFI_EVENT RateLimiter;
>> + UINT32 RateLimitingCredit;
>> + UINT32 RateLimitingCreditCount;
>> + UINT32 RateLimitingPollTimer;
>> + BOOLEAN RateLimitingEnable;
>> +} NIC_DATA;
>> +
>> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
>> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
>> +
>> +/**
>> + This command is used to determine the operational state of the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to change the UNDI operational state from stopped to started.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to change the UNDI operational state from started to stopped.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to retrieve initialization information that is
>> + needed by drivers and applications to initialized UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to retrieve configuration information about
>> + the NIC being controlled by the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and reinitializes the UNDI
>> + with the same parameters provided in the Initialize command.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Shutdown command resets the network adapter and leaves it in a
>> + safe state for another driver to initialize.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Interrupt Enables command can be used to read and/or change
>> + the current external interrupt enable settings.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and change receive filters and,
>> + if supported, read and change the multicast MAC address filter list.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to get current station and broadcast MAC addresses
>> + and, if supported, to change the current station MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and write (if supported by NIC H/W)
>> + nonvolatile storage on the NIC.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command returns the current interrupt status and/or the
>> + transmitted buffer addresses and the current media status.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to fill the media header(s) in transmit packet(s).
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Transmit command is used to place a packet into the transmit queue.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + When the network adapter has received a frame, this command is used
>> + to copy the frame into driver/application storage.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] DbAddr Data Block Address.
>> + @param[in] DbSize Data Block Size.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] PacketLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
>> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
>> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *Packet,
>> + IN OUT UINTN *PacketLength
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] PacketLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
>> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
>> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *Packet,
>> + IN OUT UINTN *PacketLength
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with an interrupt transfer pipe.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
>> + FALSE, the interrupt transfer is deleted from the device's interrupt
>> + transfer queue.
>> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
>> + executed.This parameter is required when IsNewTransfer is TRUE. The
>> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
>> + The units are in milliseconds.
>> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
>> +
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Request
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet Mac Address.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet Bulk transfer data size.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] BulkSize A pointer to the Bulk transfer data size.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + );
>> +
>> +/**
>> + Retrieves the USB Header functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + );
>> +
>> +/**
>> + Retrieves the USB Union functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + );
>> +
>> +/**
>> + This request sets the Ethernet device multicast filters as specified in the
>> + sequential list of 48 bit Ethernet multicast addresses.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] McastAddr A pointer to the value of the multicast addresses.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + );
>> +
>> +/**
>> + This request sets up the specified Ethernet power management pattern filter as
>> + described in the data structure.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] Length Size of the power management pattern filter data.
>> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + );
>> +
>> +/**
>> + This request retrieves the status of the specified Ethernet power management
>> + pattern filter from the device.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value The filter number.
>> + @param[out] PatternActive A pointer to the pattern active boolean.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + OUT BOOLEAN *PatternActive
>> + );
>> +
>> +/**
>> + This request is used to configure device Ethernet packet filter settings.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Packet Filter Bitmap.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + );
>> +
>> +/**
>> + This request is used to retrieve a statistic based on the feature selector.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] FeatureSelector Value of the feature selector.
>> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 FeatureSelector,
>> + OUT VOID *Statistic
>> + );
>> +
>> +typedef struct {
>> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
>> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
>> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
>> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
>> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
>> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
>> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
>> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
>> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
>> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
>> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
>> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
>> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
>> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
>> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
>> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
>> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
>> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
>> +} EDKII_USB_ETHERNET_UNDI;
>> +
>> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
>> +// descriptor and specific requests.
>> +struct _EDKII_USB_ETHERNET_PROTOCOL {
>> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
>> + // for calling the UNDI child functions
>> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
>> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
>> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
>> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
>> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
>> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
>> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
>> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
>> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
>> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
>> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
>> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
>> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
>> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
>> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
>> +};
>> +
>> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> new file mode 100644
>> index 000000000000..0416ce132302
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> @@ -0,0 +1,266 @@
>> +/** @file
>> + Header file for for USB network common driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef _DRIVER_BINDING_H_
>> +#define _DRIVER_BINDING_H_
>> +
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/UefiUsbLib.h>
>> +#include <Protocol/UsbIo.h>
>> +#include <Protocol/NetworkInterfaceIdentifier.h>
>> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
>> +
>> +#define NETWORK_COMMON_DRIVER_VERSION 1
>> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
>> +#define RX_BUFFER_COUNT 32
>> +#define TX_BUFFER_COUNT 32
>> +#define MEMORY_REQUIRE 0
>> +
>> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
>> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
>> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
>> +
>> +#pragma pack(1)
>> +typedef struct {
>> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
>> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
>> + UINT16 Protocol;
>> +} EthernetHeader;
>> +#pragma pack()
>> +
>> +typedef struct {
>> + UINTN Signature;
>> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
>> + EFI_HANDLE DeviceHandle;
>> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
>> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
>> + NIC_DATA NicInfo;
>> + VOID *ReceiveBuffer;
>> +} NIC_DEVICE;
>> +
>> +typedef VOID (*API_FUNC)(
>> + PXE_CDB *,
>> + NIC_DATA *
>> + );
>> +
>> +extern PXE_SW_UNDI *gPxe;
>> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
>> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + );
>> +
>> +VOID
>> +PxeStructInit (
>> + OUT PXE_SW_UNDI *PxeSw
>> + );
>> +
>> +VOID
>> +UpdateNicNum (
>> + IN NIC_DATA *Nic,
>> + IN OUT PXE_SW_UNDI *PxeSw
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UndiApiEntry (
>> + IN UINT64 Cdb
>> + );
>> +
>> +UINTN
>> +MapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + OUT UINT64 MappedAddr
>> + );
>> +
>> +VOID
>> +UnMapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + IN UINT64 MappedAddr
>> + );
>> +
>> +VOID
>> +UndiGetState (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiInterruptEnable (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStationAddress (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStatistics (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiMcastIp2Mac (
>> + IN OUT PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiNvData (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiFillHeader (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +UINT16
>> +Initialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +UINT16
>> +Transmit (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN UINT16 OpFlags
>> + );
>> +
>> +UINT16
>> +Receive (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN OUT UINT64 DbAddr
>> + );
>> +
>> +UINT16
>> +SetFilter (
>> + IN NIC_DATA *Nic,
>> + IN UINT16 SetFilter,
>> + IN UINT64 CpbAddr,
>> + IN UINT32 CpbSize
>> + );
>> +
>> +UINT16
>> +Statistics (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + );
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> new file mode 100644
>> index 000000000000..775807042460
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> @@ -0,0 +1,586 @@
>> +/** @file
>> + Header file for for USB Rndis driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef _USB_RNDIS_H_
>> +#define _USB_RNDIS_H_
>> +
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/UefiUsbLib.h>
>> +#include <Protocol/UsbIo.h>
>> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
>> +
>> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
>> +
>> +typedef struct {
>> + UINT32 Signature;
>> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
>> + EFI_HANDLE UsbCdcDataHandle;
>> + EFI_HANDLE UsbRndisHandle;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
>> + EFI_USB_CONFIG_DESCRIPTOR *Config;
>> + UINT8 NumOfInterface;
>> + UINT8 BulkInEndpoint;
>> + UINT8 BulkOutEndpoint;
>> + UINT8 InterrupEndpoint;
>> + EFI_MAC_ADDRESS MacAddress;
>> + UINT32 RequestId;
>> + UINT32 Medium;
>> + UINT32 MaxPacketsPerTransfer;
>> + UINT32 MaxTransferSize;
>> + UINT32 PacketAlignmentFactor;
>> + LIST_ENTRY ReceivePacketList;
>> +} USB_RNDIS_DEVICE;
>> +
>> +#define USB_RNDIS_DRIVER_VERSION 1
>> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
>> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
>> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
>> +
>> +#define LAN_BULKIN_CMD_CONTROL 1
>> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
>> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
>> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
>> +#define RNDIS_RESERVED_BYTE_LENGTH 8
>> +
>> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
>> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
>> +
>> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
>> +
>> +struct BIT_MAP {
>> + unsigned int Src;
>> + unsigned int Dst;
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + );
>> +
>> +EFI_STATUS
>> +LoadAllDescriptor (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
>> + );
>> +
>> +BOOLEAN
>> +NextDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
>> + IN OUT UINTN *Offset
>> + );
>> +
>> +EFI_STATUS
>> +GetFunctionalDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
>> + IN UINT8 FunDescriptorType,
>> + OUT VOID *DataBuffer
>> + );
>> +
>> +VOID
>> +GetEndpoint (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisInterrupt (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Requst
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +InterruptCallback (
>> + IN VOID *Data,
>> + IN UINTN DataLength,
>> + IN VOID *Context,
>> + IN UINT32 Status
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbEthMacAddress (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbEthBulkSize (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisDummyReturn (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN VOID *BulkOutData,
>> + IN OUT UINTN *DataLength
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *BulkInData,
>> + IN OUT UINTN *DataLength
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbHeaderFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbUnionFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisMcastFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN BOOLEAN *PatternActive
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPacketFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetRndisStatistic (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *Statistic
>> + );
>> +
>> +EFI_STATUS
>> +RndisControlMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
>> + );
>> +
>> +EFI_STATUS
>> +RndisTransmitDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + UINTN *TransferLength
>> + );
>> +
>> +EFI_STATUS
>> +RndisReceiveDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + UINTN *TransferLength
>> + );
>> +
>> +VOID
>> +PrintRndisMsg (
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
>> + );
>> +
>> +#define RNDIS_MAJOR_VERSION 0x00000001
>> +#define RNDIS_MINOR_VERSION 0x00000000
>> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
>> +
>> +#define RNDIS_PACKET_MSG 0x00000001
>> +#define RNDIS_INITIALIZE_MSG 0x00000002
>> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
>> +#define RNDIS_HLT_MSG 0x00000003
>> +#define RNDIS_QUERY_MSG 0x00000004
>> +#define RNDIS_QUERY_CMPLT 0x80000004
>> +#define RNDIS_SET_MSG 0x00000005
>> +#define RNDIS_SET_CMPLT 0x80000005
>> +#define RNDIS_RESET_MSG 0x00000006
>> +#define RNDIS_RESET_CMPLT 0x80000006
>> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
>> +#define RNDIS_KEEPALIVE_MSG 0x00000008
>> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
>> +
>> +#define RNDIS_STATUS_SUCCESS 0x00000000
>> +#define RNDIS_STATUS_FAILURE 0xC0000001
>> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
>> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
>> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
>> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
>> +
>> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
>> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
>> +
>> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
>> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
>> +
>> +//
>> +// General Objects
>> +//
>> +// Taken from NTDDNDIS.H
>> +#define OID_GEN_SUPPORTED_LIST 0x00010101
>> +#define OID_GEN_HARDWARE_STATUS 0x00010102
>> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
>> +#define OID_GEN_MEDIA_IN_USE 0x00010104
>> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
>> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
>> +#define OID_GEN_LINK_SPEED 0x00010107
>> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
>> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
>> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
>> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
>> +#define OID_GEN_VENDOR_ID 0x0001010C
>> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
>> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
>> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
>> +#define OID_GEN_DRIVER_VERSION 0x00010110
>> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
>> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
>> +#define OID_GEN_MAC_OPTIONS 0x00010113
>> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
>> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
>> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
>> +
>> +#define OID_GEN_XMIT_OK 0x00020101
>> +#define OID_GEN_RCV_OK 0x00020102
>> +#define OID_GEN_XMIT_ERROR 0x00020103
>> +#define OID_GEN_RCV_ERROR 0x00020104
>> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
>> +
>> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
>> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
>> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
>> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
>> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
>> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
>> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
>> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
>> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
>> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
>> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
>> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
>> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
>> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
>> +
>> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
>> +//
>> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
>> +//
>> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
>> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
>> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
>> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
>> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
>> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
>> +#define NDIS_PACKET_TYPE_SMT 0x0040
>> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
>> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
>> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
>> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
>> +#define NDIS_PACKET_TYPE_GROUP 0x1000
>> +
>> +#pragma pack(1)
>> +
>> +typedef struct _REMOTE_NDIS_MSG_HEADER {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> +} REMOTE_NDIS_MSG_HEADER;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 MajorVersion;
>> + UINT32 MinorVersion;
>> + UINT32 MaxTransferSize;
>> +} REMOTE_NDIS_INITIALIZE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> +} REMOTE_NDIS_HALT_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Oid;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_QUERY_MSG;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_MSG QueryMsg;
>> + UINT8 Addr[6];
>> +} REMOTE_NDIS_QUERY_MAC_MSG;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_MSG QueryMsg;
>> + UINT32 MaxTotalSize;
>> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Oid;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_SET_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_RESET_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Status;
>> + UINT32 StatusBufferLength;
>> + UINT32 StatusBufferOffset;
>> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
>> +
>> +typedef struct {
>> + UINT32 DiagStatus;
>> + UINT32 ErrorOffset;
>> +} RNDIS_DIAGNOSTIC_INFO;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> +} REMOTE_NDIS_KEEPALIVE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> + UINT32 MajorVersion;
>> + UINT32 MinorVersion;
>> + UINT32 DeviceFlags;
>> + UINT32 Medium;
>> + UINT32 MaxPacketsPerTransfer;
>> + UINT32 MaxTransferSize;
>> + UINT32 PacketAlignmentFactor;
>> + UINT64 Reserved;
>> +} REMOTE_NDIS_INITIALIZE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> +} REMOTE_NDIS_QUERY_CMPLT;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
>> + UINT8 Addr[6];
>> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
>> + UINT32 MaxTotalSize;
>> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> +} REMOTE_NDIS_SET_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Status;
>> + UINT32 AddressingReset;
>> +} REMOTE_NDIS_RESET_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 DataOffset;
>> + UINT32 DataLength;
>> + UINT32 OutOfBandDataOffset;
>> + UINT32 OutOfBandDataLength;
>> + UINT32 NumOutOfBandDataElements;
>> + UINT32 PerPacketInfoOffset;
>> + UINT32 PerPacketInfoLength;
>> + UINT32 Reserved1;
>> + UINT32 Reserved2;
>> +} REMOTE_NDIS_PACKET_MSG;
>> +
>> +typedef struct {
>> + UINT32 Size;
>> + UINT32 Type;
>> + UINT32 ClassInformationOffset;
>> +} OUT_OF_BAND_DATA_RECORD;
>> +
>> +typedef struct {
>> + UINT32 Size;
>> + UINT32 Type;
>> + UINT32 ClassInformationOffset;
>> +} PER_PACKET_INFO_DATA_RECORD;
>> +
>> +typedef struct {
>> + LIST_ENTRY PacketList;
>> + UINT8 *OrgBuffer;
>> + UINTN RemainingLength;
>> + UINT8 *PacketStartBuffer; // Variable size data to follow
>> +} PACKET_LIST;
>> +
>> +#pragma pack()
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> new file mode 100644
>> index 000000000000..e83469e13079
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> @@ -0,0 +1,263 @@
>> +/** @file
>> + This file contains code for USB network common driver
>> + component name definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
>> + {
>> + "eng;en",
>> + L"Network Common Driver"
>> + },
>> + {
>> + NULL,
>> + NULL
>> + }
>> +};
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
>> + NetworkCommonComponentNameGetDriverName,
>> + NetworkCommonComponentNameGetControllerName,
>> + "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
>> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
>> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
>> + "en"
>> +};
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Language 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[out] DriverName 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
>> +NetworkCommonComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + )
>> +{
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gNetworkCommonDriverNameTable,
>> + DriverName,
>> + (BOOLEAN)(This == &gNetworkCommonComponentName)
>> + );
>> +}
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
>> + @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
>> +NetworkCommonComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + )
>> +{
>> + EFI_STATUS Status;
>> + CHAR16 *HandleName;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
>> +
>> + if (!Language || !ControllerName) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + if (ChildHandle == NULL) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + //
>> + // Make sure this driver is currently managing ControllerHandle
>> + //
>> + Status = EfiTestManagedDevice (
>> + Controller,
>> + gNetworkCommonDriverBinding.DriverBindingHandle,
>> + &gEdkIIUsbEthProtocolGuid
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + //
>> + // Make sure this driver produced ChildHandle
>> + //
>> + Status = EfiTestChildHandle (
>> + Controller,
>> + ChildHandle,
>> + &gEdkIIUsbEthProtocolGuid
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *ControllerName = HandleName;
>> +
>> + if (gNetworkCommonControllerNameTable != NULL) {
>> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
>> + gNetworkCommonControllerNameTable = NULL;
>> + }
>> +
>> + Status = AddUnicodeString2 (
>> + "eng",
>> + gNetworkCommonComponentName.SupportedLanguages,
>> + &gNetworkCommonControllerNameTable,
>> + HandleName,
>> + TRUE
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = AddUnicodeString2 (
>> + "en",
>> + gNetworkCommonComponentName2.SupportedLanguages,
>> + &gNetworkCommonControllerNameTable,
>> + HandleName,
>> + FALSE
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gNetworkCommonControllerNameTable,
>> + ControllerName,
>> + (BOOLEAN)(This == &gNetworkCommonComponentName)
>> + );
>> + }
>> +
>> + return EFI_UNSUPPORTED;
>> +}
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> new file mode 100644
>> index 000000000000..23b791362091
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> @@ -0,0 +1,595 @@
>> +/** @file
>> + This file contains code for USB network binding driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +PXE_SW_UNDI *gPxe = NULL;
>> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
>> +UINT32 gRateLimitingCredit;
>> +UINT32 gRateLimitingPollTimer;
>> +BOOLEAN gRateLimitingEnable;
>> +
>> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
>> + NetworkCommonSupported,
>> + NetworkCommonDriverStart,
>> + NetworkCommonDriverStop,
>> + NETWORK_COMMON_DRIVER_VERSION,
>> + NULL,
>> + NULL
>> +};
>> +
>> +/**
>> + Create MAC Device Path
>> +
>> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
>> + @retval EFI_SUCCESS MAC device path created successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +CreateMacDevicePath (
>> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
>> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> + MAC_ADDR_DEVICE_PATH MacAddrNode;
>> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
>> + UINT8 *DevicePath;
>> + UINT16 TotalLength;
>> + UINT16 BaseLength;
>> +
>> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
>> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
>> +
>> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
>> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
>> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
>> + MacAddrNode.Header.Length[1] = 0;
>> +
>> + EndNode = BaseDev;
>> +
>> + while (!IsDevicePathEnd (EndNode)) {
>> + EndNode = NextDevicePathNode (EndNode);
>> + }
>> +
>> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
>> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
>> +
>> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
>> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
>> + DevicePath += BaseLength;
>> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
>> + DevicePath += sizeof (MacAddrNode);
>> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Support.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to test.
>> + @param[in] 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
>> +NetworkCommonSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Start.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
>> + @retval other This driver does not support this device
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + EFI_MAC_ADDRESS MacAddress;
>> + UINTN BulkDataSize;
>> + NIC_DEVICE *NicDevice;
>> + UINT8 *TmpPxePointer;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbEthPath,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
>> +
>> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
>> + ASSERT_EFI_ERROR (Status);
>> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
>> + if (!NicDevice) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + // for alignment adjustment
>> + if (gPxe == NULL) {
>> + TmpPxePointer = NULL;
>> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
>> + if (!TmpPxePointer) {
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + return EFI_OUT_OF_RESOURCES;
>> + } else {
>> + // check for paragraph alignment here
>> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
>> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
>> + } else {
>> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
>> + }
>> +
>> + if (!gPxe) {
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + PxeStructInit (gPxe);
>> + }
>> + }
>> +
>> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
>> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
>> +
>> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
>> +
>> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
>> +
>> + NicDevice->NicInfo.UsbEth = UsbEth;
>> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
>> + NicDevice->NicInfo.CableDetect = 0;
>> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
>> +
>> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
>> +
>> + NicDevice->NicInfo.TxBufferCount = 0;
>> +
>> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
>> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
>> + } else {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> +
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = CreateMacDevicePath (
>> + &NicDevice->DevPath,
>> + UsbEthPath,
>> + &NicDevice->NicInfo
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + UpdateNicNum (NULL, gPxe);
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> + }
>> +
>> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
>> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
>> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
>> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
>> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
>> + NicDevice->NiiProtocol.ImageSize = 0;
>> + NicDevice->NiiProtocol.ImageAddr = 0;
>> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
>> +
>> + NicDevice->NiiProtocol.StringId[0] = 'U';
>> + NicDevice->NiiProtocol.StringId[1] = 'N';
>> + NicDevice->NiiProtocol.StringId[2] = 'D';
>> + NicDevice->NiiProtocol.StringId[3] = 'I';
>> + NicDevice->DeviceHandle = NULL;
>> +
>> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
>> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
>> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
>> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
>> + NicDevice->NicInfo.RateLimiter = NULL;
>> +
>> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &NicDevice->DeviceHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
>> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> +
>> + if (NicDevice->DevPath != NULL) {
>> + FreePool (NicDevice->DevPath);
>> + }
>> +
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + NicDevice->DeviceHandle,
>> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> + );
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Stop.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to stop driver on
>> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
>> + children is zero stop the entire bus driver.
>> + @param[in] 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
>> +NetworkCommonDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + BOOLEAN AllChildrenStopped;
>> + UINTN Index;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + NIC_DEVICE *NicDevice;
>> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
>> +
>> + if (NumberOfChildren == 0) {
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + (VOID **)&NiiProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_SUCCESS;
>> + }
>> +
>> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
>> + Status = gBS->UninstallMultipleProtocolInterfaces (
>> + ControllerHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + FreePool (NicDevice->DevPath);
>> + FreePool (NicDevice);
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_SUCCESS;
>> + }
>> +
>> + AllChildrenStopped = TRUE;
>> +
>> + for (Index = 0; Index < NumberOfChildren; Index++) {
>> + Status = gBS->OpenProtocol (
>> + ChildHandleBuffer[Index],
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + (VOID **)&NiiProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + AllChildrenStopped = FALSE;
>> + continue;
>> + }
>> +
>> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ChildHandleBuffer[Index]
>> + );
>> +
>> + Status = gBS->UninstallMultipleProtocolInterfaces (
>> + ChildHandleBuffer[Index],
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ChildHandleBuffer[Index],
>> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> + );
>> + } else {
>> + FreePool (NicDevice->DevPath);
>> + FreePool (NicDevice);
>> + }
>> + }
>> +
>> + if (!AllChildrenStopped) {
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Entrypoint of Network Common Driver.
>> +
>> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
>> + Protocols together with Component Name Protocols.
>> +
>> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
>> + @param[in] SystemTable A pointer to the EFI System Table.
>> +
>> + @retval EFI_SUCCESS The entry point is executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonEntry (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
>> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
>> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
>> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
>> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &gNetworkCommonDriverBinding.DriverBindingHandle,
>> + &gEfiDriverBindingProtocolGuid,
>> + &gNetworkCommonDriverBinding,
>> + &gEfiComponentName2ProtocolGuid,
>> + &gNetworkCommonComponentName2,
>> + NULL
>> + );
>> + return Status;
>> +}
>> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> new file mode 100644
>> index 000000000000..687cabca4ce3
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> @@ -0,0 +1,1803 @@
>> +/** @file
>> + This file contains code for UNDI command based on UEFI specification.
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +// API table, defined in UEFI specification
>> +API_FUNC gUndiApiTable[] = {
>> + UndiGetState,
>> + UndiStart,
>> + UndiStop,
>> + UndiGetInitInfo,
>> + UndiGetConfigInfo,
>> + UndiInitialize,
>> + UndiReset,
>> + UndiShutdown,
>> + UndiInterruptEnable,
>> + UndiReceiveFilter,
>> + UndiStationAddress,
>> + UndiStatistics,
>> + UndiMcastIp2Mac,
>> + UndiNvData,
>> + UndiGetStatus,
>> + UndiFillHeader,
>> + UndiTransmit,
>> + UndiReceive
>> +};
>> +
>> +/**
>> + Callback function for enable Rate Limiter
>> +
>> + @param[in] Event Event whose notification function is being invoked
>> + @param[in] Context Pointer to the notification function's context
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +UndiRateLimiterCallback (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + )
>> +{
>> + NIC_DATA *Nic = Context;
>> +
>> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
>> + Nic->RateLimitingCreditCount++;
>> + }
>> +}
>> +
>> +/**
>> + This command is used to determine the operational state of the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetState (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to change the UNDI operational state from stopped to started.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_START_31 *Cpb;
>> + EFI_STATUS Status;
>> + BOOLEAN EventError;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
>> +
>> + Nic->PxeStart.Delay = Cpb->Delay;
>> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
>> + Nic->PxeStart.Block = Cpb->Block;
>> + Nic->PxeStart.Map_Mem = 0;
>> + Nic->PxeStart.UnMap_Mem = 0;
>> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
>> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
>> + EventError = FALSE;
>> + Status = EFI_SUCCESS;
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + Status = gBS->CreateEvent (
>> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
>> + TPL_NOTIFY,
>> + UndiRateLimiterCallback,
>> + Nic,
>> + &Nic->RateLimiter
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + Status = gBS->SetTimer (
>> + Nic->RateLimiter,
>> + TimerPeriodic,
>> + Nic->RateLimitingPollTimer * 10000
>> + );
>> + if (EFI_ERROR (Status)) {
>> + EventError = TRUE;
>> + }
>> + }
>> + }
>> +
>> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
>> + }
>> +
>> + if (!EFI_ERROR (Status)) {
>> + // Initial the state for UNDI start.
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + } else {
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + if (!EventError) {
>> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
>> + }
>> +
>> + if (Nic->RateLimiter) {
>> + gBS->CloseEvent (&Nic->RateLimiter);
>> + Nic->RateLimiter = 0;
>> + }
>> + }
>> +
>> + // Initial the state when UNDI start is fail
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
>> + }
>> +}
>> +
>> +/**
>> + This command is used to change the UNDI operational state from started to stopped.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
>> + return;
>> + }
>> +
>> + Nic->PxeStart.Delay = 0;
>> + Nic->PxeStart.Virt2Phys = 0;
>> + Nic->PxeStart.Block = 0;
>> + Nic->PxeStart.Map_Mem = 0;
>> + Nic->PxeStart.UnMap_Mem = 0;
>> + Nic->PxeStart.Sync_Mem = 0;
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
>> +
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
>> + gBS->CloseEvent (&Nic->RateLimiter);
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to retrieve initialization information that is
>> + needed by drivers and applications to initialized UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_INIT_INFO *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->MemoryRequired = MEMORY_REQUIRE;
>> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
>> + Db->LinkSpeeds[0] = 10;
>> + Db->LinkSpeeds[1] = 100;
>> + Db->LinkSpeeds[2] = 1000;
>> + Db->LinkSpeeds[3] = 0;
>> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
>> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
>> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
>> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
>> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
>> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
>> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
>> + Db->IFtype = PXE_IFTYPE_ETHERNET;
>> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
>> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
>> +
>> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
>> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to retrieve configuration information about
>> + the NIC being controlled by the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_CONFIG_INFO *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->pci.BusType = PXE_BUSTYPE_USB;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_INITIALIZE *Cpb;
>> + PXE_DB_INITIALIZE *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
>> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
>> +
>> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
>> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
>> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
>> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
>> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
>> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
>> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
>> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
>> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
>> +
>> + Cdb->StatCode = Initialize (Cdb, Nic);
>> +
>> + Db->MemoryUsed = MEMORY_REQUIRE;
>> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
>> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
>> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
>> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
>> +
>> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
>> + Nic->CanTransmit = FALSE;
>> +
>> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
>> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
>> + Nic->CableDetect = 0;
>> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
>> + Nic->CableDetect = 1;
>> + }
>> +
>> + if (Nic->CableDetect == 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
>> + }
>> + }
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Initialize Network interface controller data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> + @retval Status A value of Pxe statcode.
>> +
>> +**/
>> +UINT16
>> +Initialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + UINTN Status;
>> + UINT32 Index;
>> + EFI_STATUS EfiStatus;
>> +
>> + Status = MapIt (
>> + Nic,
>> + Nic->PxeInit.MemoryAddr,
>> + Nic->PxeInit.MemoryLength,
>> + TO_AND_FROM_DEVICE,
>> + (UINT64)(UINTN)&Nic->MappedAddr
>> + );
>> +
>> + if (Status != 0) {
>> + return (UINT16)Status;
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->BroadcastNodeAddress[Index] = 0xFF;
>> + }
>> +
>> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = 0;
>> + Nic->PermNodeAddress[Index] = 0;
>> + Nic->BroadcastNodeAddress[Index] = 0;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
>> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
>> + if (EFI_ERROR (EfiStatus)) {
>> + return PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + return (UINT16)Status;
>> +}
>> +
>> +/**
>> + This command resets the network adapter and reinitializes the UNDI
>> + with the same parameters provided in the Initialize command.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
>> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
>> + Nic->InterrupOpFlag = 0;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Shutdown command resets the network adapter and leaves it in a
>> + safe state for another driver to initialize.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + Nic->CanTransmit = FALSE;
>> +
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Interrupt Enables command can be used to read and/or change
>> + the current external interrupt enable settings.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiInterruptEnable (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and change receive filters and,
>> + if supported, read and change the multicast MAC address filter list.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + UINT16 NewFilter;
>> + PXE_DB_RECEIVE_FILTERS *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>> +
>> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
>> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
>> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
>> + if ((Cdb->DBsize != 0)) {
>> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
>> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
>> + }
>> + }
>> +
>> + break;
>> +
>> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
>> + if (NewFilter == 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if (Cdb->CPBsize != 0) {
>> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
>> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
>> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
>> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
>> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
>> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if ((Cdb->CPBsize == 0)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
>> + break;
>> +
>> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
>> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + break;
>> +
>> + default:
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Set PXE receive filter.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] SetFilter PXE receive filter
>> + @param[in] CpbAddr Command Parameter Block Address
>> + @param[in] CpbSize Command Parameter Block Size
>> +
>> +**/
>> +UINT16
>> +SetFilter (
>> + IN NIC_DATA *Nic,
>> + IN UINT16 SetFilter,
>> + IN UINT64 CpbAddr,
>> + IN UINT32 CpbSize
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 *McastList;
>> + UINT8 Count;
>> + UINT8 Index1;
>> + UINT8 Index2;
>> + PXE_CPB_RECEIVE_FILTERS *Cpb;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> +
>> + Count = 0;
>> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
>> +
>> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
>> + Nic->RxFilter = (UINT8)SetFilter;
>> +
>> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
>> + if (Cpb != NULL) {
>> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
>> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
>> + }
>> +
>> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + } else {
>> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Cpb != NULL) {
>> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
>> + for (Index2 = 0; Index2 < 6; Index2++) {
>> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
>> + }
>> + }
>> + }
>> +
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
>> + if (Cpb != NULL) {
>> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
>> + }
>> +
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + FreePool (McastList);
>> + }
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + This command is used to get current station and broadcast MAC addresses
>> + and, if supported, to change the current station MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStationAddress (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_STATION_ADDRESS *Cpb;
>> + PXE_DB_STATION_ADDRESS *Db;
>> + UINT16 Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
>> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
>> + }
>> + }
>> + }
>> +
>> + if (Cdb->CPBaddr != 0) {
>> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
>> + }
>> + }
>> +
>> + if (Cdb->DBaddr != 0) {
>> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
>> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
>> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStatistics (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Return data for DB data.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] DbAddr Data Block Address.
>> + @param[in] DbSize Data Block Size.
>> +
>> +**/
>> +UINT16
>> +Statistics (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + )
>> +{
>> + PXE_DB_STATISTICS *DbStatistic;
>> + EFI_STATUS Status;
>> +
>> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
>> +
>> + if (DbSize == 0) {
>> + return PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + DbStatistic->Supported = 0x802;
>> + DbStatistic->Data[0x01] = Nic->RxFrame;
>> + DbStatistic->Data[0x0B] = Nic->TxFrame;
>> +
>> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
>> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
>> +
>> + @param[in, out] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiMcastIp2Mac (
>> + IN OUT PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
>> + PXE_DB_MCAST_IP_TO_MAC *Db;
>> + UINT8 *Tmp;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
>> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + return;
>> + }
>> +
>> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
>> +
>> + if ((Tmp[0] & 0xF0) != 0xE0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
>> + }
>> +
>> + Db->MAC[0] = 0x01;
>> + Db->MAC[1] = 0x00;
>> + Db->MAC[2] = 0x5E;
>> + Db->MAC[3] = Tmp[1] & 0x7F;
>> + Db->MAC[4] = Tmp[2];
>> + Db->MAC[5] = Tmp[3];
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and write (if supported by NIC H/W)
>> + nonvolatile storage on the NIC.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiNvData (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command returns the current interrupt status and/or the
>> + transmitted buffer addresses and the current media status.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_STATUS *Db;
>> + PXE_DB_GET_STATUS TmpGetStatus;
>> + UINT16 NumEntries;
>> + UINTN Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + TmpGetStatus.RxFrameLen = 0;
>> + TmpGetStatus.reserved = 0;
>> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
>> +
>> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
>> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
>> + } else {
>> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
>> + if (Cdb->DBsize == 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + NumEntries = Cdb->DBsize - sizeof (UINT64);
>> + Cdb->DBsize = sizeof (UINT32) * 2;
>> +
>> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
>> + if (Nic->TxBufferCount > 0) {
>> + Nic->TxBufferCount--;
>> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
>> + }
>> + }
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
>> + if (Nic->ReceiveStatus != 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
>> + }
>> + }
>> +
>> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
>> + Nic->CableDetect = 0;
>> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
>> + Nic->CableDetect = 1;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
>> + if (Nic->CableDetect == 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to fill the media header(s) in transmit packet(s).
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiFillHeader (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_FILL_HEADER *CpbFillHeader;
>> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
>> + EthernetHeader *MacHeader;
>> + UINTN Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
>> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
>> +
>> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
>> + MacHeader->Protocol = CpbFill->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
>> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
>> + }
>> + } else {
>> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
>> +
>> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
>> + MacHeader->Protocol = CpbFillHeader->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
>> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Transmit command is used to place a packet into the transmit queue.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + return;
>> + }
>> +
>> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +}
>> +
>> +/**
>> + Use USB Ethernet Protocol Bulk out command to transmit data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> + @param[in] CpbAddr Command Parameter Block Address.
>> + @param[in] OpFlags Operation Flags.
>> +
>> +**/
>> +UINT16
>> +Transmit (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN UINT16 OpFlags
>> + )
>> +{
>> + EFI_STATUS Status;
>> + PXE_CPB_TRANSMIT *Cpb;
>> + UINT64 BulkOutData;
>> + UINTN DataLength;
>> + UINTN TransmitLength;
>> + UINTN Map;
>> + UINT32 Counter;
>> + UINT16 StatCode;
>> +
>> + BulkOutData = 0;
>> + Counter = 0;
>> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
>> +
>> + if (Nic->CanTransmit) {
>> + return PXE_STATCODE_BUSY;
>> + }
>> +
>> + Nic->CanTransmit = TRUE;
>> +
>> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + Map = MapIt (
>> + Nic,
>> + Cpb->FrameAddr,
>> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
>> + TO_DEVICE,
>> + (UINT64)(UINTN)&BulkOutData
>> + );
>> +
>> + if (Map != 0) {
>> + Nic->CanTransmit = FALSE;
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
>> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
>> + Nic->TxBufferCount++;
>> + }
>> +
>> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
>> +
>> + while (1) {
>> + if (Counter >= 3) {
>> + StatCode = PXE_STATCODE_BUSY;
>> + break;
>> + }
>> +
>> + TransmitLength = DataLength;
>> +
>> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
>> + if (EFI_ERROR (Status)) {
>> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if (Status == EFI_INVALID_PARAMETER) {
>> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
>> + break;
>> + }
>> +
>> + if (Status == EFI_DEVICE_ERROR) {
>> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
>> + break;
>> + }
>> +
>> + if (!EFI_ERROR (Status)) {
>> + Nic->TxFrame++;
>> + StatCode = PXE_STATCODE_SUCCESS;
>> + break;
>> + }
>> +
>> + Counter++;
>> + }
>> +
>> + UnMapIt (
>> + Nic,
>> + Cpb->FrameAddr,
>> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
>> + TO_DEVICE,
>> + BulkOutData
>> + );
>> +
>> + Nic->CanTransmit = FALSE;
>> +
>> + return StatCode;
>> +}
>> +
>> +/**
>> + When the network adapter has received a frame, this command is used
>> + to copy the frame into driver/application storage.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + return;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +}
>> +
>> +/**
>> + Use USB Ethernet Protocol Bulk in command to receive data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> + @param[in] CpbAddr Command Parameter Block Address.
>> + @param[in, out] DbAddr Data Block Address.
>> +
>> +**/
>> +UINT16
>> +Receive (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN OUT UINT64 DbAddr
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + PXE_FRAME_TYPE FrameType;
>> + PXE_CPB_RECEIVE *Cpb;
>> + PXE_DB_RECEIVE *Db;
>> + NIC_DEVICE *NicDevice;
>> + UINT8 *BulkInData;
>> + UINTN DataLength;
>> + EthernetHeader *Header;
>> + EFI_TPL OriginalTpl;
>> +
>> + FrameType = PXE_FRAME_TYPE_NONE;
>> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
>> + BulkInData = NicDevice->ReceiveBuffer;
>> + DataLength = (UINTN)Nic->MaxSegmentSize;
>> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
>> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
>> +
>> + if (!BulkInData) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
>> + return PXE_STATCODE_NO_DATA;
>> + }
>> +
>> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
>> + if (EFI_ERROR (Status)) {
>> + Nic->ReceiveStatus = 0;
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
>> + if (Nic->RateLimitingCreditCount != 0) {
>> + Nic->RateLimitingCreditCount--;
>> + }
>> +
>> + gBS->RestoreTPL (OriginalTpl);
>> + }
>> +
>> + return PXE_STATCODE_NO_DATA;
>> + }
>> +
>> + Nic->RxFrame++;
>> +
>> + if (DataLength != 0) {
>> + if (DataLength > Cpb->BufferLen) {
>> + DataLength = (UINTN)Cpb->BufferLen;
>> + }
>> +
>> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
>> +
>> + Header = (EthernetHeader *)BulkInData;
>> +
>> + Db->FrameLen = (UINT32)DataLength;
>> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
>> + break;
>> + }
>> + }
>> +
>> + if (Index >= PXE_HWADDR_LEN_ETHER) {
>> + FrameType = PXE_FRAME_TYPE_UNICAST;
>> + } else {
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
>> + break;
>> + }
>> + }
>> +
>> + if (Index >= PXE_HWADDR_LEN_ETHER) {
>> + FrameType = PXE_FRAME_TYPE_BROADCAST;
>> + } else {
>> + if ((Header->DestAddr[0] & 1) == 1) {
>> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
>> + } else {
>> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
>> + }
>> + }
>> + }
>> +
>> + Db->Type = FrameType;
>> + Db->Protocol = Header->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
>> + Db->DestAddr[Index] = Header->DestAddr[Index];
>> + }
>> + }
>> +
>> + if (FrameType == PXE_FRAME_TYPE_NONE) {
>> + Nic->ReceiveStatus = 0;
>> + } else {
>> + Nic->ReceiveStatus = 1;
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Fill out PXE SW UNDI structure.
>> +
>> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
>> +
>> +**/
>> +VOID
>> +PxeStructInit (
>> + OUT PXE_SW_UNDI *PxeSw
>> + )
>> +{
>> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
>> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
>> + PxeSw->Fudge = 0;
>> + PxeSw->IFcnt = 0;
>> + PxeSw->IFcntExt = 0;
>> + PxeSw->Rev = PXE_ROMID_REV;
>> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
>> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
>> + PxeSw->reserved1 = 0;
>> +
>> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
>> + PXE_ROMID_IMP_FRAG_SUPPORTED |
>> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
>> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
>> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
>> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
>> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
>> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
>> +
>> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
>> + PxeSw->reserved2[0] = 0;
>> + PxeSw->reserved2[1] = 0;
>> + PxeSw->reserved2[2] = 0;
>> + PxeSw->BusCnt = 1;
>> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
>> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
>> +}
>> +
>> +/**
>> + Update NIC number.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
>> +
>> +**/
>> +VOID
>> +UpdateNicNum (
>> + IN NIC_DATA *Nic,
>> + IN OUT PXE_SW_UNDI *PxeSw
>> + )
>> +{
>> + UINT16 NicNum;
>> +
>> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
>> +
>> + if (Nic == NULL) {
>> + if (NicNum > 0) {
>> + NicNum--;
>> + }
>> +
>> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
>> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
>> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
>> + return;
>> + }
>> +
>> + NicNum++;
>> +
>> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
>> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
>> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
>> +}
>> +
>> +/**
>> + UNDI API table entry.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UndiApiEntry (
>> + IN UINT64 Cdb
>> + )
>> +{
>> + PXE_CDB *CdbPtr;
>> + NIC_DATA *Nic;
>> +
>> + if (Cdb == 0) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
>> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
>> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Map virtual memory address for DMA. This field can be set to
>> + zero if there is no mapping service.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] MemAddr Virtual address to be mapped.
>> + @param[in] Size Size of memory to be mapped.
>> + @param[in] Direction Direction of data flow for this memory's usage:
>> + cpu->device, device->cpu or both ways.
>> + @param[out] MappedAddr Pointer to return the mapped device address.
>> +
>> +**/
>> +UINTN
>> +MapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + OUT UINT64 MappedAddr
>> + )
>> +{
>> + UINT64 *PhyAddr;
>> +
>> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
>> +
>> + if (Nic->PxeStart.Map_Mem == 0) {
>> + *PhyAddr = MemAddr;
>> + } else {
>> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
>> + Nic->PxeStart.Unique_ID,
>> + MemAddr,
>> + Size,
>> + Direction,
>> + MappedAddr
>> + );
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Un-map previously mapped virtual memory address. This field can be set
>> + to zero only if the Map_Mem() service is also set to zero.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] MemAddr Virtual address to be mapped.
>> + @param[in] Size Size of memory to be mapped.
>> + @param[in] Direction Direction of data flow for this memory's usage:
>> + cpu->device, device->cpu or both ways.
>> + @param[in] MappedAddr Pointer to return the mapped device address.
>> +
>> +**/
>> +VOID
>> +UnMapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + IN UINT64 MappedAddr
>> + )
>> +{
>> + if (Nic->PxeStart.UnMap_Mem != 0) {
>> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
>> + Nic->PxeStart.Unique_ID,
>> + MemAddr,
>> + Size,
>> + Direction,
>> + MappedAddr
>> + );
>> + }
>> +
>> + return;
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> new file mode 100644
>> index 000000000000..b9ba170c135b
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> @@ -0,0 +1,172 @@
>> +/** @file
>> + This file contains code for USB RNDIS Driver Component
>> + Name definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
>> + {
>> + "eng;en",
>> + L"USB RNDIS Driver"
>> + },
>> + {
>> + NULL,
>> + NULL
>> + }
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
>> + UsbRndisComponentNameGetDriverName,
>> + UsbRndisComponentNameGetControllerName,
>> + "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
>> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
>> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
>> + "en"
>> +};
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Language 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[out] DriverName 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
>> +UsbRndisComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + )
>> +{
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gUsbRndisDriverNameTable,
>> + DriverName,
>> + (BOOLEAN)(This == &gUsbRndisComponentName)
>> + );
>> +}
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
>> + @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
>> +UsbRndisComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + )
>> +{
>> + return EFI_UNSUPPORTED;
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> new file mode 100644
>> index 000000000000..92830771e408
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> @@ -0,0 +1,886 @@
>> +/** @file
>> + This file contains code for USB Remote Network Driver
>> + Interface Spec. Driver Binding
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
>> + UsbRndisDriverSupported,
>> + UsbRndisDriverStart,
>> + UsbRndisDriverStop,
>> + USB_RNDIS_DRIVER_VERSION,
>> + NULL,
>> + NULL
>> +};
>> +
>> +/**
>> + Check if this interface is USB Rndis SubType
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis SubType.
>> + @retval FALSE Not USB Rndis SubType.
>> +
>> +**/
>> +BOOLEAN
>> +IsSupportedDevice (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check specific device/RNDIS and CDC-DATA
>> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
>> + )
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if this interface is USB Rndis SubType but not CDC Data interface
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis SubType.
>> + @retval FALSE Not USB Rndis SubType.
>> +**/
>> +BOOLEAN
>> +IsRndisInterface (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for specific device/RNDIS and CDC-DATA
>> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
>> + )
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
>> +
>> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> +
>> + @retval EFI_SUCCESS Is the same device.
>> + @retval EFI_UNSUPPORTED Is not the same device.
>> +
>> +**/
>> +EFI_STATUS
>> +IsSameDevice (
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
>> + )
>> +{
>> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
>> + while (1) {
>> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
>> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
>> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
>> + {
>> + return EFI_SUCCESS;
>> + } else {
>> + return EFI_UNSUPPORTED;
>> + }
>> + } else {
>> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
>> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
>> + }
>> + }
>> +
>> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
>> +}
>> +
>> +/**
>> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB CDC Data(UsbIo) installed.
>> + @retval FALSE USB CDC Data(UsbIo) did not installed.
>> +
>> +**/
>> +BOOLEAN
>> +IsUsbCdcData (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for CDC-DATA
>> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if the USB Rndis(UsbIo) installed
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis(UsbIo) installed.
>> + @retval FALSE USB Rndis(UsbIo) did not installed.
>> +
>> +**/
>> +BOOLEAN
>> +IsUsbRndis (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for Rndis
>> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
>> + For one device two USBIO will be installed each for CDC and RNDIS interface.
>> +
>> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
>> +
>> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
>> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
>> +
>> +**/
>> +EFI_STATUS
>> +UpdateRndisDevice (
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
>> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + BOOLEAN IsRndisInterfaceFlag;
>> +
>> + IsRndisInterfaceFlag = FALSE;
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEdkIIUsbEthProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEthDevice
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
>> + if (IsRndisInterfaceFlag == FALSE) {
>> + continue;
>> + }
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> +
>> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>> +
>> + if (!EFI_ERROR (Status)) {
>> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>> + FreePool (HandleBuffer);
>> + return EFI_SUCCESS;
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> +
>> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
>> + and UsbIO protocol.
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
>> +
>> +**/
>> +VOID
>> +FindMatchingCdcData (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = gBS->HandleProtocol (
>> + UsbRndisDevice->UsbRndisHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + return;
>> + }
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEfiUsbIoProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + if (IsUsbCdcData (UsbIo)) {
>> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbCdcDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
>> + FreePool (HandleBuffer);
>> + return;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>> + if (!EFI_ERROR (Status)) {
>> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
>> + UsbRndisDevice->UsbIoCdcData = UsbIo;
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + FreePool (HandleBuffer);
>> + return;
>> + }
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> +}
>> +
>> +/**
>> +
>> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
>> +
>> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
>> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
>> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
>> +
>> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
>> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FindMatchingRndisDev (
>> + IN EFI_HANDLE CdcHandle,
>> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
>> + OUT EFI_HANDLE *RndisHandle
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = gBS->HandleProtocol (
>> + CdcHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbCdcDataPath
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEfiUsbIoProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if (IsUsbRndis (UsbIo)) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
>> + break;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + *RndisHandle = HandleBuffer[Index];
>> + *CdcUsbIo = UsbIo;
>> + FreePool (HandleBuffer);
>> + return Status;
>> + }
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> + USB Rndis Driver Binding Support.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to test.
>> + @param[in] 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
>> +UsbRndisDriverSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + USB RNDIS Driver Binding Start.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
>> + @retval other This driver does not support this device
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
>> + EFI_HANDLE RndisHandle;
>> +
>> + RndisHandle = ControllerHandle;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbEthPath,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
>> + if (IsUsbCdcData (UsbIo)) {
>> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = UpdateRndisDevice (
>> + UsbEthPath,
>> + &UsbRndisDevice
>> + );
>> +
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
>> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
>> + UsbRndisDevice->UsbIoCdcData = UsbIo;
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + return Status;
>> + } else {
>> + // Check if RnDis exist
>> + Status = FindMatchingRndisDev (
>> + ControllerHandle,
>> + &UsbIo,
>> + &RndisHandle
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> + }
>> + }
>> +
>> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
>> +
>> + if (!UsbRndisDevice) {
>> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + Status = LoadAllDescriptor (
>> + UsbIo,
>> + &UsbRndisDevice->Config
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (
>> + UsbIo,
>> + &Interface
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
>> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
>> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
>> + UsbRndisDevice->UsbCdcDataHandle = 0;
>> + UsbRndisDevice->UsbIo = UsbIo;
>> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
>> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
>> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
>> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
>> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
>> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
>> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
>> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
>> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
>> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
>> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
>> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
>> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
>> +
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
>> +
>> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
>> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
>> + UsbRndisDevice->PacketAlignmentFactor = 0;
>> +
>> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
>> +
>> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
>> + FindMatchingCdcData (UsbRndisDevice);
>> +
>> + if (UsbRndisDevice->UsbIoCdcData) {
>> + Status = gBS->InstallProtocolInterface (
>> + &ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + EFI_NATIVE_INTERFACE,
>> + &(UsbRndisDevice->UsbEth)
>> + );
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
>> +
>> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
>> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
>> + return EFI_SUCCESS;
>> + }
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + CheckandStopRndisDevice
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> +
>> + @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
>> +CheckandStopRndisDevice (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if (IsUsbRndis (UsbIo)) {
>> + Status = gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
>> + return Status;
>> + }
>> +
>> + return EFI_UNSUPPORTED;
>> +}
>> +
>> +/**
>> + USB Rndis Driver Binding Stop.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to stop driver on
>> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
>> + children is zero stop the entire bus driver.
>> + @param[in] 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
>> +UsbRndisDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEthProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + Status = CheckandStopRndisDevice (This, ControllerHandle);
>> + return Status;
>> + }
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
>> +
>> + Status = gBS->CloseProtocol (
>> + UsbRndisDevice->UsbCdcDataHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + UsbRndisDevice->UsbCdcDataHandle
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
>> + }
>> +
>> + Status = gBS->UninstallProtocolInterface (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + UsbEthProtocol
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> +
>> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
>> + return Status;
>> +}
>> +
>> +/**
>> + Entrypoint of RNDIS Driver.
>> +
>> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
>> + Protocols together with Component Name Protocols.
>> +
>> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
>> + @param[in] SystemTable A pointer to the EFI System Table.
>> +
>> + @retval EFI_SUCCESS The entry point is executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisEntry (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
>> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
>> +
>> + return gBS->InstallMultipleProtocolInterfaces (
>> + &gUsbRndisDriverBinding.DriverBindingHandle,
>> + &gEfiDriverBindingProtocolGuid,
>> + &gUsbRndisDriverBinding,
>> + &gEfiComponentName2ProtocolGuid,
>> + &gUsbRndisComponentName2,
>> + NULL
>> + );
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> new file mode 100644
>> index 000000000000..e3fe737cdef1
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> @@ -0,0 +1,1718 @@
>> +/** @file
>> + This file contains code for USB Ethernet descriptor
>> + and specific requests implement.
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +UINT16 gStopBulkInCnt = 0;
>> +UINT16 gBlockBulkInCnt = 0;
>> +
>> +/**
>> + Load All of device descriptor.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> + @param[out] ConfigDesc A pointer to the configuration descriptor.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
>> + buffer specified by DescriptorLength and Descriptor
>> + is not large enough to hold the result of the request.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
>> + status is returned in Status.
>> +**/
>> +EFI_STATUS
>> +LoadAllDescriptor (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 TransStatus;
>> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
>> +
>> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = gBS->AllocatePool (
>> + EfiBootServicesData,
>> + Tmp.TotalLength,
>> + (VOID **)ConfigDesc
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = UsbGetDescriptor (
>> + UsbIo,
>> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
>> + 0,
>> + Tmp.TotalLength,
>> + *ConfigDesc,
>> + &TransStatus
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Returns pointer to the next descriptor for the pack of USB descriptors
>> + located in continues memory segment
>> +
>> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
>> + @param[in, out] Offset A pointer to the sum of descriptor length.
>> +
>> + @retval TRUE The request executed successfully.
>> + @retval FALSE No next descriptor.
>> +
>> +**/
>> +BOOLEAN
>> +NextDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
>> + IN OUT UINTN *Offset
>> + )
>> +{
>> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
>> + return FALSE;
>> + }
>> +
>> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
>> + return FALSE;
>> + }
>> +
>> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
>> + if ( *Offset >= Desc->TotalLength ) {
>> + return FALSE;
>> + }
>> +
>> + return TRUE;
>> +}
>> +
>> +/**
>> + Read Function descriptor
>> +
>> + @param[in] Config A pointer to all of configuration.
>> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
>> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
>> +
>> + @retval EFI_SUCCESS The device capability descriptor was retrieved
>> + successfully.
>> + @retval EFI_UNSUPPORTED No supported.
>> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +GetFunctionalDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
>> + IN UINT8 FunDescriptorType,
>> + OUT VOID *DataBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Offset;
>> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
>> +
>> + Status = EFI_NOT_FOUND;
>> +
>> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
>> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
>> + if (Interface->DescriptorType == CS_INTERFACE) {
>> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
>> + switch (FunDescriptorType) {
>> + case HEADER_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
>> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
>> + );
>> + return EFI_SUCCESS;
>> + case UNION_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
>> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
>> + );
>> + return EFI_SUCCESS;
>> + case ETHERNET_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
>> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
>> + );
>> + return EFI_SUCCESS;
>> + default:
>> + Status = EFI_UNSUPPORTED;
>> + break;
>> + }
>> + }
>> + }
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> +
>> +**/
>> +VOID
>> +GetEndpoint (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 Index;
>> + UINT32 Result;
>> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
>> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + if (Interface.NumEndpoints == 0 ) {
>> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> + }
>> +
>> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
>> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
>> + case USB_ENDPOINT_BULK:
>> + if (Endpoint.EndpointAddress & BIT7) {
>> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
>> + } else {
>> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
>> + }
>> +
>> + break;
>> + case USB_ENDPOINT_INTERRUPT:
>> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
>> + break;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Async USB transfer callback routine.
>> +
>> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
>> + transfer completed successfully.
>> + @param[in] DataLength The length of Data received or sent via the Asynchronous
>> + Transfer, if transfer successfully completes.
>> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
>> + @param[in] Status Indicates the result of the asynchronous transfer.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +InterruptCallback (
>> + IN VOID *Data,
>> + IN UINTN DataLength,
>> + IN VOID *Context,
>> + IN UINT32 Status
>> + )
>> +{
>> + if ((Data == NULL) || (Context == NULL)) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
>> + CopyMem (
>> + (EFI_USB_DEVICE_REQUEST *)Context,
>> + (EFI_USB_DEVICE_REQUEST *)Data,
>> + sizeof (EFI_USB_DEVICE_REQUEST)
>> + );
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is used to manage a USB device with an interrupt transfer pipe.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
>> + FALSE, the interrupt transfer is deleted from the device's interrupt
>> + transfer queue.
>> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
>> + executed.This parameter is required when IsNewTransfer is TRUE. The
>> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
>> + The units are in milliseconds.
>> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisInterrupt (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Requst
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + UINTN DataLength;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> + DataLength = 0;
>> +
>> + if (IsNewTransfer == TRUE) {
>> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + IsNewTransfer,
>> + PollingInterval,
>> + DataLength,
>> + InterruptCallback,
>> + Requst
>> + );
>> +
>> + if (Status == EFI_INVALID_PARAMETER) {
>> + // Because of Stacked AsyncInterrupt request are not supported
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + 0,
>> + 0,
>> + 0,
>> + NULL,
>> + NULL
>> + );
>> + }
>> + } else {
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + IsNewTransfer,
>> + 0,
>> + 0,
>> + NULL,
>> + NULL
>> + );
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function is used to read USB interrupt transfer before the response RNDIS message.
>> +
>> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
>> +
>> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ReadRndisResponseInterrupt (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 Data[2];
>> + UINT32 UsbStatus;
>> + UINTN DataLength;
>> +
>> + DataLength = 8;
>> +
>> + ZeroMem (Data, sizeof (Data));
>> +
>> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + &Data,
>> + &DataLength,
>> + 0x20,
>> + &UsbStatus
>> + );
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet Mac Address.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbEthMacAddress (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
>> + CHAR16 *Data;
>> + CHAR16 *DataPtr;
>> + CHAR16 TmpStr[1];
>> + UINT8 Index;
>> + UINT8 Hi;
>> + UINT8 Low;
>> +
>> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
>> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
>> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
>> +
>> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
>> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
>> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
>> +
>> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
>> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
>> +
>> + Status = RndisControlMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
>> + }
>> +
>> + UsbRndisDevice->RequestId++;
>> + return Status;
>> + }
>> +
>> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
>> + // To check USB Ethernet functional Descriptor
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
>> + UsbRndisDevice->UsbIo,
>> + 0x409, // English-US Language ID
>> + UsbEthDescriptor.MacAddress,
>> + &Data
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + DataPtr = Data;
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
>> + DataPtr++;
>> + Hi = (UINT8)StrHexToUintn (TmpStr);
>> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
>> + DataPtr++;
>> + Low = (UINT8)StrHexToUintn (TmpStr);
>> + MacAddress->Addr[Index] = (Hi << 4) | Low;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet Bulk transfer data size.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] BulkSize A pointer to the Bulk transfer data size.
>> +
>> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
>> + @retval other Failed to retrieve the bulk transfer data size.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbEthBulkSize (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
>> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
>> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
>> +
>> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
>> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
>> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
>> +
>> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
>> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
>> +
>> + Status = RndisControlMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
>> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
>> + UsbRndisDevice->RequestId++;
>> + return Status;
>> + }
>> +
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Header functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbHeaderFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbHeaderFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + HEADER_FUN_DESCRIPTOR,
>> + UsbHeaderFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Union functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbUnionFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbUnionFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + UNION_FUN_DESCRIPTOR,
>> + UsbUnionFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet functional Descriptor.
>> +
>> + This function get the Mac Address, Ethernet statistics, maximum segment size,
>> + number of multicast filters, and number of pattern filters from Ethernet
>> + functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbEthFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + ETHERNET_FUN_DESCRIPTOR,
>> + UsbEthFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + This request sets the Ethernet device multicast filters as specified in the
>> + sequential list of 48 bit Ethernet multicast addresses.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] McastAddr A pointer to the value of the multicast addresses.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisMcastFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
>> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = Value * 6;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + McastAddr,
>> + Request.Length,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> + This request sets up the specified Ethernet power management pattern filter as
>> + described in the data structure.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] Length Size of the power management pattern filter data.
>> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + )
>> +{
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
>> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = Length;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + PatternFilter,
>> + Length,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> + This request retrieves the status of the specified Ethernet power management
>> + pattern filter from the device.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value The filter number.
>> + @param[out] PatternActive A pointer to the pattern active boolean.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + OUT BOOLEAN *PatternActive
>> + )
>> +{
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
>> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataIn,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + PatternActive,
>> + USB_ETH_POWER_FILTER_LENGTH,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> +
>> + Converts PXE filter settings to RNDIS values
>> +
>> + @param[in] Value PXE filter data.
>> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
>> +
>> +**/
>> +VOID
>> +ConvertFilter (
>> + IN UINT16 Value,
>> + OUT UINT16 *CdcFilter
>> + )
>> +{
>> + UINT32 Index;
>> + UINT32 Count;
>> + static struct BIT_MAP Table[] = {
>> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
>> + };
>> +
>> + Count = sizeof (Table)/sizeof (Table[0]);
>> +
>> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
>> + if (Table[Index].Src & Value) {
>> + *CdcFilter |= Table[Index].Dst;
>> + }
>> + }
>> +}
>> +
>> +/**
>> +
>> + Updates Filter settings on the device.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_STATUS
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 *McastList;
>> + UINT8 Count;
>> + UINT8 Index1;
>> + UINT8 Index2;
>> + UINT64 CpbAddr;
>> + UINT32 CpbSize;
>> + UINT16 SetFilter;
>> + PXE_CPB_RECEIVE_FILTERS *Cpb;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> +
>> + Count = 0;
>> + CpbAddr = Cdb->CPBaddr;
>> + CpbSize = Cdb->CPBsize;
>> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
>> +
>> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
>> + Nic->RxFilter = (UINT8)SetFilter;
>> +
>> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
>> + if (Cpb != NULL) {
>> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
>> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
>> + } else {
>> + Nic->McastCount = 0;
>> + }
>> +
>> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
>> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + } else {
>> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Cpb != NULL) {
>> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
>> + for (Index2 = 0; Index2 < 6; Index2++) {
>> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
>> + }
>> + }
>> + }
>> +
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
>> + if (Cpb != NULL) {
>> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
>> + }
>> +
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + FreePool (McastList);
>> + }
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This request is used to configure device Ethernet packet filter settings.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Packet Filter Bitmap.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPacketFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + )
>> +{
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This request is used to retrieve a statistic based on the feature selector.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] FeatureSelector Value of the feature selector.
>> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetRndisStatistic (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 FeatureSelector,
>> + OUT VOID *Statistic
>> + )
>> +{
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiStart is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
>> +
>> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
>> + Status = RndisUndiReset (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + RndisUndiReset (Cdb, Nic);
>> + }
>> +
>> + Status = RndisUndiInitialize (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + RndisUndiInitialize (Cdb, Nic);
>> + }
>> +
>> + RndisUndiShutdown (Cdb, Nic);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when Undistop is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiGetInitInfo is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + PXE_DB_GET_INIT_INFO *Db;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
>> +
>> + UsbEthDevice = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>> +
>> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
>> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
>> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
>> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when RndisUndiGetConfigInfo is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiInitialize is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
>> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
>> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
>> +
>> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
>> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
>> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
>> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
>> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
>> +
>> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
>> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
>> +
>> + UsbRndisDevice->RequestId++;
>> +
>> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
>> + return Status;
>> + }
>> +
>> + // Only Wired Medium is supported
>> + if (RndisInitMsgCmplt.Medium) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
>> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
>> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
>> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
>> +
>> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
>> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
>> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
>> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function is called when UndiReset is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
>> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
>> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
>> +
>> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
>> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
>> +
>> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
>> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
>> +
>> + UsbRndisDevice->RequestId = 1; // Let's start with 1
>> +
>> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiShutdown is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
>> +
>> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
>> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
>> +
>> + if (Status == EFI_DEVICE_ERROR) {
>> + Status = EFI_SUCCESS;
>> + }
>> +
>> + UsbRndisDevice->RequestId = 1;
>> + return Status;
>> +}
>> +
>> +/**
>> + Update the Media connection.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Transmit the data after appending RNDIS header.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] DataLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN VOID *BulkOutData,
>> + IN OUT UINTN *DataLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
>> + UINTN TransferLength;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
>> + if (RndisPacketMsg == NULL) {
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
>> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
>> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
>> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
>> +
>> + CopyMem (
>> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
>> + BulkOutData,
>> + *DataLength
>> + );
>> +
>> + TransferLength = RndisPacketMsg->MessageLength;
>> +
>> + Status = RndisTransmitDataMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
>> + &TransferLength
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
>> +
>> + FreePool (RndisPacketMsg);
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Receives and removes RNDIS header and returns the raw data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] DataLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
>> + @retval EFI_NOT_FOUND No buffer was found in the list.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *BulkInData,
>> + IN OUT UINTN *DataLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
>> + UINTN TransferLength;
>> + VOID *Buffer;
>> + PACKET_LIST *HeadPacket;
>> + PACKET_LIST *PacketList;
>> +
>> + // Check if there is any outstanding packet to receive
>> + // The buffer allocated has a linked List followed by the packet.
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> + Buffer = NULL;
>> + HeadPacket = NULL;
>> +
>> + while (1) {
>> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
>> + if (Buffer == NULL) {
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
>> + PacketList = (PACKET_LIST *)Buffer;
>> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
>> + // Save the original address for freeing it up
>> + PacketList->OrgBuffer = (UINT8 *)Buffer;
>> + TransferLength = UsbRndisDevice->MaxTransferSize;
>> +
>> + Status = RndisReceiveDataMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
>> + &TransferLength
>> + );
>> +
>> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
>> + FreePool (Buffer);
>> + break;
>> + }
>> +
>> + // Collect all the RNDIS packet in Linked list.
>> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
>> + (TransferLength >= RndisPacketMsg->MessageLength))
>> + {
>> + // Insert Packet
>> + PacketList->RemainingLength = TransferLength;
>> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
>> + } else {
>> + FreePool (Buffer);
>> + }
>> + }
>> +
>> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
>> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
>> +
>> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
>> +
>> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
>> +
>> + // Check whether the packet is valid RNDIS packet.
>> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
>> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
>> + {
>> + if (*DataLength >= RndisPacketMsg->DataLength) {
>> + CopyMem (
>> + BulkInData,
>> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
>> + RndisPacketMsg->DataLength
>> + );
>> +
>> + *DataLength = RndisPacketMsg->DataLength;
>> +
>> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
>> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
>> +
>> + return EFI_SUCCESS;
>> + } else {
>> + *DataLength = RndisPacketMsg->DataLength;
>> + return EFI_BUFFER_TOO_SMALL;
>> + }
>> + }
>> +
>> + RemoveEntryList (&HeadPacket->PacketList);
>> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
>> + }
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
>> + point to this function.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisDummyReturn (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's control endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
>> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisControlMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
>> + )
>> +{
>> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
>> + EFI_USB_DEVICE_REQUEST DevReq;
>> + UINT32 UsbStatus;
>> + EFI_STATUS Status;
>> + UINT32 SaveResponseType;
>> + UINT32 SaveResponseLength;
>> + UINT32 Index;
>> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
>> +
>> + SaveResponseType = 0;
>> + SaveResponseLength = 0;
>> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
>> +
>> + if (RndisMsgResponse) {
>> + SaveResponseType = RndisMsgResponse->MessageType;
>> + SaveResponseLength = RndisMsgResponse->MessageLength;
>> + }
>> +
>> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
>> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
>> + DevReq.Value = 0;
>> + DevReq.Index = 0;
>> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + Status = UsbIo->UsbControlTransfer (
>> + UsbIo,
>> + &DevReq,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + RndisMsg,
>> + RndisMsg->MessageLength,
>> + &UsbStatus
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
>> +
>> + // Error or no response expected
>> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
>> + ReadRndisResponseInterrupt (UsbRndisDevice);
>> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
>> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
>> + DevReq.Value = 0;
>> + DevReq.Index = 0;
>> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
>> +
>> + Status = UsbIo->UsbControlTransfer (
>> + UsbIo,
>> + &DevReq,
>> + EfiUsbDataIn,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + RndisMsgResponse,
>> + RndisMsgResponse->MessageLength,
>> + &UsbStatus
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
>> +
>> + PrintRndisMsg (RndisMsgResponse);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
>> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
>> +
>> + RndisMsgResponse->MessageType = SaveResponseType;
>> + RndisMsgResponse->MessageLength = SaveResponseLength;
>> + continue;
>> + }
>> + }
>> +
>> + return Status;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
>> +
>> + return EFI_TIMEOUT;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's Data endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
>> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisTransmitDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + IN OUT UINTN *TransferLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 UsbStatus;
>> +
>> + if (UsbRndisDevice->BulkInEndpoint == 0) {
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + }
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>> + UsbRndisDevice->UsbIoCdcData,
>> + UsbRndisDevice->BulkOutEndpoint,
>> + RndisMsg,
>> + TransferLength,
>> + USB_TX_ETHERNET_BULK_TIMEOUT,
>> + &UsbStatus
>> + );
>> +
>> + if (Status == EFI_SUCCESS) {
>> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's Data endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
>> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisReceiveDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + IN OUT UINTN *TransferLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 UsbStatus;
>> +
>> + UsbStatus = 0;
>> +
>> + if (UsbRndisDevice->BulkInEndpoint == 0) {
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + }
>> +
>> + // Use gStopBulkInCnt to stop BulkIn command
>> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
>> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>> + UsbRndisDevice->UsbIoCdcData,
>> + UsbRndisDevice->BulkInEndpoint,
>> + RndisMsg,
>> + TransferLength,
>> + USB_RX_ETHERNET_BULK_TIMEOUT,
>> + &UsbStatus
>> + );
>> +
>> + if (!EFI_ERROR (Status)) {
>> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>> + } else {
>> + gStopBulkInCnt--;
>> + }
>> + } else {
>> + Status = EFI_TIMEOUT;
>> + *TransferLength = 0;
>> + gBlockBulkInCnt++;
>> + }
>> +
>> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
>> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>> + gBlockBulkInCnt = 0;
>> + }
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Prints RNDIS Header and Data
>> +
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
>> +
>> +**/
>> +VOID
>> +PrintRndisMsg (
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
>> + )
>> +{
>> + UINTN Length;
>> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
>> +
>> + Length = 0;
>> +
>> + switch (RndisMsg->MessageType) {
>> + case RNDIS_PACKET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
>> + break;
>> + case RNDIS_INITIALIZE_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
>> + break;
>> + case RNDIS_INITIALIZE_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
>> + break;
>> + case RNDIS_HLT_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
>> + break;
>> + case RNDIS_QUERY_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
>> + break;
>> + case RNDIS_QUERY_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
>> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
>> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
>> + break;
>> + case RNDIS_SET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_SET_MSG);
>> + break;
>> + case RNDIS_SET_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
>> + break;
>> + case RNDIS_RESET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
>> + break;
>> + case RNDIS_RESET_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
>> + break;
>> + case RNDIS_INDICATE_STATUS_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
>> + break;
>> + case RNDIS_KEEPALIVE_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
>> + break;
>> + case RNDIS_KEEPALIVE_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
>> + }
>> +
>> + if (Length) {
>> + UINTN Index = 0;
>> + for ( ; Length; Length -= 4, Index++) {
>> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
>> + if (((Index % 4) == 3) && (Index != 0)) {
>> + DEBUG ((DEBUG_INFO, "\n"));
>> + }
>> +
>> + if ((Length < 8) && (Length > 4)) {
>> + UINT32 Data32;
>> + Index++;
>> + Data32 = *((UINT32 *)RndisMsg + Index);
>> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
>> + break;
>> + }
>> + }
>> +
>> + if (Index % 4) {
>> + DEBUG ((DEBUG_INFO, "\n"));
>> + }
>> + }
>> +}
>> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
>> new file mode 100644
>> index 000000000000..cb70684f0bf1
>> --- /dev/null
>> +++ b/UsbNetworkPkg/ReadMe.md
>> @@ -0,0 +1,65 @@
>> +# UsbNetworkPkg
>> +
>> +This document is intend to provide package information, include the interface details.
>> +
>> +# INDEX
>> + * [Introduction](#introduction)
>> + * [Components](#components)
>> + * [[NetworkCommon]](#networkcommon)
>> + * [[UsbCdcEcm]](#usbcdcecm)
>> + * [[UsbCdcNcm]](#usbcdcncm)
>> + * [[UsbRndis]](#usbrndis)
>> +
>> +# Introduction
>> +UsbNetworkPkg provides network functions for USB LAN devices.
>> +
>> +# Components
>> +Below module is included in this package:<br>
>> +- NetworkCommon
>> +- UsbCdcEcm
>> +- UsbCdcNcm
>> +- UsbRndis
>> +
>> +## [NetworkCommon]
>> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
>> +
>> +## Required Components
>> +- NetworkPkg
>> +
>> +## [UsbCdcEcm]
>> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x06|0x00|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> +## [UsbCdcNcm]
>> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x0D|0x00|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> +## [UsbRndis]
>> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x02|0xFF|
>> +|0xEF|0x04|0x01|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
>> new file mode 100644
>> index 000000000000..f8ccccdb0830
>> --- /dev/null
>> +++ b/UsbNetworkPkg/ReleaseNotes.md
>> @@ -0,0 +1,11 @@
>> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
>> +
>> +# Release History<!-- omit in toc -->
>> +- [1.00](#100)
>> +
>> +## 1.00
>> +
>> +**Release Date:** Mar 10, 2022
>> +
>> +**New Features**
>> +- UsbNetworkPkg first release.
>> --
>> 2.35.1.windows.2
>> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
> -The information contained in this message may be confidential and
> proprietary to American Megatrends (AMI). This communication is
> intended to be read only by the individual or entity to whom it is
> addressed or by their designee. If the reader of this message is not
> the intended recipient, you are on notice that any distribution of this
> message, in any form, is strictly prohibited. Please promptly notify
> the sender by reply e-mail or by telephone at 770-246-8600, and then
> delete or destroy all copies of the transmission.
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
2023-04-07 2:49 ` RichardHo [何明忠]
2023-04-07 2:52 ` [edk2-devel] " Rebecca Cran
@ 2023-04-07 11:47 ` Rebecca Cran
1 sibling, 0 replies; 11+ messages in thread
From: Rebecca Cran @ 2023-04-07 11:47 UTC (permalink / raw)
To: Richard Ho (何明忠), devel@edk2.groups.io
Cc: Andrew Fish, Leif Lindholm, Michael D Kinney, Michael Kubacki,
Zhiguang Liu, Liming Gao, Tinh Nguyen,
Tony Lo (羅金松)
Thanks. I think I know what's happening: Exchange is converting your
messages from 8bit to quoted-printable before sending them to recipients.
I found this message from 2005 of it doing the same thing:
https://www.mhonarc.org/archive/html/fetchmail-friends/2005-01/msg00017.html
--
Rebecca Cran
On 4/6/23 8:49 PM, Richard Ho (何明忠) wrote:
> Hi Rebecca,
>
> I have already run the SetupGit.py before send the mail.
> (Use git send-email --transfer-encoding=8bit --annotate --suppress-from --to devel@edk2.groups.io *.patch to send mail)
>
> Below is my .git/config
>
> [core]
> repositoryformatversion = 0
> filemode = false
> bare = false
> logallrefupdates = true
> symlinks = false
> ignorecase = true
> abbrev = 12
> attributesFile = D:/EDKII-Upstream/edk2/BaseTools/Conf/gitattributes
> whitespace = cr-at-eol
> [remote "origin"]
> url = https://github.com/tianocore/edk2.git
> fetch = +refs/heads/*:refs/remotes/origin/*
> [branch "master"]
> remote = origin
> merge = refs/heads/master
> [am]
> keepcr = True
> signoff = True
> [cherry-pick]
> signoff = True
> [color]
> diff = True
> grep = auto
> [commit]
> signoff = True
> [diff]
> algorithm = patience
> orderFile = D:/EDKII-Upstream/edk2/BaseTools/Conf/diff.order
> renames = copies
> statGraphWidth = 20
> [diff "ini"]
> xfuncname = ^\\[[A-Za-z0-9_., ]+]
> [format]
> coverLetter = True
> numbered = True
> signoff = False
> [log]
> mailmap = True
> [notes]
> rewriteRef = refs/notes/commits
> [sendemail]
> chainreplyto = False
> thread = True
> transferEncoding = 8bit
> to = devel@edk2.groups.io
>
> Thanks,
> Richard
>
> -----Original Message-----
> From: Rebecca Cran <rebecca@bsdio.com>
> Sent: 2023年4月7日 9:57 AM
> To: Richard Ho (何明忠) <RichardHo@ami.com>; devel@edk2.groups.io
> Cc: Andrew Fish <afish@apple.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Michael D Kinney <michael.d.kinney@intel.com>; Michael Kubacki <mikuback@linux.microsoft.com>; Zhiguang Liu <zhiguang.liu@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>; Tinh Nguyen <tinhnguyen@os.amperecomputing.com>; Tony Lo (羅金松) <TonyLo@ami.com>
> Subject: [EXTERNAL] Re: [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
>
>
> **CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**
>
> Your patches are still coming through rather mangled, unfortunately.
>
> You should be sending them as 8bit, not quoted-printable - the
> BaseTools/Scripts/SetupGit.py script will configure the settings for you.
>
> Also, there should be a cover letter with the patch series: that script
> configures "git format-patch" to generate one.
>
>
> If you've already run SetupGit.py, could you tell me what .git/config in
> your edk2 clone contains, please?
>
>
> --
> Rebecca Cran
>
>
> On 3/9/23 12:51 AM, Richard Ho (何明忠) wrote:
>> This driver provides UEFI driver for USB RNDIS device
>>
>> Signed-off-by: Richard Ho <richardho@ami.com>
>> Cc: Andrew Fish <afish@apple.com>
>> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
>> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
>> Cc: Liming Gao <gaoliming@byosoft.com.cn>
>> Cc: Rebecca Cran <rebecca@bsdio.com>
>> Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
>> Reviewed-by: Tony Lo <tonylo@ami.com>
>> ---
>> UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
>> UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc | 9 +
>> .../Config/UsbNetworkPkgComponentsDxe.inc.dsc | 20 +
>> .../Config/UsbNetworkPkgDefines.inc.dsc | 23 +
>> .../Config/UsbNetworkPkgComponentsDxe.inc.fdf | 20 +
>> UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
>> UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
>> .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
>> UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
>> UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
>> UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
>> UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
>> UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803 +++++++++++++++++
>> UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
>> UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
>> UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718 ++++++++++++++++
>> UsbNetworkPkg/ReadMe.md | 65 +
>> UsbNetworkPkg/ReleaseNotes.md | 11 +
>> 18 files changed, 7452 insertions(+)
>> create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> create mode 100644 UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
>> create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
>> create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
>> create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> create mode 100644 UsbNetworkPkg/ReadMe.md
>> create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>>
>> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec b/UsbNetworkPkg/UsbNetworkPkg.dec
>> new file mode 100644
>> index 000000000000..30e4e4c8aac7
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
>> @@ -0,0 +1,46 @@
>> +## @file
>> +# This package defines Usb network specific interfaces and library classes
>> +# as well as configuration for standard edk2 packages.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + DEC_SPECIFICATION = 0x00010005
>> + PACKAGE_NAME = UsbNetworkPkg
>> + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
>> + PACKAGE_VERSION = 0.1
>> +
>> +[Includes]
>> + Include
>> +
>> +[Protocols]
>> + ## Include/Protocol/EdkIIUsbEthernet.h
>> + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
>> +
>> +[Guids]
>> + ## Usb Network package token space GUID
>> + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204, { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
>> +
>> +[PcdsFeatureFlag]
>> +
>> + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x00000001
>> +
>> + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x00000002
>> +
>> + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to be enabled.
>> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x00000003
>> +
>> +[PcdsFixedAtBuild, PcdsPatchableInModule]
>> + ## Support rate limiting
>> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x00010001
>> +
>> + ## The rate limiting Credit value is check in rate limiter event.
>> + # It is to control the RateLimitingCreditCount max value.
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x00010002
>> +
>> + ## The value of rate limiter event for timeout check. Default value is 100(unit 1ms).
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x00010003
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> new file mode 100644
>> index 000000000000..a3316b1d4a89
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> @@ -0,0 +1,9 @@
>> +## @file
>> +# Global DSC definitions to be included into project DSC file.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Components.X64]
>> +!include UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> new file mode 100644
>> index 000000000000..544df8404c64
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
>> + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
>> + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
>> + UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> +!endif
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> new file mode 100644
>> index 000000000000..85a309bcf567
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> @@ -0,0 +1,23 @@
>> +## @file
>> +# Global switches enable/disable project features.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> +!if "IA32" in $(ARCH) && "X64" in $(ARCH)
>> + DEFINE PEI=IA32
>> + DEFINE DXE=X64
>> +!else
>> + DEFINE PEI=COMMON
>> + DEFINE DXE=COMMON
>> +!endif
>> +
>> +[Packages]
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[PcdsFeatureFlag]
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
>> + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
>> + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> new file mode 100644
>> index 000000000000..10616d97edb4
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
>> + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
>> + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> +!endif
>> +
>> +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
>> + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> +!endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> new file mode 100644
>> index 000000000000..8923102bc350
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> @@ -0,0 +1,49 @@
>> +## @file
>> +# This is Usb Network Common driver for DXE phase.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = NetworkCommon
>> + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = NetworkCommonEntry
>> +
>> +[Sources]
>> + DriverBinding.c
>> + DriverBinding.h
>> + ComponentName.c
>> + PxeFunction.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + MdeModulePkg/MdeModulePkg.dec
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[LibraryClasses]
>> + UefiDriverEntryPoint
>> + UefiBootServicesTableLib
>> + UefiLib
>> + DebugLib
>> + UefiUsbLib
>> + MemoryAllocationLib
>> + BaseMemoryLib
>> +
>> +[Protocols]
>> + gEfiNetworkInterfaceIdentifierProtocolGuid_31
>> + gEfiUsbIoProtocolGuid
>> + gEfiDevicePathProtocolGuid
>> + gEfiDriverBindingProtocolGuid
>> + gEdkIIUsbEthProtocolGuid
>> +
>> +[Pcd]
>> + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
>> + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> new file mode 100644
>> index 000000000000..64205e427745
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> @@ -0,0 +1,42 @@
>> +## @file
>> +# This is Usb Rndis driver for DXE phase.
>> +#
>> +# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = UsbRndis
>> + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = UsbRndisEntry
>> +
>> +[Sources]
>> + UsbRndis.c
>> + UsbRndis.h
>> + UsbRndisFunction.c
>> + ComponentName.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + UsbNetworkPkg/UsbNetworkPkg.dec
>> +
>> +[LibraryClasses]
>> + UefiDriverEntryPoint
>> + UefiBootServicesTableLib
>> + UefiLib
>> + DebugLib
>> + UefiUsbLib
>> + MemoryAllocationLib
>> + BaseMemoryLib
>> +
>> +[Protocols]
>> + gEfiUsbIoProtocolGuid
>> + gEfiDevicePathProtocolGuid
>> + gEfiDriverBindingProtocolGuid
>> + gEdkIIUsbEthProtocolGuid
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> new file mode 100644
>> index 000000000000..f54946c7aa69
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
>> @@ -0,0 +1,878 @@
>> +/** @file
>> + Header file contains code for USB Ethernet Protocol
>> + definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
>> +#define EDKII_USB_ETHERNET_PROTOCOL_H_
>> +
>> +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
>> + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43}}
>> +
>> +typedef struct _EDKII_USB_ETHERNET_PROTOCOL EDKII_USB_ETHERNET_PROTOCOL;
>> +
>> +#define USB_CDC_CLASS 0x02
>> +#define USB_CDC_ACM_SUBCLASS 0x02
>> +#define USB_CDC_ECM_SUBCLASS 0x06
>> +#define USB_CDC_NCM_SUBCLASS 0x0D
>> +#define USB_CDC_DATA_CLASS 0x0A
>> +#define USB_CDC_DATA_SUBCLASS 0x00
>> +#define USB_NO_CLASS_PROTOCOL 0x00
>> +#define USB_NCM_NTB_PROTOCOL 0x01
>> +#define USB_VENDOR_PROTOCOL 0xFF
>> +
>> +// Type Values for the DescriptorType Field
>> +#define CS_INTERFACE 0x24
>> +#define CS_ENDPOINT 0x25
>> +
>> +// Descriptor SubType in Functional Descriptors
>> +#define HEADER_FUN_DESCRIPTOR 0x00
>> +#define UNION_FUN_DESCRIPTOR 0x06
>> +#define ETHERNET_FUN_DESCRIPTOR 0x0F
>> +
>> +#define MAX_LAN_INTERFACE 0x10
>> +
>> +// Table 20: Class-Specific Notification Codes
>> +#define USB_CDC_NETWORK_CONNECTION 0x00
>> +
>> +// 6.3.1 NetworkConnection
>> +#define NETWORK_CONNECTED 0x01
>> +#define NETWORK_DISCONNECT 0x00
>> +
>> +// USB Header functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT16 BcdCdc;
>> +} USB_HEADER_FUN_DESCRIPTOR;
>> +
>> +// USB Union Functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT8 MasterInterface;
>> + UINT8 SlaveInterface;
>> +} USB_UNION_FUN_DESCRIPTOR;
>> +
>> +// USB Ethernet Functional Descriptor
>> +typedef struct {
>> + UINT8 FunctionLength;
>> + UINT8 DescriptorType;
>> + UINT8 DescriptorSubtype;
>> + UINT8 MacAddress;
>> + UINT32 EthernetStatistics;
>> + UINT16 MaxSegmentSize;
>> + UINT16 NumberMcFilters;
>> + UINT8 NumberPowerFilters;
>> +} USB_ETHERNET_FUN_DESCRIPTOR;
>> +
>> +typedef struct {
>> + UINT32 UsBitRate;
>> + UINT32 DsBitRate;
>> +} USB_CONNECT_SPEED_CHANGE;
>> +
>> +// Request Type Codes for USB Ethernet
>> +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
>> +#define USB_ETHERNET_SET_REQ_TYPE 0x21
>> +
>> +// Class-Specific Request Codes for Ethernet subclass
>> +// USB ECM 1.2 specification, Section 6.2
>> +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
>> +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
>> +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
>> +#define SET_ETH_PACKET_FILTER_REQ 0x43
>> +#define GET_ETH_STATISTIC_REQ 0x44
>> +
>> +// USB ECM command request length
>> +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
>> +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
>> +#define USB_ETH_STATISTIC 4 // Section 6.2.5
>> +
>> +// USB Ethernet Packet Filter Bitmap
>> +// USB ECM 1.2 specification, Section 6.2.4
>> +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
>> +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
>> +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
>> +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
>> +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
>> +
>> +// USB Ethernet Statistics Feature Selector Codes
>> +// USB ECM 1.2 specification, Section 6.2.5
>> +#define USB_ETH_XMIT_OK 0x01
>> +#define USB_ETH_RCV_OK 0x02
>> +#define USB_ETH_XMIT_ERROR 0x03
>> +#define USB_ETH_RCV_ERROR 0x04
>> +#define USB_ETH_RCV_NO_BUFFER 0x05
>> +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
>> +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
>> +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
>> +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
>> +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
>> +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
>> +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
>> +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
>> +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
>> +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
>> +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
>> +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
>> +#define USB_ETH_RCV_CRC_ERROR 0x12
>> +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
>> +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
>> +#define USB_ETH_XMIT_ONE_COLLISION 0x15
>> +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
>> +#define USB_ETH_XMIT_DEFERRED 0x17
>> +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
>> +#define USB_ETH_RCV_OVERRUN 0x19
>> +#define USB_ETH_XMIT_UNDERRUN 0x1A
>> +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
>> +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
>> +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
>> +
>> +// NIC Information
>> +typedef struct {
>> + UINT32 Signature;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + UINT16 InterrupOpFlag;
>> + UINT64 MappedAddr;
>> + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
>> + UINT8 McastCount;
>> + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
>> + UINT8 TxBufferCount;
>> + UINT16 State;
>> + BOOLEAN CanTransmit;
>> + UINT16 ReceiveStatus;
>> + UINT8 RxFilter;
>> + UINT32 RxFrame;
>> + UINT32 TxFrame;
>> + UINT16 NetworkConnect;
>> + UINT8 CableDetect;
>> + UINT16 MaxSegmentSize;
>> + EFI_MAC_ADDRESS MacAddr;
>> + PXE_CPB_START_31 PxeStart;
>> + PXE_CPB_INITIALIZE PxeInit;
>> + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
>> + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
>> + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
>> + EFI_USB_DEVICE_REQUEST Request;
>> + EFI_EVENT RateLimiter;
>> + UINT32 RateLimitingCredit;
>> + UINT32 RateLimitingCreditCount;
>> + UINT32 RateLimitingPollTimer;
>> + BOOLEAN RateLimitingEnable;
>> +} NIC_DATA;
>> +
>> +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
>> +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a, NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
>> +
>> +/**
>> + This command is used to determine the operational state of the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to change the UNDI operational state from stopped to started.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to change the UNDI operational state from started to stopped.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to retrieve initialization information that is
>> + needed by drivers and applications to initialized UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to retrieve configuration information about
>> + the NIC being controlled by the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and reinitializes the UNDI
>> + with the same parameters provided in the Initialize command.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Shutdown command resets the network adapter and leaves it in a
>> + safe state for another driver to initialize.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Interrupt Enables command can be used to read and/or change
>> + the current external interrupt enable settings.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and change receive filters and,
>> + if supported, read and change the multicast MAC address filter list.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to get current station and broadcast MAC addresses
>> + and, if supported, to change the current station MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and write (if supported by NIC H/W)
>> + nonvolatile storage on the NIC.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command returns the current interrupt status and/or the
>> + transmitted buffer addresses and the current media status.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to fill the media header(s) in transmit packet(s).
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + The Transmit command is used to place a packet into the transmit queue.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + When the network adapter has received a frame, this command is used
>> + to copy the frame into driver/application storage.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] DbAddr Data Block Address.
>> + @param[in] DbSize Data Block Size.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] PacketLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
>> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
>> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *Packet,
>> + IN OUT UINTN *PacketLength
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] Packet A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] PacketLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is returned in status.
>> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be submitted due to a lack of resources.
>> + @retval EFI_TIMEOUT The control transfer fails due to timeout.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *Packet,
>> + IN OUT UINTN *PacketLength
>> + );
>> +
>> +/**
>> + This function is used to manage a USB device with an interrupt transfer pipe.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
>> + FALSE, the interrupt transfer is deleted from the device's interrupt
>> + transfer queue.
>> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
>> + executed.This parameter is required when IsNewTransfer is TRUE. The
>> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
>> + The units are in milliseconds.
>> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
>> +
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Request
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet Mac Address.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet Bulk transfer data size.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] BulkSize A pointer to the Bulk transfer data size.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + );
>> +
>> +/**
>> + Retrieves the USB Header functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + );
>> +
>> +/**
>> + Retrieves the USB Union functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + );
>> +
>> +/**
>> + Retrieves the USB Ethernet functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + );
>> +
>> +/**
>> + This request sets the Ethernet device multicast filters as specified in the
>> + sequential list of 48 bit Ethernet multicast addresses.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] McastAddr A pointer to the value of the multicast addresses.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + );
>> +
>> +/**
>> + This request sets up the specified Ethernet power management pattern filter as
>> + described in the data structure.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] Length Size of the power management pattern filter data.
>> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + );
>> +
>> +/**
>> + This request retrieves the status of the specified Ethernet power management
>> + pattern filter from the device.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value The filter number.
>> + @param[out] PatternActive A pointer to the pattern active boolean.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + OUT BOOLEAN *PatternActive
>> + );
>> +
>> +/**
>> + This request is used to configure device Ethernet packet filter settings.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Packet Filter Bitmap.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + );
>> +
>> +/**
>> + This request is used to retrieve a statistic based on the feature selector.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] FeatureSelector Value of the feature selector.
>> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +**/
>> +typedef
>> +EFI_STATUS
>> +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 FeatureSelector,
>> + OUT VOID *Statistic
>> + );
>> +
>> +typedef struct {
>> + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
>> + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
>> + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
>> + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
>> + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO UsbEthUndiGetConfigInfo;
>> + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
>> + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
>> + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
>> + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE UsbEthUndiInterruptEnable;
>> + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER UsbEthUndiReceiveFilter;
>> + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS UsbEthUndiStationAddress;
>> + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
>> + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC UsbEthUndiMcastIp2Mac;
>> + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
>> + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
>> + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
>> + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
>> + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
>> +} EDKII_USB_ETHERNET_UNDI;
>> +
>> +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device relevant
>> +// descriptor and specific requests.
>> +struct _EDKII_USB_ETHERNET_PROTOCOL {
>> + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
>> + // for calling the UNDI child functions
>> + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
>> + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
>> + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
>> + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
>> + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
>> + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
>> + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
>> + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR UsbHeaderFunDescriptor;
>> + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR UsbUnionFunDescriptor;
>> + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR UsbEthFunDescriptor;
>> + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS SetUsbEthMcastFilter;
>> + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER SetUsbEthPowerPatternFilter;
>> + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER GetUsbEthPowerPatternFilter;
>> + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER SetUsbEthPacketFilter;
>> + EDKII_USB_ETHERNET_GET_ETH_STATISTIC GetUsbEthStatistic;
>> +};
>> +
>> +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> new file mode 100644
>> index 000000000000..0416ce132302
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> @@ -0,0 +1,266 @@
>> +/** @file
>> + Header file for for USB network common driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef _DRIVER_BINDING_H_
>> +#define _DRIVER_BINDING_H_
>> +
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/UefiUsbLib.h>
>> +#include <Protocol/UsbIo.h>
>> +#include <Protocol/NetworkInterfaceIdentifier.h>
>> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
>> +
>> +#define NETWORK_COMMON_DRIVER_VERSION 1
>> +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
>> +#define RX_BUFFER_COUNT 32
>> +#define TX_BUFFER_COUNT 32
>> +#define MEMORY_REQUIRE 0
>> +
>> +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
>> +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol, UNDI_DEV_SIGNATURE)
>> +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo, UNDI_DEV_SIGNATURE)
>> +
>> +#pragma pack(1)
>> +typedef struct {
>> + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
>> + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
>> + UINT16 Protocol;
>> +} EthernetHeader;
>> +#pragma pack()
>> +
>> +typedef struct {
>> + UINTN Signature;
>> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
>> + EFI_HANDLE DeviceHandle;
>> + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
>> + EFI_DEVICE_PATH_PROTOCOL *DevPath;
>> + NIC_DATA NicInfo;
>> + VOID *ReceiveBuffer;
>> +} NIC_DEVICE;
>> +
>> +typedef VOID (*API_FUNC)(
>> + PXE_CDB *,
>> + NIC_DATA *
>> + );
>> +
>> +extern PXE_SW_UNDI *gPxe;
>> +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
>> +extern EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + );
>> +
>> +VOID
>> +PxeStructInit (
>> + OUT PXE_SW_UNDI *PxeSw
>> + );
>> +
>> +VOID
>> +UpdateNicNum (
>> + IN NIC_DATA *Nic,
>> + IN OUT PXE_SW_UNDI *PxeSw
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UndiApiEntry (
>> + IN UINT64 Cdb
>> + );
>> +
>> +UINTN
>> +MapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + OUT UINT64 MappedAddr
>> + );
>> +
>> +VOID
>> +UnMapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + IN UINT64 MappedAddr
>> + );
>> +
>> +VOID
>> +UndiGetState (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiInterruptEnable (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStationAddress (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiStatistics (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiMcastIp2Mac (
>> + IN OUT PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiNvData (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiFillHeader (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +VOID
>> +UndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +UINT16
>> +Initialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + );
>> +
>> +UINT16
>> +Transmit (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN UINT16 OpFlags
>> + );
>> +
>> +UINT16
>> +Receive (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN OUT UINT64 DbAddr
>> + );
>> +
>> +UINT16
>> +SetFilter (
>> + IN NIC_DATA *Nic,
>> + IN UINT16 SetFilter,
>> + IN UINT64 CpbAddr,
>> + IN UINT32 CpbSize
>> + );
>> +
>> +UINT16
>> +Statistics (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + );
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> new file mode 100644
>> index 000000000000..775807042460
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> @@ -0,0 +1,586 @@
>> +/** @file
>> + Header file for for USB Rndis driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef _USB_RNDIS_H_
>> +#define _USB_RNDIS_H_
>> +
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/UefiUsbLib.h>
>> +#include <Protocol/UsbIo.h>
>> +#include <Protocol/EdkIIUsbEthernetProtocol.h>
>> +
>> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
>> +
>> +typedef struct {
>> + UINT32 Signature;
>> + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
>> + EFI_HANDLE UsbCdcDataHandle;
>> + EFI_HANDLE UsbRndisHandle;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
>> + EFI_USB_CONFIG_DESCRIPTOR *Config;
>> + UINT8 NumOfInterface;
>> + UINT8 BulkInEndpoint;
>> + UINT8 BulkOutEndpoint;
>> + UINT8 InterrupEndpoint;
>> + EFI_MAC_ADDRESS MacAddress;
>> + UINT32 RequestId;
>> + UINT32 Medium;
>> + UINT32 MaxPacketsPerTransfer;
>> + UINT32 MaxTransferSize;
>> + UINT32 PacketAlignmentFactor;
>> + LIST_ENTRY ReceivePacketList;
>> +} USB_RNDIS_DEVICE;
>> +
>> +#define USB_RNDIS_DRIVER_VERSION 1
>> +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
>> +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
>> +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
>> +
>> +#define LAN_BULKIN_CMD_CONTROL 1
>> +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum counts for waiting bulk in command
>> +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum counts for waiting bulk in command
>> +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting counts for send bulk in command when system pending
>> +#define RNDIS_RESERVED_BYTE_LENGTH 8
>> +
>> +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
>> +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE, UsbEth, USB_RNDIS_SIGNATURE)
>> +
>> +extern EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2;
>> +
>> +struct BIT_MAP {
>> + unsigned int Src;
>> + unsigned int Dst;
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + );
>> +
>> +EFI_STATUS
>> +LoadAllDescriptor (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
>> + );
>> +
>> +BOOLEAN
>> +NextDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
>> + IN OUT UINTN *Offset
>> + );
>> +
>> +EFI_STATUS
>> +GetFunctionalDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
>> + IN UINT8 FunDescriptorType,
>> + OUT VOID *DataBuffer
>> + );
>> +
>> +VOID
>> +GetEndpoint (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisInterrupt (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Requst
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +InterruptCallback (
>> + IN VOID *Data,
>> + IN UINTN DataLength,
>> + IN VOID *Context,
>> + IN UINT32 Status
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbEthMacAddress (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbEthBulkSize (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisDummyReturn (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN VOID *BulkOutData,
>> + IN OUT UINTN *DataLength
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *BulkInData,
>> + IN OUT UINTN *DataLength
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbHeaderFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbUnionFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisMcastFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN BOOLEAN *PatternActive
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPacketFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GetRndisStatistic (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *Statistic
>> + );
>> +
>> +EFI_STATUS
>> +RndisControlMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
>> + );
>> +
>> +EFI_STATUS
>> +RndisTransmitDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + UINTN *TransferLength
>> + );
>> +
>> +EFI_STATUS
>> +RndisReceiveDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + UINTN *TransferLength
>> + );
>> +
>> +VOID
>> +PrintRndisMsg (
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
>> + );
>> +
>> +#define RNDIS_MAJOR_VERSION 0x00000001
>> +#define RNDIS_MINOR_VERSION 0x00000000
>> +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
>> +
>> +#define RNDIS_PACKET_MSG 0x00000001
>> +#define RNDIS_INITIALIZE_MSG 0x00000002
>> +#define RNDIS_INITIALIZE_CMPLT 0x80000002
>> +#define RNDIS_HLT_MSG 0x00000003
>> +#define RNDIS_QUERY_MSG 0x00000004
>> +#define RNDIS_QUERY_CMPLT 0x80000004
>> +#define RNDIS_SET_MSG 0x00000005
>> +#define RNDIS_SET_CMPLT 0x80000005
>> +#define RNDIS_RESET_MSG 0x00000006
>> +#define RNDIS_RESET_CMPLT 0x80000006
>> +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
>> +#define RNDIS_KEEPALIVE_MSG 0x00000008
>> +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
>> +
>> +#define RNDIS_STATUS_SUCCESS 0x00000000
>> +#define RNDIS_STATUS_FAILURE 0xC0000001
>> +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
>> +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
>> +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
>> +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
>> +
>> +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
>> +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
>> +
>> +#define SEND_ENCAPSULATED_COMMAND 0x00000000
>> +#define GET_ENCAPSULATED_RESPONSE 0x00000001
>> +
>> +//
>> +// General Objects
>> +//
>> +// Taken from NTDDNDIS.H
>> +#define OID_GEN_SUPPORTED_LIST 0x00010101
>> +#define OID_GEN_HARDWARE_STATUS 0x00010102
>> +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
>> +#define OID_GEN_MEDIA_IN_USE 0x00010104
>> +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
>> +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
>> +#define OID_GEN_LINK_SPEED 0x00010107
>> +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
>> +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
>> +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
>> +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
>> +#define OID_GEN_VENDOR_ID 0x0001010C
>> +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
>> +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
>> +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
>> +#define OID_GEN_DRIVER_VERSION 0x00010110
>> +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
>> +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
>> +#define OID_GEN_MAC_OPTIONS 0x00010113
>> +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
>> +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
>> +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
>> +
>> +#define OID_GEN_XMIT_OK 0x00020101
>> +#define OID_GEN_RCV_OK 0x00020102
>> +#define OID_GEN_XMIT_ERROR 0x00020103
>> +#define OID_GEN_RCV_ERROR 0x00020104
>> +#define OID_GEN_RCV_NO_BUFFER 0x00020105
>> +
>> +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
>> +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
>> +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
>> +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
>> +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
>> +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
>> +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
>> +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
>> +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
>> +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
>> +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
>> +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
>> +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
>> +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
>> +
>> +#define OID_802_3_CURRENT_ADDRESS 0x01010102
>> +//
>> +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
>> +//
>> +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
>> +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
>> +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
>> +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
>> +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
>> +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
>> +#define NDIS_PACKET_TYPE_SMT 0x0040
>> +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
>> +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
>> +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
>> +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
>> +#define NDIS_PACKET_TYPE_GROUP 0x1000
>> +
>> +#pragma pack(1)
>> +
>> +typedef struct _REMOTE_NDIS_MSG_HEADER {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> +} REMOTE_NDIS_MSG_HEADER;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 MajorVersion;
>> + UINT32 MinorVersion;
>> + UINT32 MaxTransferSize;
>> +} REMOTE_NDIS_INITIALIZE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> +} REMOTE_NDIS_HALT_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Oid;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_QUERY_MSG;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_MSG QueryMsg;
>> + UINT8 Addr[6];
>> +} REMOTE_NDIS_QUERY_MAC_MSG;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_MSG QueryMsg;
>> + UINT32 MaxTotalSize;
>> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Oid;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_SET_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Reserved;
>> +} REMOTE_NDIS_RESET_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Status;
>> + UINT32 StatusBufferLength;
>> + UINT32 StatusBufferOffset;
>> +} REMOTE_NDIS_INDICATE_STATUS_MSG;
>> +
>> +typedef struct {
>> + UINT32 DiagStatus;
>> + UINT32 ErrorOffset;
>> +} RNDIS_DIAGNOSTIC_INFO;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> +} REMOTE_NDIS_KEEPALIVE_MSG;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> + UINT32 MajorVersion;
>> + UINT32 MinorVersion;
>> + UINT32 DeviceFlags;
>> + UINT32 Medium;
>> + UINT32 MaxPacketsPerTransfer;
>> + UINT32 MaxTransferSize;
>> + UINT32 PacketAlignmentFactor;
>> + UINT64 Reserved;
>> +} REMOTE_NDIS_INITIALIZE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> + UINT32 InformationBufferLength;
>> + UINT32 InformationBufferOffset;
>> +} REMOTE_NDIS_QUERY_CMPLT;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
>> + UINT8 Addr[6];
>> +} REMOTE_NDIS_QUERY_MAC_CMPLT;
>> +
>> +typedef struct {
>> + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
>> + UINT32 MaxTotalSize;
>> +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> +} REMOTE_NDIS_SET_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 Status;
>> + UINT32 AddressingReset;
>> +} REMOTE_NDIS_RESET_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 RequestID;
>> + UINT32 Status;
>> +} REMOTE_NDIS_KEEPALIVE_CMPLT;
>> +
>> +typedef struct {
>> + UINT32 MessageType;
>> + UINT32 MessageLength;
>> + UINT32 DataOffset;
>> + UINT32 DataLength;
>> + UINT32 OutOfBandDataOffset;
>> + UINT32 OutOfBandDataLength;
>> + UINT32 NumOutOfBandDataElements;
>> + UINT32 PerPacketInfoOffset;
>> + UINT32 PerPacketInfoLength;
>> + UINT32 Reserved1;
>> + UINT32 Reserved2;
>> +} REMOTE_NDIS_PACKET_MSG;
>> +
>> +typedef struct {
>> + UINT32 Size;
>> + UINT32 Type;
>> + UINT32 ClassInformationOffset;
>> +} OUT_OF_BAND_DATA_RECORD;
>> +
>> +typedef struct {
>> + UINT32 Size;
>> + UINT32 Type;
>> + UINT32 ClassInformationOffset;
>> +} PER_PACKET_INFO_DATA_RECORD;
>> +
>> +typedef struct {
>> + LIST_ENTRY PacketList;
>> + UINT8 *OrgBuffer;
>> + UINTN RemainingLength;
>> + UINT8 *PacketStartBuffer; // Variable size data to follow
>> +} PACKET_LIST;
>> +
>> +#pragma pack()
>> +
>> +#endif
>> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> new file mode 100644
>> index 000000000000..e83469e13079
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> @@ -0,0 +1,263 @@
>> +/** @file
>> + This file contains code for USB network common driver
>> + component name definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +extern EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding;
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gNetworkCommonDriverNameTable[] = {
>> + {
>> + "eng;en",
>> + L"Network Common Driver"
>> + },
>> + {
>> + NULL,
>> + NULL
>> + }
>> +};
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gNetworkCommonControllerNameTable = NULL;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName = {
>> + NetworkCommonComponentNameGetDriverName,
>> + NetworkCommonComponentNameGetControllerName,
>> + "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNetworkCommonComponentName2 = {
>> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonComponentNameGetDriverName,
>> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonComponentNameGetControllerName,
>> + "en"
>> +};
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Language 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[out] DriverName 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
>> +NetworkCommonComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + )
>> +{
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gNetworkCommonDriverNameTable,
>> + DriverName,
>> + (BOOLEAN)(This == &gNetworkCommonComponentName)
>> + );
>> +}
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
>> + @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
>> +NetworkCommonComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + )
>> +{
>> + EFI_STATUS Status;
>> + CHAR16 *HandleName;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
>> +
>> + if (!Language || !ControllerName) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + if (ChildHandle == NULL) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + //
>> + // Make sure this driver is currently managing ControllerHandle
>> + //
>> + Status = EfiTestManagedDevice (
>> + Controller,
>> + gNetworkCommonDriverBinding.DriverBindingHandle,
>> + &gEdkIIUsbEthProtocolGuid
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + //
>> + // Make sure this driver produced ChildHandle
>> + //
>> + Status = EfiTestChildHandle (
>> + Controller,
>> + ChildHandle,
>> + &gEdkIIUsbEthProtocolGuid
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid, (VOID **)&UsbIo);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409, DevDesc.StrManufacturer, &HandleName);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *ControllerName = HandleName;
>> +
>> + if (gNetworkCommonControllerNameTable != NULL) {
>> + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
>> + gNetworkCommonControllerNameTable = NULL;
>> + }
>> +
>> + Status = AddUnicodeString2 (
>> + "eng",
>> + gNetworkCommonComponentName.SupportedLanguages,
>> + &gNetworkCommonControllerNameTable,
>> + HandleName,
>> + TRUE
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = AddUnicodeString2 (
>> + "en",
>> + gNetworkCommonComponentName2.SupportedLanguages,
>> + &gNetworkCommonControllerNameTable,
>> + HandleName,
>> + FALSE
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gNetworkCommonControllerNameTable,
>> + ControllerName,
>> + (BOOLEAN)(This == &gNetworkCommonComponentName)
>> + );
>> + }
>> +
>> + return EFI_UNSUPPORTED;
>> +}
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> new file mode 100644
>> index 000000000000..23b791362091
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> @@ -0,0 +1,595 @@
>> +/** @file
>> + This file contains code for USB network binding driver
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +PXE_SW_UNDI *gPxe = NULL;
>> +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
>> +UINT32 gRateLimitingCredit;
>> +UINT32 gRateLimitingPollTimer;
>> +BOOLEAN gRateLimitingEnable;
>> +
>> +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
>> + NetworkCommonSupported,
>> + NetworkCommonDriverStart,
>> + NetworkCommonDriverStop,
>> + NETWORK_COMMON_DRIVER_VERSION,
>> + NULL,
>> + NULL
>> +};
>> +
>> +/**
>> + Create MAC Device Path
>> +
>> + @param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
>> + @retval EFI_SUCCESS MAC device path created successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +CreateMacDevicePath (
>> + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
>> + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> + MAC_ADDR_DEVICE_PATH MacAddrNode;
>> + EFI_DEVICE_PATH_PROTOCOL *EndNode;
>> + UINT8 *DevicePath;
>> + UINT16 TotalLength;
>> + UINT16 BaseLength;
>> +
>> + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
>> + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
>> +
>> + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
>> + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
>> + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
>> + MacAddrNode.Header.Length[1] = 0;
>> +
>> + EndNode = BaseDev;
>> +
>> + while (!IsDevicePathEnd (EndNode)) {
>> + EndNode = NextDevicePathNode (EndNode);
>> + }
>> +
>> + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
>> + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
>> +
>> + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
>> + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
>> + DevicePath += BaseLength;
>> + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
>> + DevicePath += sizeof (MacAddrNode);
>> + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Support.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to test.
>> + @param[in] 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
>> +NetworkCommonSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Start.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
>> + @retval other This driver does not support this device
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + EFI_MAC_ADDRESS MacAddress;
>> + UINTN BulkDataSize;
>> + NIC_DEVICE *NicDevice;
>> + UINT8 *TmpPxePointer;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbEthPath,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
>> +
>> + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
>> + ASSERT_EFI_ERROR (Status);
>> + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
>> + if (!NicDevice) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + // for alignment adjustment
>> + if (gPxe == NULL) {
>> + TmpPxePointer = NULL;
>> + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
>> + if (!TmpPxePointer) {
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + return EFI_OUT_OF_RESOURCES;
>> + } else {
>> + // check for paragraph alignment here
>> + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
>> + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
>> + } else {
>> + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
>> + }
>> +
>> + if (!gPxe) {
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + PxeStructInit (gPxe);
>> + }
>> + }
>> +
>> + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
>> + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
>> +
>> + UpdateNicNum (&NicDevice->NicInfo, gPxe);
>> +
>> + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
>> +
>> + NicDevice->NicInfo.UsbEth = UsbEth;
>> + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
>> + NicDevice->NicInfo.CableDetect = 0;
>> + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
>> +
>> + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
>> +
>> + NicDevice->NicInfo.TxBufferCount = 0;
>> +
>> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
>> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
>> + } else {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> +
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = CreateMacDevicePath (
>> + &NicDevice->DevPath,
>> + UsbEthPath,
>> + &NicDevice->NicInfo
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + UpdateNicNum (NULL, gPxe);
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> + }
>> +
>> + NicDevice->Signature = UNDI_DEV_SIGNATURE;
>> + NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
>> + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
>> + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
>> + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
>> + NicDevice->NiiProtocol.ImageSize = 0;
>> + NicDevice->NiiProtocol.ImageAddr = 0;
>> + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
>> +
>> + NicDevice->NiiProtocol.StringId[0] = 'U';
>> + NicDevice->NiiProtocol.StringId[1] = 'N';
>> + NicDevice->NiiProtocol.StringId[2] = 'D';
>> + NicDevice->NiiProtocol.StringId[3] = 'I';
>> + NicDevice->DeviceHandle = NULL;
>> +
>> + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
>> + NicDevice->NicInfo.RateLimitingCreditCount = 0;
>> + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
>> + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
>> + NicDevice->NicInfo.RateLimiter = NULL;
>> +
>> + ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &NicDevice->DeviceHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
>> + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + if (TmpPxePointer != NULL) {
>> + FreePool (TmpPxePointer);
>> + }
>> +
>> + if (NicDevice->DevPath != NULL) {
>> + FreePool (NicDevice->DevPath);
>> + }
>> +
>> + if (NicDevice != NULL) {
>> + FreePool (NicDevice);
>> + }
>> +
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + NicDevice->DeviceHandle,
>> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> + );
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Network Common Driver Binding Stop.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to stop driver on
>> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
>> + children is zero stop the entire bus driver.
>> + @param[in] 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
>> +NetworkCommonDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + BOOLEAN AllChildrenStopped;
>> + UINTN Index;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
>> + NIC_DEVICE *NicDevice;
>> + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
>> +
>> + if (NumberOfChildren == 0) {
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + (VOID **)&NiiProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_SUCCESS;
>> + }
>> +
>> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
>> + Status = gBS->UninstallMultipleProtocolInterfaces (
>> + ControllerHandle,
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + FreePool (NicDevice->DevPath);
>> + FreePool (NicDevice);
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_SUCCESS;
>> + }
>> +
>> + AllChildrenStopped = TRUE;
>> +
>> + for (Index = 0; Index < NumberOfChildren; Index++) {
>> + Status = gBS->OpenProtocol (
>> + ChildHandleBuffer[Index],
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + (VOID **)&NiiProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + AllChildrenStopped = FALSE;
>> + continue;
>> + }
>> +
>> + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + This->DriverBindingHandle,
>> + ChildHandleBuffer[Index]
>> + );
>> +
>> + Status = gBS->UninstallMultipleProtocolInterfaces (
>> + ChildHandleBuffer[Index],
>> + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
>> + &NicDevice->NiiProtocol,
>> + &gEfiDevicePathProtocolGuid,
>> + NicDevice->DevPath,
>> + NULL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEth,
>> + This->DriverBindingHandle,
>> + ChildHandleBuffer[Index],
>> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> + );
>> + } else {
>> + FreePool (NicDevice->DevPath);
>> + FreePool (NicDevice);
>> + }
>> + }
>> +
>> + if (!AllChildrenStopped) {
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Entrypoint of Network Common Driver.
>> +
>> + This function is the entrypoint of Network Common Driver. It installs Driver Binding
>> + Protocols together with Component Name Protocols.
>> +
>> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
>> + @param[in] SystemTable A pointer to the EFI System Table.
>> +
>> + @retval EFI_SUCCESS The entry point is executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NetworkCommonEntry (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
>> + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
>> + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
>> + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
>> + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &gNetworkCommonDriverBinding.DriverBindingHandle,
>> + &gEfiDriverBindingProtocolGuid,
>> + &gNetworkCommonDriverBinding,
>> + &gEfiComponentName2ProtocolGuid,
>> + &gNetworkCommonComponentName2,
>> + NULL
>> + );
>> + return Status;
>> +}
>> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> new file mode 100644
>> index 000000000000..687cabca4ce3
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> @@ -0,0 +1,1803 @@
>> +/** @file
>> + This file contains code for UNDI command based on UEFI specification.
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "DriverBinding.h"
>> +
>> +// API table, defined in UEFI specification
>> +API_FUNC gUndiApiTable[] = {
>> + UndiGetState,
>> + UndiStart,
>> + UndiStop,
>> + UndiGetInitInfo,
>> + UndiGetConfigInfo,
>> + UndiInitialize,
>> + UndiReset,
>> + UndiShutdown,
>> + UndiInterruptEnable,
>> + UndiReceiveFilter,
>> + UndiStationAddress,
>> + UndiStatistics,
>> + UndiMcastIp2Mac,
>> + UndiNvData,
>> + UndiGetStatus,
>> + UndiFillHeader,
>> + UndiTransmit,
>> + UndiReceive
>> +};
>> +
>> +/**
>> + Callback function for enable Rate Limiter
>> +
>> + @param[in] Event Event whose notification function is being invoked
>> + @param[in] Context Pointer to the notification function's context
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +UndiRateLimiterCallback (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + )
>> +{
>> + NIC_DATA *Nic = Context;
>> +
>> + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
>> + Nic->RateLimitingCreditCount++;
>> + }
>> +}
>> +
>> +/**
>> + This command is used to determine the operational state of the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetState (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to change the UNDI operational state from stopped to started.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_START_31 *Cpb;
>> + EFI_STATUS Status;
>> + BOOLEAN EventError;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_START) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
>> +
>> + Nic->PxeStart.Delay = Cpb->Delay;
>> + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
>> + Nic->PxeStart.Block = Cpb->Block;
>> + Nic->PxeStart.Map_Mem = 0;
>> + Nic->PxeStart.UnMap_Mem = 0;
>> + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
>> + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
>> + EventError = FALSE;
>> + Status = EFI_SUCCESS;
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + Status = gBS->CreateEvent (
>> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
>> + TPL_NOTIFY,
>> + UndiRateLimiterCallback,
>> + Nic,
>> + &Nic->RateLimiter
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + Status = gBS->SetTimer (
>> + Nic->RateLimiter,
>> + TimerPeriodic,
>> + Nic->RateLimitingPollTimer * 10000
>> + );
>> + if (EFI_ERROR (Status)) {
>> + EventError = TRUE;
>> + }
>> + }
>> + }
>> +
>> + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
>> + }
>> +
>> + if (!EFI_ERROR (Status)) {
>> + // Initial the state for UNDI start.
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + } else {
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + if (!EventError) {
>> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
>> + }
>> +
>> + if (Nic->RateLimiter) {
>> + gBS->CloseEvent (&Nic->RateLimiter);
>> + Nic->RateLimiter = 0;
>> + }
>> + }
>> +
>> + // Initial the state when UNDI start is fail
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
>> + }
>> +}
>> +
>> +/**
>> + This command is used to change the UNDI operational state from started to stopped.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
>> + return;
>> + }
>> +
>> + Nic->PxeStart.Delay = 0;
>> + Nic->PxeStart.Virt2Phys = 0;
>> + Nic->PxeStart.Block = 0;
>> + Nic->PxeStart.Map_Mem = 0;
>> + Nic->PxeStart.UnMap_Mem = 0;
>> + Nic->PxeStart.Sync_Mem = 0;
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
>> +
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
>> + gBS->CloseEvent (&Nic->RateLimiter);
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to retrieve initialization information that is
>> + needed by drivers and applications to initialized UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_INIT_INFO *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->MemoryRequired = MEMORY_REQUIRE;
>> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
>> + Db->LinkSpeeds[0] = 10;
>> + Db->LinkSpeeds[1] = 100;
>> + Db->LinkSpeeds[2] = 1000;
>> + Db->LinkSpeeds[3] = 0;
>> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
>> + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
>> + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
>> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
>> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
>> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
>> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
>> + Db->IFtype = PXE_IFTYPE_ETHERNET;
>> + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
>> + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
>> +
>> + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
>> + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to retrieve configuration information about
>> + the NIC being controlled by the UNDI.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_CONFIG_INFO *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->pci.BusType = PXE_BUSTYPE_USB;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command resets the network adapter and initializes UNDI using
>> + the parameters supplied in the CPB.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_INITIALIZE *Cpb;
>> + PXE_DB_INITIALIZE *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
>> + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
>> +
>> + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
>> + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
>> + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
>> + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
>> + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
>> + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
>> + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
>> + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
>> + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
>> +
>> + Cdb->StatCode = Initialize (Cdb, Nic);
>> +
>> + Db->MemoryUsed = MEMORY_REQUIRE;
>> + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
>> + Db->TxBufSize = Nic->PxeInit.TxBufSize;
>> + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
>> + Db->RxBufSize = Nic->PxeInit.RxBufSize;
>> +
>> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
>> + Nic->CanTransmit = FALSE;
>> +
>> + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
>> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
>> + Nic->CableDetect = 0;
>> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
>> + Nic->CableDetect = 1;
>> + }
>> +
>> + if (Nic->CableDetect == 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
>> + }
>> + }
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Initialize Network interface controller data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> + @retval Status A value of Pxe statcode.
>> +
>> +**/
>> +UINT16
>> +Initialize (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + UINTN Status;
>> + UINT32 Index;
>> + EFI_STATUS EfiStatus;
>> +
>> + Status = MapIt (
>> + Nic,
>> + Nic->PxeInit.MemoryAddr,
>> + Nic->PxeInit.MemoryLength,
>> + TO_AND_FROM_DEVICE,
>> + (UINT64)(UINTN)&Nic->MappedAddr
>> + );
>> +
>> + if (Status != 0) {
>> + return (UINT16)Status;
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
>> + }
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Nic->BroadcastNodeAddress[Index] = 0xFF;
>> + }
>> +
>> + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = 0;
>> + Nic->PermNodeAddress[Index] = 0;
>> + Nic->BroadcastNodeAddress[Index] = 0;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthInitialize != NULL) {
>> + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
>> + if (EFI_ERROR (EfiStatus)) {
>> + return PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + return (UINT16)Status;
>> +}
>> +
>> +/**
>> + This command resets the network adapter and reinitializes the UNDI
>> + with the same parameters provided in the Initialize command.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
>> + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
>> + Nic->InterrupOpFlag = 0;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Shutdown command resets the network adapter and leaves it in a
>> + safe state for another driver to initialize.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + Nic->CanTransmit = FALSE;
>> +
>> + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Interrupt Enables command can be used to read and/or change
>> + the current external interrupt enable settings.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiInterruptEnable (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and change receive filters and,
>> + if supported, read and change the multicast MAC address filter list.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + UINT16 NewFilter;
>> + PXE_DB_RECEIVE_FILTERS *Db;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>> +
>> + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
>> + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
>> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
>> + if ((Cdb->DBsize != 0)) {
>> + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
>> + CopyMem (Db, &Nic->McastList, Nic->McastCount);
>> + }
>> + }
>> +
>> + break;
>> +
>> + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
>> + if (NewFilter == 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if (Cdb->CPBsize != 0) {
>> + if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
>> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
>> + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
>> + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
>> + if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
>> + ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if ((Cdb->CPBsize == 0)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
>> + break;
>> +
>> + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
>> + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + break;
>> +
>> + default:
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + }
>> +
>> + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Set PXE receive filter.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] SetFilter PXE receive filter
>> + @param[in] CpbAddr Command Parameter Block Address
>> + @param[in] CpbSize Command Parameter Block Size
>> +
>> +**/
>> +UINT16
>> +SetFilter (
>> + IN NIC_DATA *Nic,
>> + IN UINT16 SetFilter,
>> + IN UINT64 CpbAddr,
>> + IN UINT32 CpbSize
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 *McastList;
>> + UINT8 Count;
>> + UINT8 Index1;
>> + UINT8 Index2;
>> + PXE_CPB_RECEIVE_FILTERS *Cpb;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> +
>> + Count = 0;
>> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
>> +
>> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
>> + Nic->RxFilter = (UINT8)SetFilter;
>> +
>> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
>> + if (Cpb != NULL) {
>> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
>> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
>> + }
>> +
>> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + } else {
>> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Cpb != NULL) {
>> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
>> + for (Index2 = 0; Index2 < 6; Index2++) {
>> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
>> + }
>> + }
>> + }
>> +
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
>> + if (Cpb != NULL) {
>> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
>> + }
>> +
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + FreePool (McastList);
>> + }
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + This command is used to get current station and broadcast MAC addresses
>> + and, if supported, to change the current station MAC address.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStationAddress (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_STATION_ADDRESS *Cpb;
>> + PXE_DB_STATION_ADDRESS *Db;
>> + UINT16 Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
>> + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
>> + }
>> + }
>> + }
>> +
>> + if (Cdb->CPBaddr != 0) {
>> + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
>> + }
>> + }
>> +
>> + if (Cdb->DBaddr != 0) {
>> + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
>> + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
>> + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
>> + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
>> + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and clear the NIC traffic statistics.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiStatistics (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
>> + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Return data for DB data.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] DbAddr Data Block Address.
>> + @param[in] DbSize Data Block Size.
>> +
>> +**/
>> +UINT16
>> +Statistics (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 DbAddr,
>> + IN UINT16 DbSize
>> + )
>> +{
>> + PXE_DB_STATISTICS *DbStatistic;
>> + EFI_STATUS Status;
>> +
>> + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
>> +
>> + if (DbSize == 0) {
>> + return PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + DbStatistic->Supported = 0x802;
>> + DbStatistic->Data[0x01] = Nic->RxFrame;
>> + DbStatistic->Data[0x0B] = Nic->TxFrame;
>> +
>> + if (Nic->UsbEth->UsbEthStatistics != NULL) {
>> + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
>> +
>> + @param[in, out] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiMcastIp2Mac (
>> + IN OUT PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
>> + PXE_DB_MCAST_IP_TO_MAC *Db;
>> + UINT8 *Tmp;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
>> + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + return;
>> + }
>> +
>> + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
>> +
>> + if ((Tmp[0] & 0xF0) != 0xE0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
>> + }
>> +
>> + Db->MAC[0] = 0x01;
>> + Db->MAC[1] = 0x00;
>> + Db->MAC[2] = 0x5E;
>> + Db->MAC[3] = Tmp[1] & 0x7F;
>> + Db->MAC[4] = Tmp[2];
>> + Db->MAC[5] = Tmp[3];
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to read and write (if supported by NIC H/W)
>> + nonvolatile storage on the NIC.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiNvData (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command returns the current interrupt status and/or the
>> + transmitted buffer addresses and the current media status.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_DB_GET_STATUS *Db;
>> + PXE_DB_GET_STATUS TmpGetStatus;
>> + UINT16 NumEntries;
>> + UINTN Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
>> + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + TmpGetStatus.RxFrameLen = 0;
>> + TmpGetStatus.reserved = 0;
>> + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
>> +
>> + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
>> + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
>> + } else {
>> + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
>> + if (Cdb->DBsize == 0) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + NumEntries = Cdb->DBsize - sizeof (UINT64);
>> + Cdb->DBsize = sizeof (UINT32) * 2;
>> +
>> + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
>> + if (Nic->TxBufferCount > 0) {
>> + Nic->TxBufferCount--;
>> + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
>> + }
>> + }
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
>> + if (Nic->ReceiveStatus != 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
>> + }
>> + }
>> +
>> + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
>> + Nic->CableDetect = 0;
>> + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
>> + Nic->CableDetect = 1;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
>> + if (Nic->CableDetect == 0) {
>> + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + This command is used to fill the media header(s) in transmit packet(s).
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiFillHeader (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + PXE_CPB_FILL_HEADER *CpbFillHeader;
>> + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
>> + EthernetHeader *MacHeader;
>> + UINTN Index;
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + return;
>> + }
>> +
>> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
>> + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
>> +
>> + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + MacHeader = (EthernetHeader *)(UINTN)CpbFill->FragDesc[0].FragAddr;
>> + MacHeader->Protocol = CpbFill->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
>> + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
>> + }
>> + } else {
>> + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
>> +
>> + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader->MediaHeader;
>> + MacHeader->Protocol = CpbFillHeader->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
>> + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
>> + }
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + The Transmit command is used to place a packet into the transmit queue.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
>> + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
>> + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + return;
>> + }
>> +
>> + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +}
>> +
>> +/**
>> + Use USB Ethernet Protocol Bulk out command to transmit data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> + @param[in] CpbAddr Command Parameter Block Address.
>> + @param[in] OpFlags Operation Flags.
>> +
>> +**/
>> +UINT16
>> +Transmit (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN UINT16 OpFlags
>> + )
>> +{
>> + EFI_STATUS Status;
>> + PXE_CPB_TRANSMIT *Cpb;
>> + UINT64 BulkOutData;
>> + UINTN DataLength;
>> + UINTN TransmitLength;
>> + UINTN Map;
>> + UINT32 Counter;
>> + UINT16 StatCode;
>> +
>> + BulkOutData = 0;
>> + Counter = 0;
>> + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
>> +
>> + if (Nic->CanTransmit) {
>> + return PXE_STATCODE_BUSY;
>> + }
>> +
>> + Nic->CanTransmit = TRUE;
>> +
>> + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + Map = MapIt (
>> + Nic,
>> + Cpb->FrameAddr,
>> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
>> + TO_DEVICE,
>> + (UINT64)(UINTN)&BulkOutData
>> + );
>> +
>> + if (Map != 0) {
>> + Nic->CanTransmit = FALSE;
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
>> + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
>> + Nic->TxBufferCount++;
>> + }
>> +
>> + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
>> +
>> + while (1) {
>> + if (Counter >= 3) {
>> + StatCode = PXE_STATCODE_BUSY;
>> + break;
>> + }
>> +
>> + TransmitLength = DataLength;
>> +
>> + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
>> + if (EFI_ERROR (Status)) {
>> + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + if (Status == EFI_INVALID_PARAMETER) {
>> + StatCode = PXE_STATCODE_INVALID_PARAMETER;
>> + break;
>> + }
>> +
>> + if (Status == EFI_DEVICE_ERROR) {
>> + StatCode = PXE_STATCODE_DEVICE_FAILURE;
>> + break;
>> + }
>> +
>> + if (!EFI_ERROR (Status)) {
>> + Nic->TxFrame++;
>> + StatCode = PXE_STATCODE_SUCCESS;
>> + break;
>> + }
>> +
>> + Counter++;
>> + }
>> +
>> + UnMapIt (
>> + Nic,
>> + Cpb->FrameAddr,
>> + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
>> + TO_DEVICE,
>> + BulkOutData
>> + );
>> +
>> + Nic->CanTransmit = FALSE;
>> +
>> + return StatCode;
>> +}
>> +
>> +/**
>> + When the network adapter has received a frame, this command is used
>> + to copy the frame into driver/application storage.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> +**/
>> +VOID
>> +UndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
>> + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
>> + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
>> + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
>> + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
>> + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
>> + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
>> + {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
>> + return;
>> + } else {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
>> + Cdb->StatCode = PXE_STATCODE_SUCCESS;
>> + }
>> +
>> + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
>> + return;
>> + }
>> +
>> + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
>> + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +
>> + return;
>> + }
>> +
>> + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
>> +
>> + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
>> + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>> + }
>> +}
>> +
>> +/**
>> + Use USB Ethernet Protocol Bulk in command to receive data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in, out] Nic A pointer to the Network interface controller data.
>> + @param[in] CpbAddr Command Parameter Block Address.
>> + @param[in, out] DbAddr Data Block Address.
>> +
>> +**/
>> +UINT16
>> +Receive (
>> + IN PXE_CDB *Cdb,
>> + IN OUT NIC_DATA *Nic,
>> + IN UINT64 CpbAddr,
>> + IN OUT UINT64 DbAddr
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + PXE_FRAME_TYPE FrameType;
>> + PXE_CPB_RECEIVE *Cpb;
>> + PXE_DB_RECEIVE *Db;
>> + NIC_DEVICE *NicDevice;
>> + UINT8 *BulkInData;
>> + UINTN DataLength;
>> + EthernetHeader *Header;
>> + EFI_TPL OriginalTpl;
>> +
>> + FrameType = PXE_FRAME_TYPE_NONE;
>> + NicDevice = UNDI_DEV_FROM_NIC (Nic);
>> + BulkInData = NicDevice->ReceiveBuffer;
>> + DataLength = (UINTN)Nic->MaxSegmentSize;
>> + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
>> + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
>> +
>> + if (!BulkInData) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
>> + return PXE_STATCODE_NO_DATA;
>> + }
>> +
>> + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
>> + if (EFI_ERROR (Status)) {
>> + Nic->ReceiveStatus = 0;
>> + if (Nic->RateLimitingEnable == TRUE) {
>> + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
>> + if (Nic->RateLimitingCreditCount != 0) {
>> + Nic->RateLimitingCreditCount--;
>> + }
>> +
>> + gBS->RestoreTPL (OriginalTpl);
>> + }
>> +
>> + return PXE_STATCODE_NO_DATA;
>> + }
>> +
>> + Nic->RxFrame++;
>> +
>> + if (DataLength != 0) {
>> + if (DataLength > Cpb->BufferLen) {
>> + DataLength = (UINTN)Cpb->BufferLen;
>> + }
>> +
>> + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
>> +
>> + Header = (EthernetHeader *)BulkInData;
>> +
>> + Db->FrameLen = (UINT32)DataLength;
>> + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
>> + break;
>> + }
>> + }
>> +
>> + if (Index >= PXE_HWADDR_LEN_ETHER) {
>> + FrameType = PXE_FRAME_TYPE_UNICAST;
>> + } else {
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
>> + break;
>> + }
>> + }
>> +
>> + if (Index >= PXE_HWADDR_LEN_ETHER) {
>> + FrameType = PXE_FRAME_TYPE_BROADCAST;
>> + } else {
>> + if ((Header->DestAddr[0] & 1) == 1) {
>> + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
>> + } else {
>> + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
>> + }
>> + }
>> + }
>> +
>> + Db->Type = FrameType;
>> + Db->Protocol = Header->Protocol;
>> +
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + Db->SrcAddr[Index] = Header->SrcAddr[Index];
>> + Db->DestAddr[Index] = Header->DestAddr[Index];
>> + }
>> + }
>> +
>> + if (FrameType == PXE_FRAME_TYPE_NONE) {
>> + Nic->ReceiveStatus = 0;
>> + } else {
>> + Nic->ReceiveStatus = 1;
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Fill out PXE SW UNDI structure.
>> +
>> + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
>> +
>> +**/
>> +VOID
>> +PxeStructInit (
>> + OUT PXE_SW_UNDI *PxeSw
>> + )
>> +{
>> + PxeSw->Signature = PXE_ROMID_SIGNATURE;
>> + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
>> + PxeSw->Fudge = 0;
>> + PxeSw->IFcnt = 0;
>> + PxeSw->IFcntExt = 0;
>> + PxeSw->Rev = PXE_ROMID_REV;
>> + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
>> + PxeSw->MinorVer = PXE_ROMID_MINORVER;
>> + PxeSw->reserved1 = 0;
>> +
>> + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
>> + PXE_ROMID_IMP_FRAG_SUPPORTED |
>> + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
>> + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
>> + PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
>> + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
>> + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
>> + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
>> +
>> + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
>> + PxeSw->reserved2[0] = 0;
>> + PxeSw->reserved2[1] = 0;
>> + PxeSw->reserved2[2] = 0;
>> + PxeSw->BusCnt = 1;
>> + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
>> + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
>> +}
>> +
>> +/**
>> + Update NIC number.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
>> +
>> +**/
>> +VOID
>> +UpdateNicNum (
>> + IN NIC_DATA *Nic,
>> + IN OUT PXE_SW_UNDI *PxeSw
>> + )
>> +{
>> + UINT16 NicNum;
>> +
>> + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
>> +
>> + if (Nic == NULL) {
>> + if (NicNum > 0) {
>> + NicNum--;
>> + }
>> +
>> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
>> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
>> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
>> + return;
>> + }
>> +
>> + NicNum++;
>> +
>> + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
>> + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
>> + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
>> +}
>> +
>> +/**
>> + UNDI API table entry.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UndiApiEntry (
>> + IN UINT64 Cdb
>> + )
>> +{
>> + PXE_CDB *CdbPtr;
>> + NIC_DATA *Nic;
>> +
>> + if (Cdb == 0) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
>> + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
>> + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Map virtual memory address for DMA. This field can be set to
>> + zero if there is no mapping service.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] MemAddr Virtual address to be mapped.
>> + @param[in] Size Size of memory to be mapped.
>> + @param[in] Direction Direction of data flow for this memory's usage:
>> + cpu->device, device->cpu or both ways.
>> + @param[out] MappedAddr Pointer to return the mapped device address.
>> +
>> +**/
>> +UINTN
>> +MapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + OUT UINT64 MappedAddr
>> + )
>> +{
>> + UINT64 *PhyAddr;
>> +
>> + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
>> +
>> + if (Nic->PxeStart.Map_Mem == 0) {
>> + *PhyAddr = MemAddr;
>> + } else {
>> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
>> + Nic->PxeStart.Unique_ID,
>> + MemAddr,
>> + Size,
>> + Direction,
>> + MappedAddr
>> + );
>> + }
>> +
>> + return PXE_STATCODE_SUCCESS;
>> +}
>> +
>> +/**
>> + Un-map previously mapped virtual memory address. This field can be set
>> + to zero only if the Map_Mem() service is also set to zero.
>> +
>> + @param[in] Nic A pointer to the Network interface controller data.
>> + @param[in] MemAddr Virtual address to be mapped.
>> + @param[in] Size Size of memory to be mapped.
>> + @param[in] Direction Direction of data flow for this memory's usage:
>> + cpu->device, device->cpu or both ways.
>> + @param[in] MappedAddr Pointer to return the mapped device address.
>> +
>> +**/
>> +VOID
>> +UnMapIt (
>> + IN NIC_DATA *Nic,
>> + IN UINT64 MemAddr,
>> + IN UINT32 Size,
>> + IN UINT32 Direction,
>> + IN UINT64 MappedAddr
>> + )
>> +{
>> + if (Nic->PxeStart.UnMap_Mem != 0) {
>> + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
>> + Nic->PxeStart.Unique_ID,
>> + MemAddr,
>> + Size,
>> + Direction,
>> + MappedAddr
>> + );
>> + }
>> +
>> + return;
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> new file mode 100644
>> index 000000000000..b9ba170c135b
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> @@ -0,0 +1,172 @@
>> +/** @file
>> + This file contains code for USB RNDIS Driver Component
>> + Name definitions
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbRndisDriverNameTable[] = {
>> + {
>> + "eng;en",
>> + L"USB RNDIS Driver"
>> + },
>> + {
>> + NULL,
>> + NULL
>> + }
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
>> + UsbRndisComponentNameGetDriverName,
>> + UsbRndisComponentNameGetControllerName,
>> + "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
>> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNameGetDriverName,
>> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponentNameGetControllerName,
>> + "en"
>> +};
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Language 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[out] DriverName 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
>> +UsbRndisComponentNameGetDriverName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **DriverName
>> + )
>> +{
>> + return LookupUnicodeString2 (
>> + Language,
>> + This->SupportedLanguages,
>> + gUsbRndisDriverNameTable,
>> + DriverName,
>> + (BOOLEAN)(This == &gUsbRndisComponentName)
>> + );
>> +}
>> +
>> +/**
>> + 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
>> + EFI_COMPONENT_NAME_PROTOCOL instance.
>> + @param[in] Controller 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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 not a valid EFI_HANDLE.
>> + @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
>> +UsbRndisComponentNameGetControllerName (
>> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
>> + IN EFI_HANDLE Controller,
>> + IN EFI_HANDLE ChildHandle OPTIONAL,
>> + IN CHAR8 *Language,
>> + OUT CHAR16 **ControllerName
>> + )
>> +{
>> + return EFI_UNSUPPORTED;
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.c b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> new file mode 100644
>> index 000000000000..92830771e408
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> @@ -0,0 +1,886 @@
>> +/** @file
>> + This file contains code for USB Remote Network Driver
>> + Interface Spec. Driver Binding
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
>> + UsbRndisDriverSupported,
>> + UsbRndisDriverStart,
>> + UsbRndisDriverStop,
>> + USB_RNDIS_DRIVER_VERSION,
>> + NULL,
>> + NULL
>> +};
>> +
>> +/**
>> + Check if this interface is USB Rndis SubType
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis SubType.
>> + @retval FALSE Not USB Rndis SubType.
>> +
>> +**/
>> +BOOLEAN
>> +IsSupportedDevice (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check specific device/RNDIS and CDC-DATA
>> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x00))
>> + )
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if this interface is USB Rndis SubType but not CDC Data interface
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis SubType.
>> + @retval FALSE Not USB Rndis SubType.
>> +**/
>> +BOOLEAN
>> +IsRndisInterface (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for specific device/RNDIS and CDC-DATA
>> + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
>> + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x1))
>> + )
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if the USB RNDIS and USB CDC Data interfaces are from the same device.
>> +
>> + @param[in] UsbRndisDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[in] UsbCdcDataPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> +
>> + @retval EFI_SUCCESS Is the same device.
>> + @retval EFI_UNSUPPORTED Is not the same device.
>> +
>> +**/
>> +EFI_STATUS
>> +IsSameDevice (
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
>> + )
>> +{
>> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
>> + while (1) {
>> + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
>> + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
>> + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
>> + {
>> + return EFI_SUCCESS;
>> + } else {
>> + return EFI_UNSUPPORTED;
>> + }
>> + } else {
>> + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
>> + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
>> + }
>> + }
>> +
>> + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
>> +}
>> +
>> +/**
>> + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB CDC Data(UsbIo) installed.
>> + @retval FALSE USB CDC Data(UsbIo) did not installed.
>> +
>> +**/
>> +BOOLEAN
>> +IsUsbCdcData (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for CDC-DATA
>> + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0x0))
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Check if the USB Rndis(UsbIo) installed
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> +
>> + @retval TRUE USB Rndis(UsbIo) installed.
>> + @retval FALSE USB Rndis(UsbIo) did not installed.
>> +
>> +**/
>> +BOOLEAN
>> +IsUsbRndis (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return FALSE;
>> + }
>> +
>> + // Check for Rndis
>> + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
>> + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
>> + {
>> + return TRUE;
>> + }
>> +
>> + return FALSE;
>> +}
>> +
>> +/**
>> + Control comes here when a CDC device is found.Check if a RNDIS interface is already found for this device or not.
>> + For one device two USBIO will be installed each for CDC and RNDIS interface.
>> +
>> + @param[in] UsbEthPath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
>> + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE Data.
>> +
>> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
>> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
>> +
>> +**/
>> +EFI_STATUS
>> +UpdateRndisDevice (
>> + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
>> + OUT USB_RNDIS_DEVICE **UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + BOOLEAN IsRndisInterfaceFlag;
>> +
>> + IsRndisInterfaceFlag = FALSE;
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEdkIIUsbEthProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEthDevice
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
>> + if (IsRndisInterfaceFlag == FALSE) {
>> + continue;
>> + }
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + continue;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> +
>> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>> +
>> + if (!EFI_ERROR (Status)) {
>> + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>> + FreePool (HandleBuffer);
>> + return EFI_SUCCESS;
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> +
>> + For the given Rndis Device, find a matching CDC device already exists or not. If found update the handle
>> + and UsbIO protocol.
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE data.
>> +
>> +**/
>> +VOID
>> +FindMatchingCdcData (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = gBS->HandleProtocol (
>> + UsbRndisDevice->UsbRndisHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + return;
>> + }
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEfiUsbIoProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + if (IsUsbCdcData (UsbIo)) {
>> + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData interface found\n"));
>> +
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbCdcDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not found\n"));
>> + FreePool (HandleBuffer);
>> + return;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>> + if (!EFI_ERROR (Status)) {
>> + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
>> + UsbRndisDevice->UsbIoCdcData = UsbIo;
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + FreePool (HandleBuffer);
>> + return;
>> + }
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> +}
>> +
>> +/**
>> +
>> + For the given UsbIo CdcData, find a matching RNDIS device already exists or not.
>> +
>> + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC Data.
>> + @param[out] CdcUsbIo A pointer for retrieve the EFI_USB_IO_PROTOCOL instance.
>> + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS device.
>> +
>> + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC Data is found.
>> + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this CDC Data is not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FindMatchingRndisDev (
>> + IN EFI_HANDLE CdcHandle,
>> + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
>> + OUT EFI_HANDLE *RndisHandle
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Index;
>> + UINTN HandleCount;
>> + EFI_HANDLE *HandleBuffer;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = gBS->HandleProtocol (
>> + CdcHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbCdcDataPath
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->LocateHandleBuffer (
>> + ByProtocol,
>> + &gEfiUsbIoProtocolGuid,
>> + NULL,
>> + &HandleCount,
>> + &HandleBuffer
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < HandleCount; Index++) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if (IsUsbRndis (UsbIo)) {
>> + Status = gBS->HandleProtocol (
>> + HandleBuffer[Index],
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbRndisDataPath
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
>> + break;
>> + }
>> +
>> + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + *RndisHandle = HandleBuffer[Index];
>> + *CdcUsbIo = UsbIo;
>> + FreePool (HandleBuffer);
>> + return Status;
>> + }
>> + }
>> + } // End of For loop
>> +
>> + FreePool (HandleBuffer);
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> + USB Rndis Driver Binding Support.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to test.
>> + @param[in] 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
>> +UsbRndisDriverSupported (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + USB RNDIS Driver Binding Start.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> + @param[in] 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 EFI_OUT_OF_RESOURCES The driver could not install successfully due to a lack of resources.
>> + @retval other This driver does not support this device
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisDriverStart (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
>> + EFI_HANDLE RndisHandle;
>> +
>> + RndisHandle = ControllerHandle;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + (VOID **)&UsbEthPath,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_BY_DRIVER
>> + );
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiDevicePathProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + // Controls come here for RNDIS and CDC. If it is CDC, check whether RNDIS is present on the same controller or not.
>> + if (IsUsbCdcData (UsbIo)) {
>> + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
>> +
>> + // Find the parent RNDIS and update the UsbIo for the CDC device
>> + Status = UpdateRndisDevice (
>> + UsbEthPath,
>> + &UsbRndisDevice
>> + );
>> +
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
>> + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
>> + UsbRndisDevice->UsbIoCdcData = UsbIo;
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + return Status;
>> + } else {
>> + // Check if RnDis exist
>> + Status = FindMatchingRndisDev (
>> + ControllerHandle,
>> + &UsbIo,
>> + &RndisHandle
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return Status;
>> + }
>> + }
>> + }
>> +
>> + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
>> +
>> + if (!UsbRndisDevice) {
>> + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
>> +
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + Status = LoadAllDescriptor (
>> + UsbIo,
>> + &UsbRndisDevice->Config
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n", __FUNCTION__, Status));
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (
>> + UsbIo,
>> + &Interface
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
>> + UsbRndisDevice->NumOfInterface = Interface.InterfaceNumber;
>> + UsbRndisDevice->UsbRndisHandle = RndisHandle;
>> + UsbRndisDevice->UsbCdcDataHandle = 0;
>> + UsbRndisDevice->UsbIo = UsbIo;
>> + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
>> + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
>> + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
>> + UsbRndisDevice->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
>> + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
>> + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
>> + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
>> + UsbRndisDevice->UsbEth.UsbEthFunDescriptor = GetUsbRndisFunDescriptor;
>> + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter = SetUsbRndisMcastFilter;
>> + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter = SetUsbRndisPowerFilter;
>> + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter = GetUsbRndisPowerFilter;
>> + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter = SetUsbRndisPacketFilter;
>> + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
>> +
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart = RndisUndiStart;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop = RndisUndiStop;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo = RndisUndiGetInitInfo;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo = RndisUndiGetConfigInfo;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize = RndisUndiInitialize;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset = RndisUndiReset;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown = RndisUndiShutdown;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter = RndisUndiReceiveFilter;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus = RndisUndiGetStatus;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader = RndisDummyReturn;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
>> + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
>> +
>> + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
>> + UsbRndisDevice->MaxPacketsPerTransfer = 1;
>> + UsbRndisDevice->PacketAlignmentFactor = 0;
>> +
>> + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
>> +
>> + // This is a RNDIS interface. See whether CDC-DATA interface has already been connected or not
>> + FindMatchingCdcData (UsbRndisDevice);
>> +
>> + if (UsbRndisDevice->UsbIoCdcData) {
>> + Status = gBS->InstallProtocolInterface (
>> + &ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + EFI_NATIVE_INTERFACE,
>> + &(UsbRndisDevice->UsbEth)
>> + );
>> + if (EFI_ERROR (Status)) {
>> + gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> + return Status;
>> + }
>> +
>> + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
>> +
>> + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice->UsbRndisHandle));
>> + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice->UsbCdcDataHandle));
>> + return EFI_SUCCESS;
>> + }
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + CheckandStopRndisDevice
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to bind driver to.
>> +
>> + @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
>> +CheckandStopRndisDevice (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_IO_PROTOCOL *UsbIo;
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + (VOID **)&UsbIo,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if (IsUsbRndis (UsbIo)) {
>> + Status = gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
>> + return Status;
>> + }
>> +
>> + return EFI_UNSUPPORTED;
>> +}
>> +
>> +/**
>> + USB Rndis Driver Binding Stop.
>> +
>> + @param[in] This Protocol instance pointer.
>> + @param[in] ControllerHandle Handle of device to stop driver on
>> + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
>> + children is zero stop the entire bus driver.
>> + @param[in] 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
>> +UsbRndisDriverStop (
>> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> + IN EFI_HANDLE ControllerHandle,
>> + IN UINTN NumberOfChildren,
>> + IN EFI_HANDLE *ChildHandleBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n", ControllerHandle));
>> +
>> + Status = gBS->OpenProtocol (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + (VOID **)&UsbEthProtocol,
>> + This->DriverBindingHandle,
>> + ControllerHandle,
>> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> + );
>> + if (EFI_ERROR (Status)) {
>> + Status = CheckandStopRndisDevice (This, ControllerHandle);
>> + return Status;
>> + }
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
>> +
>> + Status = gBS->CloseProtocol (
>> + UsbRndisDevice->UsbCdcDataHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + UsbRndisDevice->UsbCdcDataHandle
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n", __FUNCTION__, Status));
>> + }
>> +
>> + Status = gBS->UninstallProtocolInterface (
>> + ControllerHandle,
>> + &gEdkIIUsbEthProtocolGuid,
>> + UsbEthProtocol
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Status = gBS->CloseProtocol (
>> + ControllerHandle,
>> + &gEfiUsbIoProtocolGuid,
>> + This->DriverBindingHandle,
>> + ControllerHandle
>> + );
>> +
>> + FreePool (UsbRndisDevice->Config);
>> + FreePool (UsbRndisDevice);
>> +
>> + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
>> + return Status;
>> +}
>> +
>> +/**
>> + Entrypoint of RNDIS Driver.
>> +
>> + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
>> + Protocols together with Component Name Protocols.
>> +
>> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
>> + @param[in] SystemTable A pointer to the EFI System Table.
>> +
>> + @retval EFI_SUCCESS The entry point is executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisEntry (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
>> + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
>> +
>> + return gBS->InstallMultipleProtocolInterfaces (
>> + &gUsbRndisDriverBinding.DriverBindingHandle,
>> + &gEfiDriverBindingProtocolGuid,
>> + &gUsbRndisDriverBinding,
>> + &gEfiComponentName2ProtocolGuid,
>> + &gUsbRndisComponentName2,
>> + NULL
>> + );
>> +}
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> new file mode 100644
>> index 000000000000..e3fe737cdef1
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> @@ -0,0 +1,1718 @@
>> +/** @file
>> + This file contains code for USB Ethernet descriptor
>> + and specific requests implement.
>> +
>> + Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include "UsbRndis.h"
>> +
>> +UINT16 gStopBulkInCnt = 0;
>> +UINT16 gBlockBulkInCnt = 0;
>> +
>> +/**
>> + Load All of device descriptor.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> + @param[out] ConfigDesc A pointer to the configuration descriptor.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_OUT_OF_RESOURCES The request could not be completed because the
>> + buffer specified by DescriptorLength and Descriptor
>> + is not large enough to hold the result of the request.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error. The transfer
>> + status is returned in Status.
>> +**/
>> +EFI_STATUS
>> +LoadAllDescriptor (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 TransStatus;
>> + EFI_USB_CONFIG_DESCRIPTOR Tmp;
>> +
>> + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = gBS->AllocatePool (
>> + EfiBootServicesData,
>> + Tmp.TotalLength,
>> + (VOID **)ConfigDesc
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = UsbGetDescriptor (
>> + UsbIo,
>> + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1), // zero based
>> + 0,
>> + Tmp.TotalLength,
>> + *ConfigDesc,
>> + &TransStatus
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Returns pointer to the next descriptor for the pack of USB descriptors
>> + located in continues memory segment
>> +
>> + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
>> + @param[in, out] Offset A pointer to the sum of descriptor length.
>> +
>> + @retval TRUE The request executed successfully.
>> + @retval FALSE No next descriptor.
>> +
>> +**/
>> +BOOLEAN
>> +NextDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
>> + IN OUT UINTN *Offset
>> + )
>> +{
>> + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
>> + return FALSE;
>> + }
>> +
>> + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
>> + return FALSE;
>> + }
>> +
>> + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
>> + if ( *Offset >= Desc->TotalLength ) {
>> + return FALSE;
>> + }
>> +
>> + return TRUE;
>> +}
>> +
>> +/**
>> + Read Function descriptor
>> +
>> + @param[in] Config A pointer to all of configuration.
>> + @param[in] FunDescriptorType USB CDC class descriptor SubType.
>> + @param[out] DataBuffer A pointer to the Data of corresponding to device capability.
>> +
>> + @retval EFI_SUCCESS The device capability descriptor was retrieved
>> + successfully.
>> + @retval EFI_UNSUPPORTED No supported.
>> + @retval EFI_NOT_FOUND The device capability descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +GetFunctionalDescriptor (
>> + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
>> + IN UINT8 FunDescriptorType,
>> + OUT VOID *DataBuffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Offset;
>> + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
>> +
>> + Status = EFI_NOT_FOUND;
>> +
>> + for (Offset = 0; NextDescriptor (Config, &Offset);) {
>> + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
>> + if (Interface->DescriptorType == CS_INTERFACE) {
>> + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
>> + switch (FunDescriptorType) {
>> + case HEADER_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
>> + sizeof (USB_HEADER_FUN_DESCRIPTOR)
>> + );
>> + return EFI_SUCCESS;
>> + case UNION_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_UNION_FUN_DESCRIPTOR *)Interface,
>> + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
>> + );
>> + return EFI_SUCCESS;
>> + case ETHERNET_FUN_DESCRIPTOR:
>> + CopyMem (
>> + DataBuffer,
>> + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
>> + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
>> + );
>> + return EFI_SUCCESS;
>> + default:
>> + Status = EFI_UNSUPPORTED;
>> + break;
>> + }
>> + }
>> + }
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
>> +
>> + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
>> + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> +
>> +**/
>> +VOID
>> +GetEndpoint (
>> + IN EFI_USB_IO_PROTOCOL *UsbIo,
>> + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 Index;
>> + UINT32 Result;
>> + EFI_USB_INTERFACE_DESCRIPTOR Interface;
>> + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + if (Interface.NumEndpoints == 0 ) {
>> + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> + }
>> +
>> + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
>> + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __FUNCTION__, Status));
>> + return;
>> + }
>> +
>> + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
>> + case USB_ENDPOINT_BULK:
>> + if (Endpoint.EndpointAddress & BIT7) {
>> + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
>> + } else {
>> + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
>> + }
>> +
>> + break;
>> + case USB_ENDPOINT_INTERRUPT:
>> + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
>> + break;
>> + }
>> + }
>> +}
>> +
>> +/**
>> + Async USB transfer callback routine.
>> +
>> + @param[in] Data Data received or sent via the USB Asynchronous Transfer, if the
>> + transfer completed successfully.
>> + @param[in] DataLength The length of Data received or sent via the Asynchronous
>> + Transfer, if transfer successfully completes.
>> + @param[in] Context Data passed from UsbAsyncInterruptTransfer() request.
>> + @param[in] Status Indicates the result of the asynchronous transfer.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer request has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +InterruptCallback (
>> + IN VOID *Data,
>> + IN UINTN DataLength,
>> + IN VOID *Context,
>> + IN UINT32 Status
>> + )
>> +{
>> + if ((Data == NULL) || (Context == NULL)) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
>> + CopyMem (
>> + (EFI_USB_DEVICE_REQUEST *)Context,
>> + (EFI_USB_DEVICE_REQUEST *)Data,
>> + sizeof (EFI_USB_DEVICE_REQUEST)
>> + );
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is used to manage a USB device with an interrupt transfer pipe.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted to USB controller. If
>> + FALSE, the interrupt transfer is deleted from the device's interrupt
>> + transfer queue.
>> + @param[in] PollingInterval Indicates the periodic rate, in milliseconds, that the transfer is to be
>> + executed.This parameter is required when IsNewTransfer is TRUE. The
>> + value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
>> + The units are in milliseconds.
>> + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST data.
>> +
>> + @retval EFI_SUCCESS The asynchronous USB transfer request transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbRndisInterrupt (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN BOOLEAN IsNewTransfer,
>> + IN UINTN PollingInterval,
>> + IN EFI_USB_DEVICE_REQUEST *Requst
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + UINTN DataLength;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> + DataLength = 0;
>> +
>> + if (IsNewTransfer == TRUE) {
>> + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + IsNewTransfer,
>> + PollingInterval,
>> + DataLength,
>> + InterruptCallback,
>> + Requst
>> + );
>> +
>> + if (Status == EFI_INVALID_PARAMETER) {
>> + // Because of Stacked AsyncInterrupt request are not supported
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + 0,
>> + 0,
>> + 0,
>> + NULL,
>> + NULL
>> + );
>> + }
>> + } else {
>> + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + IsNewTransfer,
>> + 0,
>> + 0,
>> + NULL,
>> + NULL
>> + );
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function is used to read USB interrupt transfer before the response RNDIS message.
>> +
>> + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
>> +
>> + @retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
>> + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ReadRndisResponseInterrupt (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 Data[2];
>> + UINT32 UsbStatus;
>> + UINTN DataLength;
>> +
>> + DataLength = 8;
>> +
>> + ZeroMem (Data, sizeof (Data));
>> +
>> + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
>> + UsbRndisDevice->UsbIo,
>> + UsbRndisDevice->InterrupEndpoint,
>> + &Data,
>> + &DataLength,
>> + 0x20,
>> + &UsbStatus
>> + );
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet Mac Address.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] MacAddress A pointer to the caller allocated USB Ethernet Mac Address.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbEthMacAddress (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT EFI_MAC_ADDRESS *MacAddress
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
>> + CHAR16 *Data;
>> + CHAR16 *DataPtr;
>> + CHAR16 TmpStr[1];
>> + UINT8 Index;
>> + UINT8 Hi;
>> + UINT8 Low;
>> +
>> + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
>> + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
>> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
>> +
>> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
>> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
>> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
>> +
>> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
>> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
>> +
>> + Status = RndisControlMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
>> + }
>> +
>> + UsbRndisDevice->RequestId++;
>> + return Status;
>> + }
>> +
>> + // If it is not support the OID_802_3_CURRENT_ADDRESS.
>> + // To check USB Ethernet functional Descriptor
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
>> + UsbRndisDevice->UsbIo,
>> + 0x409, // English-US Language ID
>> + UsbEthDescriptor.MacAddress,
>> + &Data
>> + );
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
>> + return Status;
>> + }
>> +
>> + DataPtr = Data;
>> + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
>> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
>> + DataPtr++;
>> + Hi = (UINT8)StrHexToUintn (TmpStr);
>> + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
>> + DataPtr++;
>> + Low = (UINT8)StrHexToUintn (TmpStr);
>> + MacAddress->Addr[Index] = (Hi << 4) | Low;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet Bulk transfer data size.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] BulkSize A pointer to the Bulk transfer data size.
>> +
>> + @retval EFI_SUCCESS The bulk transfer data size was retrieved successfully.
>> + @retval other Failed to retrieve the bulk transfer data size.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +UsbEthBulkSize (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT UINTN *BulkSize
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
>> + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
>> + ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
>> +
>> + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
>> + RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
>> + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
>> +
>> + RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
>> + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
>> +
>> + Status = RndisControlMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
>> + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
>> + );
>> + if (!EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
>> + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
>> + UsbRndisDevice->RequestId++;
>> + return Status;
>> + }
>> +
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Header functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Header Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Header Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbHeaderFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbHeaderFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + HEADER_FUN_DESCRIPTOR,
>> + UsbHeaderFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Union functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated USB Union Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Union Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Union Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbUnionFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbUnionFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + UNION_FUN_DESCRIPTOR,
>> + UsbUnionFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + Retrieves the USB Ethernet functional Descriptor.
>> +
>> + This function get the Mac Address, Ethernet statistics, maximum segment size,
>> + number of multicast filters, and number of pattern filters from Ethernet
>> + functional Descriptor.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[out] UsbEthFunDescriptor A pointer to the caller allocated USB Ethernet Functional Descriptor.
>> +
>> + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was retrieved successfully.
>> + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
>> + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor was not found.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisFunDescriptor (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + if (UsbEthFunDescriptor == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Status = GetFunctionalDescriptor (
>> + UsbRndisDevice->Config,
>> + ETHERNET_FUN_DESCRIPTOR,
>> + UsbEthFunDescriptor
>> + );
>> + return Status;
>> +}
>> +
>> +/**
>> + This request sets the Ethernet device multicast filters as specified in the
>> + sequential list of 48 bit Ethernet multicast addresses.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] McastAddr A pointer to the value of the multicast addresses.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisMcastFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN VOID *McastAddr
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
>> + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = Value * 6;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + McastAddr,
>> + Request.Length,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> + This request sets up the specified Ethernet power management pattern filter as
>> + described in the data structure.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Number of filters.
>> + @param[in] Length Size of the power management pattern filter data.
>> + @param[in] PatternFilter A pointer to the power management pattern filter structure.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + IN UINT16 Length,
>> + IN VOID *PatternFilter
>> + )
>> +{
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
>> + Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = Length;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + PatternFilter,
>> + Length,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> + This request retrieves the status of the specified Ethernet power management
>> + pattern filter from the device.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value The filter number.
>> + @param[out] PatternActive A pointer to the pattern active boolean.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetUsbRndisPowerFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value,
>> + OUT BOOLEAN *PatternActive
>> + )
>> +{
>> + EFI_USB_DEVICE_REQUEST Request;
>> + UINT32 TransStatus;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
>> + Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
>> + Request.Value = Value;
>> + Request.Index = UsbRndisDevice->NumOfInterface;
>> + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
>> +
>> + return UsbRndisDevice->UsbIo->UsbControlTransfer (
>> + UsbRndisDevice->UsbIo,
>> + &Request,
>> + EfiUsbDataIn,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + PatternActive,
>> + USB_ETH_POWER_FILTER_LENGTH,
>> + &TransStatus
>> + );
>> +}
>> +
>> +/**
>> +
>> + Converts PXE filter settings to RNDIS values
>> +
>> + @param[in] Value PXE filter data.
>> + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
>> +
>> +**/
>> +VOID
>> +ConvertFilter (
>> + IN UINT16 Value,
>> + OUT UINT16 *CdcFilter
>> + )
>> +{
>> + UINT32 Index;
>> + UINT32 Count;
>> + static struct BIT_MAP Table[] = {
>> + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
>> + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
>> + };
>> +
>> + Count = sizeof (Table)/sizeof (Table[0]);
>> +
>> + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
>> + if (Table[Index].Src & Value) {
>> + *CdcFilter |= Table[Index].Dst;
>> + }
>> + }
>> +}
>> +
>> +/**
>> +
>> + Updates Filter settings on the device.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_STATUS
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceiveFilter (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT8 *McastList;
>> + UINT8 Count;
>> + UINT8 Index1;
>> + UINT8 Index2;
>> + UINT64 CpbAddr;
>> + UINT32 CpbSize;
>> + UINT16 SetFilter;
>> + PXE_CPB_RECEIVE_FILTERS *Cpb;
>> + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
>> +
>> + Count = 0;
>> + CpbAddr = Cdb->CPBaddr;
>> + CpbSize = Cdb->CPBsize;
>> + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>> + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
>> +
>> + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
>> + Nic->RxFilter = (UINT8)SetFilter;
>> +
>> + if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
>> + if (Cpb != NULL) {
>> + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
>> + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
>> + } else {
>> + Nic->McastCount = 0;
>> + }
>> +
>> + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
>> + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
>> + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + } else {
>> + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
>> + if (EFI_ERROR (Status)) {
>> + return PXE_STATCODE_INVALID_PARAMETER;
>> + }
>> +
>> + if (Cpb != NULL) {
>> + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
>> + for (Index2 = 0; Index2 < 6; Index2++) {
>> + McastList[Count++] = Cpb->MCastList[Index1][Index2];
>> + }
>> + }
>> + }
>> +
>> + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
>> + if (Cpb != NULL) {
>> + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
>> + }
>> +
>> + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
>> + FreePool (McastList);
>> + }
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This request is used to configure device Ethernet packet filter settings.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] Value Packet Filter Bitmap.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +SetUsbRndisPacketFilter (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 Value
>> + )
>> +{
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This request is used to retrieve a statistic based on the feature selector.
>> +
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] FeatureSelector Value of the feature selector.
>> + @param[out] Statistic A pointer to the 32 bit unsigned integer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_TIMEOUT A timeout occurred executing the request.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +GetRndisStatistic (
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN UINT16 FeatureSelector,
>> + OUT VOID *Statistic
>> + )
>> +{
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiStart is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStart (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
>> +
>> + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
>> + Status = RndisUndiReset (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + RndisUndiReset (Cdb, Nic);
>> + }
>> +
>> + Status = RndisUndiInitialize (Cdb, Nic);
>> + if (EFI_ERROR (Status)) {
>> + RndisUndiInitialize (Cdb, Nic);
>> + }
>> +
>> + RndisUndiShutdown (Cdb, Nic);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when Undistop is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiStop (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiGetInitInfo is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetInitInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + PXE_DB_GET_INIT_INFO *Db;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
>> +
>> + UsbEthDevice = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>> +
>> + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
>> +
>> + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
>> + // Limit Max MTU size to 1500 bytes as RNDIS spec.
>> + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
>> + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when RndisUndiGetConfigInfo is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetConfigInfo (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiInitialize is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_UNSUPPORTED Not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiInitialize (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
>> + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
>> + ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
>> +
>> + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
>> + RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
>> + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
>> + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
>> + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
>> + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
>> +
>> + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
>> + RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
>> +
>> + UsbRndisDevice->RequestId++;
>> +
>> + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
>> + return Status;
>> + }
>> +
>> + // Only Wired Medium is supported
>> + if (RndisInitMsgCmplt.Medium) {
>> + return EFI_UNSUPPORTED;
>> + }
>> +
>> + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
>> + UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
>> + UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
>> + UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
>> +
>> + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
>> + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
>> + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
>> + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function is called when UndiReset is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_DEVICE_ERROR The request failed due to a device error.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReset (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_RESET_MSG RndisResetMsg;
>> + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
>> + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
>> +
>> + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
>> + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
>> +
>> + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
>> + RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
>> +
>> + UsbRndisDevice->RequestId = 1; // Let's start with 1
>> +
>> + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function is called when UndiShutdown is invoked.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiShutdown (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_HALT_MSG RndisHltMsg;
>> + EFI_STATUS Status;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
>> +
>> + UsbEthDriver = Nic->UsbEth;
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>> +
>> + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
>> +
>> + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
>> + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
>> +
>> + Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
>> +
>> + if (Status == EFI_DEVICE_ERROR) {
>> + Status = EFI_SUCCESS;
>> + }
>> +
>> + UsbRndisDevice->RequestId = 1;
>> + return Status;
>> +}
>> +
>> +/**
>> + Update the Media connection.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiGetStatus (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Transmit the data after appending RNDIS header.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] DataLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiTransmit (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN VOID *BulkOutData,
>> + IN OUT UINTN *DataLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
>> + UINTN TransferLength;
>> +
>> + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> +
>> + RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
>> + if (RndisPacketMsg == NULL) {
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
>> + RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
>> + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
>> + RndisPacketMsg->DataLength = (UINT32)*DataLength;
>> +
>> + CopyMem (
>> + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
>> + BulkOutData,
>> + *DataLength
>> + );
>> +
>> + TransferLength = RndisPacketMsg->MessageLength;
>> +
>> + Status = RndisTransmitDataMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
>> + &TransferLength
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
>> +
>> + FreePool (RndisPacketMsg);
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Receives and removes RNDIS header and returns the raw data.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
>> + @param[in, out] BulkInData A pointer to the buffer of data that will be transmitted to USB
>> + device or received from USB device.
>> + @param[in, out] DataLength A pointer to the PacketLength.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
>> + @retval EFI_NOT_FOUND No buffer was found in the list.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisUndiReceive (
>> + IN PXE_CDB *Cdb,
>> + IN EDKII_USB_ETHERNET_PROTOCOL *This,
>> + IN OUT VOID *BulkInData,
>> + IN OUT UINTN *DataLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + USB_RNDIS_DEVICE *UsbRndisDevice;
>> + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
>> + UINTN TransferLength;
>> + VOID *Buffer;
>> + PACKET_LIST *HeadPacket;
>> + PACKET_LIST *PacketList;
>> +
>> + // Check if there is any outstanding packet to receive
>> + // The buffer allocated has a linked List followed by the packet.
>> +
>> + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>> + Buffer = NULL;
>> + HeadPacket = NULL;
>> +
>> + while (1) {
>> + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
>> + if (Buffer == NULL) {
>> + return EFI_OUT_OF_RESOURCES;
>> + }
>> +
>> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
>> + PacketList = (PACKET_LIST *)Buffer;
>> + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
>> + // Save the original address for freeing it up
>> + PacketList->OrgBuffer = (UINT8 *)Buffer;
>> + TransferLength = UsbRndisDevice->MaxTransferSize;
>> +
>> + Status = RndisReceiveDataMsg (
>> + UsbRndisDevice,
>> + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
>> + &TransferLength
>> + );
>> +
>> + if (EFI_ERROR (Status) || (TransferLength == 0)) {
>> + FreePool (Buffer);
>> + break;
>> + }
>> +
>> + // Collect all the RNDIS packet in Linked list.
>> + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> + (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
>> + (TransferLength >= RndisPacketMsg->MessageLength))
>> + {
>> + // Insert Packet
>> + PacketList->RemainingLength = TransferLength;
>> + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
>> + } else {
>> + FreePool (Buffer);
>> + }
>> + }
>> +
>> + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
>> + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
>> +
>> + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
>> +
>> + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
>> +
>> + // Check whether the packet is valid RNDIS packet.
>> + if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> + (RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
>> + (HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
>> + {
>> + if (*DataLength >= RndisPacketMsg->DataLength) {
>> + CopyMem (
>> + BulkInData,
>> + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
>> + RndisPacketMsg->DataLength
>> + );
>> +
>> + *DataLength = RndisPacketMsg->DataLength;
>> +
>> + HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
>> + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
>> +
>> + return EFI_SUCCESS;
>> + } else {
>> + *DataLength = RndisPacketMsg->DataLength;
>> + return EFI_BUFFER_TOO_SMALL;
>> + }
>> + }
>> +
>> + RemoveEntryList (&HeadPacket->PacketList);
>> + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
>> + }
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> + This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
>> + point to this function.
>> +
>> + @param[in] Cdb A pointer to the command descriptor block.
>> + @param[in] Nic A pointer to the Network interface controller data.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +RndisDummyReturn (
>> + IN PXE_CDB *Cdb,
>> + IN NIC_DATA *Nic
>> + )
>> +{
>> + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's control endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
>> + @param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
>> +
>> + @retval EFI_SUCCESS The bulk transfer has been successfully executed.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisControlMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
>> + )
>> +{
>> + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
>> + EFI_USB_DEVICE_REQUEST DevReq;
>> + UINT32 UsbStatus;
>> + EFI_STATUS Status;
>> + UINT32 SaveResponseType;
>> + UINT32 SaveResponseLength;
>> + UINT32 Index;
>> + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
>> +
>> + SaveResponseType = 0;
>> + SaveResponseLength = 0;
>> + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
>> +
>> + if (RndisMsgResponse) {
>> + SaveResponseType = RndisMsgResponse->MessageType;
>> + SaveResponseLength = RndisMsgResponse->MessageLength;
>> + }
>> +
>> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
>> + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
>> + DevReq.Value = 0;
>> + DevReq.Index = 0;
>> + DevReq.Length = (UINT16)RndisMsg->MessageLength;
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + Status = UsbIo->UsbControlTransfer (
>> + UsbIo,
>> + &DevReq,
>> + EfiUsbDataOut,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + RndisMsg,
>> + RndisMsg->MessageLength,
>> + &UsbStatus
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
>> +
>> + // Error or no response expected
>> + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
>> + return Status;
>> + }
>> +
>> + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
>> + ReadRndisResponseInterrupt (UsbRndisDevice);
>> + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
>> +
>> + DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
>> + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
>> + DevReq.Value = 0;
>> + DevReq.Index = 0;
>> + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
>> +
>> + Status = UsbIo->UsbControlTransfer (
>> + UsbIo,
>> + &DevReq,
>> + EfiUsbDataIn,
>> + USB_ETHERNET_TRANSFER_TIMEOUT,
>> + RndisMsgResponse,
>> + RndisMsgResponse->MessageLength,
>> + &UsbStatus
>> + );
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
>> +
>> + PrintRndisMsg (RndisMsgResponse);
>> +
>> + if (!EFI_ERROR (Status)) {
>> + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
>> + DEBUG ((DEBUG_INFO, "Retry the response\n"));
>> +
>> + RndisMsgResponse->MessageType = SaveResponseType;
>> + RndisMsgResponse->MessageLength = SaveResponseLength;
>> + continue;
>> + }
>> + }
>> +
>> + return Status;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
>> +
>> + return EFI_TIMEOUT;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's Data endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
>> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisTransmitDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + IN OUT UINTN *TransferLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 UsbStatus;
>> +
>> + if (UsbRndisDevice->BulkInEndpoint == 0) {
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + }
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>> + UsbRndisDevice->UsbIoCdcData,
>> + UsbRndisDevice->BulkOutEndpoint,
>> + RndisMsg,
>> + TransferLength,
>> + USB_TX_ETHERNET_BULK_TIMEOUT,
>> + &UsbStatus
>> + );
>> +
>> + if (Status == EFI_SUCCESS) {
>> + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + This function send the RNDIS command through the device's Data endpoint
>> +
>> + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
>> + @param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
>> + @param[in, out] TransferLength The length of the RndisMsg data to transfer.
>> +
>> + @retval EFI_SUCCESS The request executed successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +RndisReceiveDataMsg (
>> + IN USB_RNDIS_DEVICE *UsbRndisDevice,
>> + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
>> + IN OUT UINTN *TransferLength
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINT32 UsbStatus;
>> +
>> + UsbStatus = 0;
>> +
>> + if (UsbRndisDevice->BulkInEndpoint == 0) {
>> + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>> + }
>> +
>> + // Use gStopBulkInCnt to stop BulkIn command
>> + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
>> + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>> + UsbRndisDevice->UsbIoCdcData,
>> + UsbRndisDevice->BulkInEndpoint,
>> + RndisMsg,
>> + TransferLength,
>> + USB_RX_ETHERNET_BULK_TIMEOUT,
>> + &UsbStatus
>> + );
>> +
>> + if (!EFI_ERROR (Status)) {
>> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>> + } else {
>> + gStopBulkInCnt--;
>> + }
>> + } else {
>> + Status = EFI_TIMEOUT;
>> + *TransferLength = 0;
>> + gBlockBulkInCnt++;
>> + }
>> +
>> + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
>> + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>> + gBlockBulkInCnt = 0;
>> + }
>> +
>> + PrintRndisMsg (RndisMsg);
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Prints RNDIS Header and Data
>> +
>> + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
>> +
>> +**/
>> +VOID
>> +PrintRndisMsg (
>> + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
>> + )
>> +{
>> + UINTN Length;
>> + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
>> +
>> + Length = 0;
>> +
>> + switch (RndisMsg->MessageType) {
>> + case RNDIS_PACKET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
>> + break;
>> + case RNDIS_INITIALIZE_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
>> + break;
>> + case RNDIS_INITIALIZE_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
>> + break;
>> + case RNDIS_HLT_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_HALT_MSG);
>> + break;
>> + case RNDIS_QUERY_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
>> + break;
>> + case RNDIS_QUERY_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
>> + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
>> + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
>> + break;
>> + case RNDIS_SET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_SET_MSG);
>> + break;
>> + case RNDIS_SET_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
>> + break;
>> + case RNDIS_RESET_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_RESET_MSG);
>> + break;
>> + case RNDIS_RESET_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
>> + break;
>> + case RNDIS_INDICATE_STATUS_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
>> + break;
>> + case RNDIS_KEEPALIVE_MSG:
>> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
>> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
>> + break;
>> + case RNDIS_KEEPALIVE_CMPLT:
>> + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
>> + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
>> + }
>> +
>> + if (Length) {
>> + UINTN Index = 0;
>> + for ( ; Length; Length -= 4, Index++) {
>> + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
>> + if (((Index % 4) == 3) && (Index != 0)) {
>> + DEBUG ((DEBUG_INFO, "\n"));
>> + }
>> +
>> + if ((Length < 8) && (Length > 4)) {
>> + UINT32 Data32;
>> + Index++;
>> + Data32 = *((UINT32 *)RndisMsg + Index);
>> + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
>> + break;
>> + }
>> + }
>> +
>> + if (Index % 4) {
>> + DEBUG ((DEBUG_INFO, "\n"));
>> + }
>> + }
>> +}
>> diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
>> new file mode 100644
>> index 000000000000..cb70684f0bf1
>> --- /dev/null
>> +++ b/UsbNetworkPkg/ReadMe.md
>> @@ -0,0 +1,65 @@
>> +# UsbNetworkPkg
>> +
>> +This document is intend to provide package information, include the interface details.
>> +
>> +# INDEX
>> + * [Introduction](#introduction)
>> + * [Components](#components)
>> + * [[NetworkCommon]](#networkcommon)
>> + * [[UsbCdcEcm]](#usbcdcecm)
>> + * [[UsbCdcNcm]](#usbcdcncm)
>> + * [[UsbRndis]](#usbrndis)
>> +
>> +# Introduction
>> +UsbNetworkPkg provides network functions for USB LAN devices.
>> +
>> +# Components
>> +Below module is included in this package:<br>
>> +- NetworkCommon
>> +- UsbCdcEcm
>> +- UsbCdcNcm
>> +- UsbRndis
>> +
>> +## [NetworkCommon]
>> +Provides a LAN driver based on UEFI specification(UNDI). It supports USB communication class subclass devices and USB Rndis devices, depending on the UsbEthernetProtocol.
>> +
>> +## Required Components
>> +- NetworkPkg
>> +
>> +## [UsbCdcEcm]
>> +This driver provides a communication interface for USB Ethernet devices that follows the ECM protocol. The driver installs UsbEthernetProtocol with ECM functions which are consumed by the NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x06|0x00|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> +## [UsbCdcNcm]
>> +This driver provides a communication interface for USB Ethernet devices that follows the NCM protocol. The driver installs UsbEthernetProtocol with NCM functions which are consumed by the NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x0D|0x00|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> +## [UsbRndis]
>> +This driver provides a communication interface for USB Ethernet devices that follows the RNDIS protocol. The driver installs UsbEthernetProtocol with RNDIS functions which are consumed by the NetworkCommon driver.
>> +
>> +The driver is compatible with the following USB class codes:
>> +|Class Code|SubClass Code|Protocol Code|
>> +|:--------:|:-----------:|:-----------:|
>> +|0x02|0x02|0xFF|
>> +|0xEF|0x04|0x01|
>> +
>> +## Required Components
>> +- NetworkCommon
>> +- MdeModulePkg(USB bus driver)
>> +
>> diff --git a/UsbNetworkPkg/ReleaseNotes.md b/UsbNetworkPkg/ReleaseNotes.md
>> new file mode 100644
>> index 000000000000..f8ccccdb0830
>> --- /dev/null
>> +++ b/UsbNetworkPkg/ReleaseNotes.md
>> @@ -0,0 +1,11 @@
>> +# UsbNetworkPkg Release Notes<!-- omit in toc -->
>> +
>> +# Release History<!-- omit in toc -->
>> +- [1.00](#100)
>> +
>> +## 1.00
>> +
>> +**Release Date:** Mar 10, 2022
>> +
>> +**New Features**
>> +- UsbNetworkPkg first release.
>> --
>> 2.35.1.windows.2
>> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
> -The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.
^ permalink raw reply [flat|nested] 11+ messages in thread