From 5e400d22a0d19452eba56cd553ac692318d9dd80 Mon Sep 17 00:00:00 2001
From: Richard Ho <richardho@ami.com>
Date: Thu, 13 Jul 2023 14:18:44 +0800
Subject: [PATCH] MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm: Add USB Cdc ECM
 devices support

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: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
Acked-by: Hao A Wu <hao.a.wu@intel.com>
Reviewed-by: Rebecca Cran <rebecca@bsdio.com>
Reviewed-by: Tony Lo <tonylo@ami.com>
---
 .../Usb/UsbNetwork/UsbCdcEcm/ComponentName.c  | 170 ++++
 .../Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c  | 502 ++++++++++
 .../Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h  | 211 +++++
 .../Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf    |  42 +
 .../Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c | 880 ++++++++++++++++++
 5 files changed, 1805 insertions(+)
 create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c
 create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c
 create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h
 create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf
 create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c

diff --git a/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c
new file mode 100644
index 0000000000..e37eecf229
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c
new file mode 100644
index 0000000000..eb52d2af7a
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h
new file mode 100644
index 0000000000..1fd723e6fc
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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/UsbEthernetProtocol.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/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf
new file mode 100644
index 0000000000..02c56f8378
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = UsbEcmEntry
+
+[Sources]
+  UsbCdcEcm.c
+  UsbCdcEcm.h
+  UsbEcmFunction.c
+  ComponentName.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  UefiLib
+  DebugLib
+  UefiUsbLib
+  MemoryAllocationLib
+  BaseMemoryLib
+
+[Protocols]
+  gEfiUsbIoProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gEfiDriverBindingProtocolGuid
+  gEdkIIUsbEthProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c
new file mode 100644
index 0000000000..63003e07ff
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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) {
+    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", __func__, 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", __func__, 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
+                                );
+}