[edk2-devel] [PATCH] UsbNetworkPkg: add USB network devices support

Pedro Falcato pedro.falcato at gmail.com
Fri Aug 19 15:56:05 UTC 2022


Also, I forgot, but you should CC the EDK2 stewards (they're the ones that
are going to add the Reviewed-by:).

On Fri, Aug 19, 2022 at 4:54 PM Pedro Falcato <pedro.falcato at gmail.com>
wrote:

> Hi Richard,
>
> What license is this code under? "Subject to AMI licensing agreement."
> does not sound like a valid OSS license.
>
> Thanks,
> Pedro
>
> On Fri, Aug 19, 2022 at 10:32 AM RichardHo [何明忠] via groups.io <richardho=
> ami.com at groups.io> wrote:
>
>> UsbNetworkPkg provides network functions for USB ACM, USB NCM,
>> and USB RNDIS network device.
>>
>> Signed-off-by: Richard Ho <richardho at ami.com>
>> Reviewed-by: Tony Lo <tonylo at ami.com>
>> ---
>>  UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc    |    9 +
>>  .../Config/UsbNetworkPkgComponentsDxe.inc.dsc |   20 +
>>  .../Config/UsbNetworkPkgComponentsDxe.inc.fdf |   21 +
>>  .../Config/UsbNetworkPkgDefines.inc.dsc       |   23 +
>>  .../Include/Protocol/UsbEthernetProtocol.h    |  872 +++++++++
>>  UsbNetworkPkg/NetworkCommon/ComponentName.c   |  264 +++
>>  UsbNetworkPkg/NetworkCommon/DriverBinding.c   |  583 ++++++
>>  UsbNetworkPkg/NetworkCommon/DriverBinding.h   |  263 +++
>>  UsbNetworkPkg/NetworkCommon/NetworkCommon.inf |   43 +
>>  UsbNetworkPkg/NetworkCommon/PxeFunction.c     | 1734 +++++++++++++++++
>>  UsbNetworkPkg/ReadMe.md                       |   65 +
>>  UsbNetworkPkg/ReleaseNotes.md                 |   11 +
>>  UsbNetworkPkg/UsbCdcEcm/ComponentName.c       |  170 ++
>>  UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c           |  504 +++++
>>  UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h           |  211 ++
>>  UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf         |   41 +
>>  UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c      |  861 ++++++++
>>  UsbNetworkPkg/UsbCdcNcm/ComponentName.c       |  170 ++
>>  UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c           |  508 +++++
>>  UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h           |  245 +++
>>  UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf         |   41 +
>>  UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c      |  946 +++++++++
>>  UsbNetworkPkg/UsbNetworkPkg.dec               |   32 +
>>  UsbNetworkPkg/UsbRndis/ComponentName.c        |  172 ++
>>  UsbNetworkPkg/UsbRndis/UsbRndis.c             |  848 ++++++++
>>  UsbNetworkPkg/UsbRndis/UsbRndis.h             |  569 ++++++
>>  UsbNetworkPkg/UsbRndis/UsbRndis.inf           |   41 +
>>  UsbNetworkPkg/UsbRndis/UsbRndisFunction.c     | 1587 +++++++++++++++
>>  28 files changed, 10854 insertions(+)
>>  create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>>  create mode 100644
>> UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>>  create mode 100644
>> UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>>  create mode 100644 UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>>  create mode 100644 UsbNetworkPkg/Include/Protocol/UsbEthernetProtocol.h
>>  create mode 100644 UsbNetworkPkg/NetworkCommon/ComponentName.c
>>  create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.c
>>  create mode 100644 UsbNetworkPkg/NetworkCommon/DriverBinding.h
>>  create mode 100644 UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>>  create mode 100644 UsbNetworkPkg/NetworkCommon/PxeFunction.c
>>  create mode 100644 UsbNetworkPkg/ReadMe.md
>>  create mode 100644 UsbNetworkPkg/ReleaseNotes.md
>>  create mode 100644 UsbNetworkPkg/UsbCdcEcm/ComponentName.c
>>  create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
>>  create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
>>  create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>>  create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
>>  create mode 100644 UsbNetworkPkg/UsbCdcNcm/ComponentName.c
>>  create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
>>  create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
>>  create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>>  create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
>>  create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
>>  create mode 100644 UsbNetworkPkg/UsbRndis/ComponentName.c
>>  create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.c
>>  create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.h
>>  create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndis.inf
>>  create mode 100644 UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>>
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> b/UsbNetworkPkg/Config/UsbNetworkPkg.inc.dsc
>> new file mode 100644
>> index 0000000000..504680bc4b
>> --- /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) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +[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 0000000000..ae2727b68c
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.dsc
>> @@ -0,0 +1,20 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +  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/UsbNetworkPkgComponentsDxe.inc.fdf
>> b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> new file mode 100644
>> index 0000000000..6a611e359c
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgComponentsDxe.inc.fdf
>> @@ -0,0 +1,21 @@
>> +## @file
>> +# List of Core Components.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +  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
>> +
>> \ No newline at end of file
>> diff --git a/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> new file mode 100644
>> index 0000000000..ef663bf253
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Config/UsbNetworkPkgDefines.inc.dsc
>> @@ -0,0 +1,23 @@
>> +## @file
>> +# Global switches enable/disable project features.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +[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/Include/Protocol/UsbEthernetProtocol.h
>> b/UsbNetworkPkg/Include/Protocol/UsbEthernetProtocol.h
>> new file mode 100644
>> index 0000000000..d60e83f723
>> --- /dev/null
>> +++ b/UsbNetworkPkg/Include/Protocol/UsbEthernetProtocol.h
>> @@ -0,0 +1,872 @@
>> +/** @file
>>
>> +  Header file contains code for USB Ethernet Protocol
>>
>> +  definitions
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#ifndef _USB_ETHERNET_PROTOCOL_H
>>
>> +#define _USB_ETHERNET_PROTOCOL_H
>>
>> +
>>
>> +#define USB_ETHERNET_PROTOCOL_GUID \
>>
>> +    {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38,
>> 0x56, 0x43}}
>>
>> +
>>
>> +typedef struct _USB_ETHERNET_PROTOCOL 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_ETHRTNET_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;
>>
>> +  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;
>>
>> +  BOOLEAN                   CanReceive;
>>
>> +  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;
>>
>> +} NIC_DATA;
>>
>> +
>>
>> +#define NIC_DATA_SIGNATURE  SIGNATURE_32('n', 'i', 'c', 'd')
>>
>> +#define NIC_DATA_FROM_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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 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_PARAMETE  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 *USB_ETHERNET_RECEIVE)(
>>
>> +  IN     PXE_CDB               *Cdb,
>>
>> +  IN     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 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_PARAMETE  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 *USB_ETHERNET_TRANSMIT)(
>>
>> +  IN     PXE_CDB               *Cdb,
>>
>> +  IN     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 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 *USB_ETHERNET_INTERRUPT)(
>>
>> +  IN 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 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 *USB_GET_ETH_MAC_ADDRESS)(
>>
>> +  IN  USB_ETHERNET_PROTOCOL *This,
>>
>> +  OUT EFI_MAC_ADDRESS       *MacAddress
>>
>> +  );
>>
>> +
>>
>> +/**
>>
>> +  Retrieves the USB Ethernet Bulk transfer data size.
>>
>> +
>>
>> +  @param[in]  This          A pointer to the 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 *USB_ETH_MAX_BULK_SIZE)(
>>
>> +  IN  USB_ETHERNET_PROTOCOL *This,
>>
>> +  OUT UINTN                 *BulkSize
>>
>> +  );
>>
>> +
>>
>> +/**
>>
>> +  Retrieves the USB Header functional Descriptor.
>>
>> +
>>
>> +  @param[in]  This                   A pointer to the
>> 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 *USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
>>
>> +  IN USB_ETHERNET_PROTOCOL      *This,
>>
>> +  OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +/**
>>
>> +  Retrieves the USB Union functional Descriptor.
>>
>> +
>>
>> +  @param[in]  This                   A pointer to the
>> 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 *USB_UNION_FUNCTIONAL_DESCRIPTOR)(
>>
>> +  IN USB_ETHERNET_PROTOCOL     *This,
>>
>> +  OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +/**
>>
>> +  Retrieves the USB Ethernet functional Descriptor.
>>
>> +
>>
>> +  @param[in]  This                   A pointer to the
>> 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 *USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
>>
>> +  IN 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
>> 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 *USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
>>
>> +  IN 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
>> 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 *USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>>
>> +  IN 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
>> 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 *USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
>>
>> +  IN   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 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 *USB_ETHERNET_SET_ETH_PACKET_FILTER)(
>>
>> +  IN 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
>> 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 *USB_ETHERNET_GET_ETH_STATISTIC)(
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN  UINT16                 FeatureSelector,
>>
>> +  OUT VOID                   *Statistic
>>
>> +  );
>>
>> +
>>
>> +typedef struct {
>>
>> +  USB_ETHERNET_UNDI_GET_STATE           UsbEthUndiGetState;
>>
>> +  USB_ETHERNET_UNDI_START               UsbEthUndiStart;
>>
>> +  USB_ETHERNET_UNDI_STOP                UsbEthUndiStop;
>>
>> +  USB_ETHERNET_UNDI_GET_INIT_INFO       UsbEthUndiGetInitInfo;
>>
>> +  USB_ETHERNET_UNDI_GET_CONFIG_INFO     UsbEthUndiGetConfigInfo;
>>
>> +  USB_ETHERNET_UNDI_INITIALIZE          UsbEthUndiInitialize;
>>
>> +  USB_ETHERNET_UNDI_RESET               UsbEthUndiReset;
>>
>> +  USB_ETHERNET_UNDI_SHUTDOWN            UsbEthUndiShutdown;
>>
>> +  USB_ETHERNET_UNDI_INTERRUPT_ENABLE    UsbEthUndiInterruptEnable;
>>
>> +  USB_ETHERNET_UNDI_RECEIVE_FILTER      UsbEthUndiReceiveFilter;
>>
>> +  USB_ETHERNET_UNDI_STATION_ADDRESS     UsbEthUndiStationAddress;
>>
>> +  USB_ETHERNET_UNDI_STATISTICS          UsbEthUndiStatistics;
>>
>> +  USB_ETHERNET_UNDI_MCAST_IPTOMAC       UsbEthUndiMcastIp2Mac;
>>
>> +  USB_ETHERNET_UNDI_NV_DATA             UsbEthUndiNvData;
>>
>> +  USB_ETHERNET_UNDI_GET_STATUS          UsbEthUndiGetStatus;
>>
>> +  USB_ETHERNET_UNDI_FILL_HEADER         UsbEthUndiFillHeader;
>>
>> +  USB_ETHERNET_UNDI_TRANSMIT            UsbEthUndiTransmit;
>>
>> +  USB_ETHERNET_UNDI_RECEIVE             UsbEthUndiReceive;
>>
>> +} USB_ETHERNET_UNDI;
>>
>> +
>>
>> +// The USB_ETHERNET_PROTOCOL provides some basic USB Ethernet device
>> relevant
>>
>> +// descriptor and specific requests.
>>
>> +struct _USB_ETHERNET_PROTOCOL {
>>
>> +  USB_ETHERNET_UNDI                                   UsbEthUndi;
>>
>> +  // for calling the UNDI child functions
>>
>> +  USB_ETHERNET_INITIALIZE                             UsbEthInitialize;
>>
>> +  USB_ETHERNET_STATISTICS                             UsbEthStatistics;
>>
>> +  USB_ETHERNET_RECEIVE                                UsbEthReceive;
>>
>> +  USB_ETHERNET_TRANSMIT                               UsbEthTransmit;
>>
>> +  USB_ETHERNET_INTERRUPT                              UsbEthInterrupt;
>>
>> +  USB_GET_ETH_MAC_ADDRESS                             UsbEthMacAddress;
>>
>> +  USB_ETH_MAX_BULK_SIZE                               UsbEthMaxBulkSize;
>>
>> +  USB_HEADER_FUNCTIONAL_DESCRIPTOR
>> UsbHeaderFunDescriptor;
>>
>> +  USB_UNION_FUNCTIONAL_DESCRIPTOR
>>  UsbUnionFunDescriptor;
>>
>> +  USB_ETHERNET_FUNCTIONAL_DESCRIPTOR
>> UsbEthFunDescriptor;
>>
>> +  USB_ETHERNET_SET_ETH_MULTICAST_FILTERS
>> SetUsbEthMcastFilter;
>>
>> +  USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER
>> SetUsbEthPowerPatternFilter;
>>
>> +  USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER
>> GetUsbEthPoewrPatternFilter;
>>
>> +  USB_ETHERNET_SET_ETH_PACKET_FILTER
>> SetUsbEthPacketFilter;
>>
>> +  USB_ETHERNET_GET_ETH_STATISTIC                      GetUsbEthStatistic;
>>
>> +};
>>
>> +
>>
>> +#endif
>>
>> diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> new file mode 100644
>> index 0000000000..2697bf5083
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
>> @@ -0,0 +1,264 @@
>> +/** @file
>>
>> +  This file contains code for USB network common driver
>>
>> +  component name definitions
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#include "DriverBinding.h"
>>
>> +
>>
>> +extern EFI_DRIVER_BINDING_PROTOCOL  gNetworkCommonDriverBinding;
>>
>> +extern EFI_GUID                     gUsbEthProtocolGuid;
>>
>> +
>>
>> +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 = NULL;
>>
>> +  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,
>>
>> +             &gUsbEthProtocolGuid
>>
>> +             );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  //
>>
>> +  // Make sure this driver produced ChildHandle
>>
>> +  //
>>
>> +  Status = EfiTestChildHandle (
>>
>> +             Controller,
>>
>> +             ChildHandle,
>>
>> +             &gUsbEthProtocolGuid
>>
>> +             );
>>
>> +  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 0000000000..18b2daa7a8
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
>> @@ -0,0 +1,583 @@
>> +/** @file
>>
>> +  This file contains code for USB network binding driver
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#include "DriverBinding.h"
>>
>> +
>>
>> +PXE_SW_UNDI  *gPxe = NULL;
>>
>> +NIC_DEVICE   *gLanDeviceList[MAX_LAN_INTERFACE];
>>
>> +
>>
>> +EFI_GUID  gUsbEthProtocolGuid = USB_ETHERNET_PROTOCOL_GUID;
>>
>> +
>>
>> +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;
>>
>> +  USB_ETHERNET_PROTOCOL  *UsbEth;
>>
>> +
>>
>> +  Status = gBS->OpenProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  (VOID **)&UsbEth,
>>
>> +                  This->DriverBindingHandle,
>>
>> +                  ControllerHandle,
>>
>> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  gBS->CloseProtocol (
>>
>> +         ControllerHandle,
>>
>> +         &gUsbEthProtocolGuid,
>>
>> +         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;
>>
>> +  USB_ETHERNET_PROTOCOL     *UsbEth;
>>
>> +  EFI_MAC_ADDRESS           MacAddress;
>>
>> +  UINTN                     BulkDataSize;
>>
>> +  NIC_DEVICE                *NicDevice;
>>
>> +  UINT8                     *TmpPxePointer = NULL;
>>
>> +
>>
>> +  Status = gBS->OpenProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  (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,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           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,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE));
>>
>> +  if (!NicDevice) {
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gEfiDevicePathProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    return EFI_OUT_OF_RESOURCES;
>>
>> +  }
>>
>> +
>>
>> +  // for alignment adjustment
>>
>> +  if (gPxe == NULL) {
>>
>> +    TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
>>
>> +    if (!TmpPxePointer) {
>>
>> +      if (NicDevice != NULL) {
>>
>> +        gBS->FreePool (NicDevice);
>>
>> +      }
>>
>> +
>>
>> +      gBS->CloseProtocol (
>>
>> +             ControllerHandle,
>>
>> +             &gEfiDevicePathProtocolGuid,
>>
>> +             This->DriverBindingHandle,
>>
>> +             ControllerHandle
>>
>> +             );
>>
>> +      gBS->CloseProtocol (
>>
>> +             ControllerHandle,
>>
>> +             &gUsbEthProtocolGuid,
>>
>> +             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) {
>>
>> +          gBS->FreePool (NicDevice);
>>
>> +        }
>>
>> +
>>
>> +        gBS->CloseProtocol (
>>
>> +               ControllerHandle,
>>
>> +               &gEfiDevicePathProtocolGuid,
>>
>> +               This->DriverBindingHandle,
>>
>> +               ControllerHandle
>>
>> +               );
>>
>> +        gBS->CloseProtocol (
>>
>> +               ControllerHandle,
>>
>> +               &gUsbEthProtocolGuid,
>>
>> +               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;
>>
>> +
>>
>> +  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,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +
>>
>> +    if (TmpPxePointer != NULL) {
>>
>> +      gBS->FreePool (TmpPxePointer);
>>
>> +    }
>>
>> +
>>
>> +    if (NicDevice != NULL) {
>>
>> +      gBS->FreePool (NicDevice);
>>
>> +    }
>>
>> +
>>
>> +    return EFI_DEVICE_ERROR;
>>
>> +  }
>>
>> +
>>
>> +  Status = CreateMacDevicePath (
>>
>> +             &NicDevice->DevPath,
>>
>> +             UsbEthPath,
>>
>> +             &NicDevice->NicInfo
>>
>> +             );
>>
>> +
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    UpdateNicNum (NULL, gPxe);
>>
>> +    if (TmpPxePointer != NULL) {
>>
>> +      gBS->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;
>>
>> +
>>
>> +  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,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +
>>
>> +    if (TmpPxePointer != NULL) {
>>
>> +      gBS->FreePool (TmpPxePointer);
>>
>> +    }
>>
>> +
>>
>> +    if (NicDevice->DevPath != NULL) {
>>
>> +      gBS->FreePool (NicDevice->DevPath);
>>
>> +    }
>>
>> +
>>
>> +    if (NicDevice != NULL) {
>>
>> +      gBS->FreePool (NicDevice);
>>
>> +    }
>>
>> +
>>
>> +    return EFI_DEVICE_ERROR;
>>
>> +  }
>>
>> +
>>
>> +  Status = gBS->OpenProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  (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;
>>
>> +  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,
>>
>> +             &gUsbEthProtocolGuid,
>>
>> +             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;
>>
>> +    }
>>
>> +
>>
>> +    gBS->FreePool (NicDevice->DevPath);
>>
>> +    gBS->FreePool (NicDevice);
>>
>> +
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gEfiDevicePathProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           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,
>>
>> +           &gUsbEthProtocolGuid,
>>
>> +           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,
>>
>> +                      &gUsbEthProtocolGuid,
>>
>> +                      (VOID **)&UsbEth,
>>
>> +                      This->DriverBindingHandle,
>>
>> +                      ChildHandleBuffer[Index],
>>
>> +                      EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>>
>> +                      );
>>
>> +    } else {
>>
>> +      gBS->FreePool (NicDevice->DevPath);
>>
>> +      gBS->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;
>>
>> +
>>
>> +  Status = gBS->InstallMultipleProtocolInterfaces (
>>
>> +                  &gNetworkCommonDriverBinding.DriverBindingHandle,
>>
>> +                  &gEfiDriverBindingProtocolGuid,
>>
>> +                  &gNetworkCommonDriverBinding,
>>
>> +                  &gEfiComponentName2ProtocolGuid,
>>
>> +                  &gNetworkCommonComponentName2,
>>
>> +                  NULL
>>
>> +                  );
>>
>> +  return Status;
>>
>> +}
>>
>> diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> new file mode 100644
>> index 0000000000..223e034f2f
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
>> @@ -0,0 +1,263 @@
>> +/** @file
>>
>> +  Header file for for USB network common driver
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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/BaseMemoryLib.h>
>>
>> +#include <Library/UefiUsbLib.h>
>>
>> +#include <Protocol/UsbIo.h>
>>
>> +#include <Protocol/NetworkInterfaceIdentifier.h>
>>
>> +#include <Protocol/UsbEthernetProtocol.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;
>>
>> +} 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
>>
>> +  );
>>
>> +
>>
>> +VOID
>>
>> +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/NetworkCommon/NetworkCommon.inf
>> b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> new file mode 100644
>> index 0000000000..483df660f7
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
>> @@ -0,0 +1,43 @@
>> +## @file
>> +#   This is Usb Network Common driver for DXE phase.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +[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
>> +
>> +[Depex]
>> +  TRUE
>> diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> new file mode 100644
>> index 0000000000..d34b61a69f
>> --- /dev/null
>> +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
>> @@ -0,0 +1,1734 @@
>> +/** @file
>>
>> +  This file contains code for UNDI command based on UEFI specification.
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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
>>
>> +};
>>
>> +
>>
>> +/**
>>
>> +  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;
>>
>> +
>>
>> +  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;
>>
>> +  } 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_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;
>>
>> +  Nic->State              = PXE_STATFLAGS_GET_STATE_STARTED;
>>
>> +
>>
>> +  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) {
>>
>> +    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
>>
>> +    if (EFI_ERROR (Status)) {
>>
>> +      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>>
>> +    }
>>
>> +  }
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  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->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->CanReceive  = FALSE;
>>
>> +  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->CanReceive  = FALSE;
>>
>> +  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;
>>
>> +      }
>>
>> +
>>
>> +      Nic->CanReceive = TRUE;
>>
>> +      break;
>>
>> +
>>
>> +    default:
>>
>> +      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
>>
>> +      Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
>>
>> +  }
>>
>> +
>>
>> +  if (Nic->CanReceive) {
>>
>> +    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 = 0;
>>
>> +  UINT8                        Index1;
>>
>> +  UINT8                        Index2;
>>
>> +  PXE_CPB_RECEIVE_FILTERS      *Cpb = (PXE_CPB_RECEIVE_FILTERS
>> *)(UINTN)CpbAddr;
>>
>> +  USB_ETHERNET_FUN_DESCRIPTOR  UsbEthFunDescriptor;
>>
>> +
>>
>> +  // 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);
>>
>> +    }
>>
>> +
>>
>> +    if (Nic->CanReceive) {
>>
>> +      Nic->CanReceive = FALSE;
>>
>> +    }
>>
>> +
>>
>> +    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);
>>
>> +      gBS->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 = 0;
>>
>> +  UINTN             DataLength;
>>
>> +  UINTN             Map;
>>
>> +  UINT32            Counter = 0;
>>
>> +  UINT16            StatCode;
>>
>> +
>>
>> +  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;
>>
>> +    }
>>
>> +
>>
>> +    Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID
>> *)(UINTN)BulkOutData, &DataLength);
>>
>> +    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->CanReceive) {
>>
>> +    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;
>>
>> +  UINT16           StatCode  = PXE_STATCODE_NO_DATA;
>>
>> +  PXE_FRAME_TYPE   FrameType = PXE_FRAME_TYPE_NONE;
>>
>> +  PXE_CPB_RECEIVE  *Cpb;
>>
>> +  PXE_DB_RECEIVE   *Db;
>>
>> +  UINT8            *BulkInData;
>>
>> +  UINTN            DataLength = (UINTN)Nic->MaxSegmentSize;
>>
>> +  EthernetHeader   *Header;
>>
>> +
>>
>> +  Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
>>
>> +  Db  = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
>>
>> +
>>
>> +  Status = gBS->AllocatePool (EfiBootServicesData, DataLength, (VOID
>> **)&BulkInData);
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    return PXE_STATCODE_INVALID_PARAMETER;
>>
>> +  }
>>
>> +
>>
>> +  while (1) {
>>
>> +    Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID
>> *)BulkInData, &DataLength);
>>
>> +    if (EFI_ERROR (Status)) {
>>
>> +      break;
>>
>> +    }
>>
>> +
>>
>> +    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];
>>
>> +      }
>>
>> +
>>
>> +      StatCode = PXE_STATCODE_SUCCESS;
>>
>> +      break;
>>
>> +    }
>>
>> +  }
>>
>> +
>>
>> +  if (FrameType == PXE_FRAME_TYPE_NONE) {
>>
>> +    Nic->ReceiveStatus = 0;
>>
>> +  } else {
>>
>> +    Nic->ReceiveStatus = 1;
>>
>> +  }
>>
>> +
>>
>> +  gBS->FreePool (BulkInData);
>>
>> +
>>
>> +  return StatCode;
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  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.
>>
>> +
>>
>> +**/
>>
>> +VOID
>>
>> +UndiApiEntry (
>>
>> +  IN  UINT64  Cdb
>>
>> +  )
>>
>> +{
>>
>> +  PXE_CDB   *CdbPtr;
>>
>> +  NIC_DATA  *Nic;
>>
>> +
>>
>> +  if (Cdb == 0) {
>>
>> +    return;
>>
>> +  }
>>
>> +
>>
>> +  CdbPtr = (PXE_CDB *)(UINTN)Cdb;
>>
>> +  Nic    = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
>>
>> +  gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  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/ReadMe.md b/UsbNetworkPkg/ReadMe.md
>> new file mode 100644
>> index 0000000000..6dc0514ba7
>> --- /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 0000000000..03912e7788
>> --- /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.
>>
>> diff --git a/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
>> b/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
>> new file mode 100644
>> index 0000000000..39123994b2
>> --- /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) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +#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 0000000000..34f115f48d
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
>> @@ -0,0 +1,504 @@
>> +/** @file
>>
>> +  This file contains code for USB Ethernet Control Model
>>
>> +  Driver
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +#include "UsbCdcEcm.h"
>>
>> +
>>
>> +EFI_GUID  gUsbEthProtocolGuid = USB_ETHERNET_PROTOCOL_GUID;
>>
>> +
>>
>> +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 = NULL;
>>
>> +
>>
>> +  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));
>>
>> +        gBS->FreePool (HandleBuffer);
>>
>> +        return TRUE;
>>
>> +      }
>>
>> +    }
>>
>> +  }
>>
>> +
>>
>> +  gBS->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);
>>
>> +    }
>>
>> +  }
>>
>> +
>>
>> +  gBS->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               = UsbEthReceive;
>>
>> +  UsbEthDriver->UsbEth.UsbEthTransmit              = UsbEthTransmit;
>>
>> +  UsbEthDriver->UsbEth.UsbEthInterrupt             = UsbEthInterrupt;
>>
>> +  UsbEthDriver->UsbEth.UsbEthMacAddress            = GetUsbEthMacAddress;
>>
>> +  UsbEthDriver->UsbEth.UsbEthMaxBulkSize           = UsbEthBulkSize;
>>
>> +  UsbEthDriver->UsbEth.UsbHeaderFunDescriptor      =
>> GetUsbHeaderFunDescriptor;
>>
>> +  UsbEthDriver->UsbEth.UsbUnionFunDescriptor       =
>> GetUsbUnionFunDescriptor;
>>
>> +  UsbEthDriver->UsbEth.UsbEthFunDescriptor         =
>> GetUsbEthFunDescriptor;
>>
>> +  UsbEthDriver->UsbEth.SetUsbEthMcastFilter        =
>> SetUsbEthMcastFilter;
>>
>> +  UsbEthDriver->UsbEth.SetUsbEthPowerPatternFilter =
>> SetUsbEthPowerFilter;
>>
>> +  UsbEthDriver->UsbEth.GetUsbEthPoewrPatternFilter =
>> GetUsbEthPowerFilter;
>>
>> +  UsbEthDriver->UsbEth.SetUsbEthPacketFilter       =
>> SetUsbEthPacketFilter;
>>
>> +  UsbEthDriver->UsbEth.GetUsbEthStatistic          = GetUsbEthStatistic;
>>
>> +
>>
>> +  Status = gBS->InstallProtocolInterface (
>>
>> +                  &ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  EFI_NATIVE_INTERFACE,
>>
>> +                  &(UsbEthDriver->UsbEth)
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gEfiUsbIoProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    gBS->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;
>>
>> +  USB_ETHERNET_PROTOCOL  *UsbEthProtocol;
>>
>> +  USB_ETHERNET_DRIVER    *UsbEthDriver;
>>
>> +
>>
>> +  Status = gBS->OpenProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  (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,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  UsbEthProtocol
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  Status = gBS->CloseProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gEfiUsbIoProtocolGuid,
>>
>> +                  This->DriverBindingHandle,
>>
>> +                  ControllerHandle
>>
>> +                  );
>>
>> +  gBS->FreePool (UsbEthDriver->Config);
>>
>> +  gBS->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/UsbCdcEcm.h
>> b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
>> new file mode 100644
>> index 0000000000..52a818466e
>> --- /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) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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;
>>
>> +  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
>>
>> +UsbEthReceive (
>>
>> +  IN     PXE_CDB                *Cdb,
>>
>> +  IN     USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN OUT VOID                   *Packet,
>>
>> +  IN OUT UINTN                  *PacketLength
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthTransmit (
>>
>> +  IN      PXE_CDB                *Cdb,
>>
>> +  IN      USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN      VOID                   *Packet,
>>
>> +  IN OUT  UINTN                  *PacketLength
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthInterrupt (
>>
>> +  IN 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  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  OUT EFI_MAC_ADDRESS        *MacAddress
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthBulkSize (
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  OUT UINTN                  *BulkSize
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbHeaderFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL      *This,
>>
>> +  OUT USB_HEADER_FUN_DESCRIPTOR  *UsbHeaderFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbUnionFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL     *This,
>>
>> +  OUT USB_UNION_FUN_DESCRIPTOR  *UsbUnionFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbEthFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL        *This,
>>
>> +  OUT USB_ETHERNET_FUN_DESCRIPTOR  *UsbEthFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbEthMcastFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN VOID                   *McastAddr
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbEthPowerFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN UINT16                 Length,
>>
>> +  IN VOID                   *PatternFilter
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbEthPowerFilter (
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN  UINT16                 Value,
>>
>> +  OUT BOOLEAN                *PatternActive
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbEthPacketFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbEthStatistic (
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN  UINT16                 FeatureSelector,
>>
>> +  OUT VOID                   *Statistic
>>
>> +  );
>>
>> +
>>
>> +#endif
>>
>> diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> new file mode 100644
>> index 0000000000..ed031864c6
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
>> @@ -0,0 +1,41 @@
>> +## @file
>> +#   This is Usb Cdc Ecm driver for DXE phase.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +[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
>> +
>> +[Depex]
>> +  TRUE
>> diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
>> b/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
>> new file mode 100644
>> index 0000000000..175addddc6
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
>> @@ -0,0 +1,861 @@
>> +/** @file
>>
>> +  This file contains code for USB Ethernet descriptor
>>
>> +  and specific requests implement.
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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 = EFI_NOT_FOUND;
>>
>> +  UINTN                         Offset;
>>
>> +  EFI_USB_INTERFACE_DESCRIPTOR  *Interface;
>>
>> +
>>
>> +  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 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_PARAMETE  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
>>
>> +UsbEthReceive (
>>
>> +  IN     PXE_CDB                *Cdb,
>>
>> +  IN     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 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_PARAMETE  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
>>
>> +UsbEthTransmit (
>>
>> +  IN      PXE_CDB                *Cdb,
>>
>> +  IN      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 (((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 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
>>
>> +UsbEthInterrupt (
>>
>> +  IN 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 = 0;
>>
>> +
>>
>> +  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
>>
>> +  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 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  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);
>>
>> +  ASSERT_EFI_ERROR (Status);
>>
>> +
>>
>> +  Status = UsbEthDriver->UsbIo->UsbGetStringDescriptor (
>>
>> +                                  UsbEthDriver->UsbIo,
>>
>> +                                  0x409,                        //
>> English-US Language ID
>>
>> +                                  UsbEthDescriptor.MacAddress,
>>
>> +                                  &Data
>>
>> +                                  );
>>
>> +  ASSERT_EFI_ERROR (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 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  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
>> 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  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
>> 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  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.
>>
>> +
>>
>> +  @param[in]  This                   A pointer to the
>> 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  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
>> 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 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_ETHRTNET_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
>> 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 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_ETHRTNET_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
>> 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  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 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 USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value
>>
>> +  )
>>
>> +{
>>
>> +  EFI_USB_DEVICE_REQUEST  Request;
>>
>> +  UINT32                  TransStatus;
>>
>> +  USB_ETHERNET_DRIVER     *UsbEthDriver;
>>
>> +  UINT16                  CommandFilter = 0;
>>
>> +
>>
>> +  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
>>
>> +
>>
>> +  ConvertFilter (Value, &CommandFilter);
>>
>> +
>>
>> +  Request.RequestType = USB_ETHRTNET_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
>> 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  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
>>
>> +                                );
>>
>> +}
>>
>> diff --git a/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
>> b/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
>> new file mode 100644
>> index 0000000000..36792b89c5
>> --- /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) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +#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 0000000000..fc7cbd8132
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
>> @@ -0,0 +1,508 @@
>> +/** @file
>>
>> +  This file contains code for USB Network Control Model
>>
>> +  binding driver
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#include "UsbCdcNcm.h"
>>
>> +
>>
>> +EFI_GUID  gUsbEthProtocolGuid = USB_ETHERNET_PROTOCOL_GUID;
>>
>> +
>>
>> +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 = NULL;
>>
>> +
>>
>> +  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));
>>
>> +        gBS->FreePool (HandleBuffer);
>>
>> +        return TRUE;
>>
>> +      }
>>
>> +    }
>>
>> +  }
>>
>> +
>>
>> +  gBS->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);
>>
>> +    }
>>
>> +  }
>>
>> +
>>
>> +  gBS->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               = UsbEthReceive;
>>
>> +  UsbEthDriver->UsbEth.UsbEthTransmit              = UsbEthTransmit;
>>
>> +  UsbEthDriver->UsbEth.UsbEthInterrupt             = UsbEthInterrupt;
>>
>> +  UsbEthDriver->UsbEth.UsbEthMacAddress            = GetUsbEthMacAddress;
>>
>> +  UsbEthDriver->UsbEth.UsbEthMaxBulkSize           = UsbEthBulkSize;
>>
>> +  UsbEthDriver->UsbEth.UsbHeaderFunDescriptor      =
>> GetUsbHeaderFunDescriptor;
>>
>> +  UsbEthDriver->UsbEth.UsbUnionFunDescriptor       =
>> GetUsbUnionFunDescriptor;
>>
>> +  UsbEthDriver->UsbEth.UsbEthFunDescriptor         =
>> GetUsbEthFunDescriptor;
>>
>> +  UsbEthDriver->UsbEth.SetUsbEthMcastFilter        =
>> SetUsbEthMcastFilter;
>>
>> +  UsbEthDriver->UsbEth.SetUsbEthPowerPatternFilter =
>> SetUsbEthPowerFilter;
>>
>> +  UsbEthDriver->UsbEth.GetUsbEthPoewrPatternFilter =
>> GetUsbEthPowerFilter;
>>
>> +  UsbEthDriver->UsbEth.SetUsbEthPacketFilter       =
>> SetUsbEthPacketFilter;
>>
>> +  UsbEthDriver->UsbEth.GetUsbEthStatistic          = GetUsbEthStatistic;
>>
>> +
>>
>> +  UsbEthDriver->BulkBuffer = AllocateZeroPool (USB_NCM_MAX_NTB_SIZE);
>>
>> +
>>
>> +  Status = gBS->InstallProtocolInterface (
>>
>> +                  &ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  EFI_NATIVE_INTERFACE,
>>
>> +                  &(UsbEthDriver->UsbEth)
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gEfiUsbIoProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    gBS->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;
>>
>> +  USB_ETHERNET_PROTOCOL  *UsbEthProtocol;
>>
>> +  USB_ETHERNET_DRIVER    *UsbEthDriver;
>>
>> +
>>
>> +  Status = gBS->OpenProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  (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,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  UsbEthProtocol
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  Status = gBS->CloseProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gEfiUsbIoProtocolGuid,
>>
>> +                  This->DriverBindingHandle,
>>
>> +                  ControllerHandle
>>
>> +                  );
>>
>> +  gBS->FreePool (UsbEthDriver->Config);
>>
>> +  gBS->FreePool (UsbEthDriver->BulkBuffer);
>>
>> +  gBS->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/UsbCdcNcm.h
>> b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
>> new file mode 100644
>> index 0000000000..40b2671a1e
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
>> @@ -0,0 +1,245 @@
>> +/** @file
>>
>> +  Header file for USB Network Control Model driver
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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/UsbEthernetProtocol.h>
>>
>> +
>>
>> +typedef struct {
>>
>> +  UINTN                        Signature;
>>
>> +  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_ETH_FRAME_SIZE             0x5F2  // frome network stack snp
>>
>> +
>>
>> +// 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
>>
>> +UsbEthReceive (
>>
>> +  IN     PXE_CDB                *Cdb,
>>
>> +  IN     USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN OUT VOID                   *Packet,
>>
>> +  IN OUT UINTN                  *PacketLength
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthTransmit (
>>
>> +  IN      PXE_CDB                *Cdb,
>>
>> +  IN      USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN      VOID                   *Packet,
>>
>> +  IN OUT  UINTN                  *PacketLength
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthInterrupt (
>>
>> +  IN 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  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  OUT EFI_MAC_ADDRESS        *MacAddress
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthBulkSize (
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  OUT UINTN                  *BulkSize
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbHeaderFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL      *This,
>>
>> +  OUT USB_HEADER_FUN_DESCRIPTOR  *UsbHeaderFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbUnionFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL     *This,
>>
>> +  OUT USB_UNION_FUN_DESCRIPTOR  *UsbUnionFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbEthFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL        *This,
>>
>> +  OUT USB_ETHERNET_FUN_DESCRIPTOR  *UsbEthFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbEthMcastFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN VOID                   *McastAddr
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbEthPowerFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN UINT16                 Length,
>>
>> +  IN VOID                   *PatternFilter
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbEthPowerFilter (
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN  UINT16                 Value,
>>
>> +  OUT BOOLEAN                *PatternActive
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbEthPacketFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbEthStatistic (
>>
>> +  IN  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN  UINT16                 FeatureSelector,
>>
>> +  OUT VOID                   *Statistic
>>
>> +  );
>>
>> +
>>
>> +#endif
>>
>> diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> new file mode 100644
>> index 0000000000..cfbf9ad720
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
>> @@ -0,0 +1,41 @@
>> +## @file
>> +#   This is Usb Cdc Ncm driver for DXE phase.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +[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
>> +
>> +[Depex]
>> +  TRUE
>> \ No newline at end of file
>> diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
>> b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
>> new file mode 100644
>> index 0000000000..98bcf6d6d5
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
>> @@ -0,0 +1,946 @@
>> +/** @file
>>
>> +  This file contains code for USB Ethernet descriptor
>>
>> +  and specific requests implement.
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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 = EFI_NOT_FOUND;
>>
>> +  UINTN                         Offset;
>>
>> +  EFI_USB_INTERFACE_DESCRIPTOR  *Interface;
>>
>> +
>>
>> +  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 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_PARAMETE  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
>>
>> +UsbEthReceive (
>>
>> +  IN     PXE_CDB                *Cdb,
>>
>> +  IN     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                        BulkDataLenght;
>>
>> +  UINTN                        TotalLength = 0;
>>
>> +  USB_NCM_TRANSFER_HEADER_16   *Nth;
>>
>> +  USB_NCM_DATAGRAM_POINTER_16  *Ndp;
>>
>> +  USB_NCM_DATA_GRAM            *Datagram;
>>
>> +
>>
>> +  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
>>
>> +
>>
>> +  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);
>>
>> +    }
>>
>> +
>>
>> +    BulkDataLenght = USB_NCM_MAX_NTB_SIZE;
>>
>> +    SetMem (UsbEthDriver->BulkBuffer, BulkDataLenght, 0);
>>
>> +    UsbEthDriver->NowDatagram   = 0;
>>
>> +    UsbEthDriver->TotalDatagram = 0;
>>
>> +
>>
>> +    Status = UsbIo->UsbBulkTransfer (
>>
>> +                      UsbIo,
>>
>> +                      UsbEthDriver->BulkInEndpoint,
>>
>> +                      UsbEthDriver->BulkBuffer,
>>
>> +                      &BulkDataLenght,
>>
>> +                      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_ETH_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 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_PARAMETE  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
>>
>> +UsbEthTransmit (
>>
>> +  IN      PXE_CDB                *Cdb,
>>
>> +  IN      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
>>
>> +                    );
>>
>> +  gBS->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 (((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 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
>>
>> +UsbEthInterrupt (
>>
>> +  IN 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 = 0;
>>
>> +
>>
>> +  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
>>
>> +  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 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  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);
>>
>> +  ASSERT_EFI_ERROR (Status);
>>
>> +
>>
>> +  Status = UsbEthDriver->UsbIo->UsbGetStringDescriptor (
>>
>> +                                  UsbEthDriver->UsbIo,
>>
>> +                                  0x409,                        //
>> English-US Language ID
>>
>> +                                  UsbEthDescriptor.MacAddress,
>>
>> +                                  &Data
>>
>> +                                  );
>>
>> +  ASSERT_EFI_ERROR (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 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
>>
>> +UsbEthBulkSize (
>>
>> +  IN  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
>> 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  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
>> 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  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.
>>
>> +
>>
>> +  @param[in]  This                   A pointer to the
>> 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  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
>> 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 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_ETHRTNET_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
>> 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 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_ETHRTNET_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
>> 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  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 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 USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value
>>
>> +  )
>>
>> +{
>>
>> +  EFI_USB_DEVICE_REQUEST  Request;
>>
>> +  UINT32                  TransStatus;
>>
>> +  USB_ETHERNET_DRIVER     *UsbEthDriver;
>>
>> +  UINT16                  CommandFilter = 0;
>>
>> +
>>
>> +  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
>>
>> +
>>
>> +  ConvertFilter (Value, &CommandFilter);
>>
>> +
>>
>> +  Request.RequestType = USB_ETHRTNET_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
>> 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  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
>>
>> +                                );
>>
>> +}
>>
>> diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec
>> b/UsbNetworkPkg/UsbNetworkPkg.dec
>> new file mode 100644
>> index 0000000000..4ffafd99ed
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
>> @@ -0,0 +1,32 @@
>> +## @file
>> +#  This package defines Usb network specific interfaces and library
>> classes
>> +#  as well as configuration for standard edk2 packages.
>> +#
>> +#  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +#  Subject to AMI licensing agreement.
>> +##
>> +
>> +[Defines]
>> +  DEC_SPECIFICATION              = 0x00010005
>> +  PACKAGE_NAME                   = UsbNetworkPkg
>> +  PACKAGE_GUID                   = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
>> +  PACKAGE_VERSION                = 0.1
>> +
>> +[Includes]
>> +  Include
>> +
>> +[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
>> +
>> diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c
>> b/UsbNetworkPkg/UsbRndis/ComponentName.c
>> new file mode 100644
>> index 0000000000..6b7891afd9
>> --- /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) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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 0000000000..a75355825b
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
>> @@ -0,0 +1,848 @@
>> +/** @file
>>
>> +  This file contains code for USB Remote Network Driver
>>
>> +  Interface Spec. Driver Binding
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#include "UsbRndis.h"
>>
>> +
>>
>> +EFI_GUID                             gUsbEthProtocolGuid =
>> USB_ETHERNET_PROTOCOL_GUID;
>>
>> +extern EFI_COMPONENT_NAME2_PROTOCOL  gUsbRndisComponentName2;
>>
>> +
>>
>> +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 ((EFI_D_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 ((EFI_D_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;
>>
>> +  USB_ETHERNET_PROTOCOL     *UsbEthDevice;
>>
>> +  EFI_DEVICE_PATH_PROTOCOL  *UsbRndisDataPath;
>>
>> +  EFI_USB_IO_PROTOCOL       *UsbIo;
>>
>> +  BOOLEAN                   IsRndisInterfaceFlag = FALSE;
>>
>> +
>>
>> +  Status = gBS->LocateHandleBuffer (
>>
>> +                  ByProtocol,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  NULL,
>>
>> +                  &HandleCount,
>>
>> +                  &HandleBuffer
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  for (Index = 0; Index < HandleCount; Index++) {
>>
>> +    Status = gBS->HandleProtocol (
>>
>> +                    HandleBuffer[Index],
>>
>> +                    &gUsbEthProtocolGuid,
>>
>> +                    (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
>>
>> +                    );
>>
>> +    Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>>
>> +
>>
>> +    DEBUG ((EFI_D_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>>
>> +
>>
>> +    if (!EFI_ERROR (Status)) {
>>
>> +      *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
>>
>> +      gBS->FreePool (HandleBuffer);
>>
>> +      return EFI_SUCCESS;
>>
>> +    }
>>
>> +  }   // End of For loop
>>
>> +
>>
>> +  gBS->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 ((EFI_D_VERBOSE, "Rndis FindMatchingCdcData CDCData
>> interface found\n"));
>>
>> +
>>
>> +      Status = gBS->HandleProtocol (
>>
>> +                      HandleBuffer[Index],
>>
>> +                      &gEfiDevicePathProtocolGuid,
>>
>> +                      (VOID **)&UsbCdcDataPath
>>
>> +                      );
>>
>> +      if (EFI_ERROR (Status)) {
>>
>> +        DEBUG ((EFI_D_VERBOSE, "Rndis CDCData DevicePath not found\n"));
>>
>> +        gBS->FreePool (HandleBuffer);
>>
>> +        return;
>>
>> +      }
>>
>> +
>>
>> +      Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>>
>> +      DEBUG ((EFI_D_VERBOSE, "Rndis IsSameDevice %r\n", Status));
>>
>> +      if (!EFI_ERROR (Status)) {
>>
>> +        UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
>>
>> +        UsbRndisDevice->UsbIoCdcData     = UsbIo;
>>
>> +        GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>>
>> +        gBS->FreePool (HandleBuffer);
>>
>> +        return;
>>
>> +      }
>>
>> +    }
>>
>> +  }   // End of For loop
>>
>> +
>>
>> +  gBS->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
>>
>> +                    );
>>
>> +    ASSERT_EFI_ERROR (Status);
>>
>> +
>>
>> +    if (IsUsbRndis (UsbIo)) {
>>
>> +      Status = gBS->HandleProtocol (
>>
>> +                      HandleBuffer[Index],
>>
>> +                      &gEfiDevicePathProtocolGuid,
>>
>> +                      (VOID **)&UsbRndisDataPath
>>
>> +                      );
>>
>> +      if (EFI_ERROR (Status)) {
>>
>> +        DEBUG ((EFI_D_ERROR, "Usb Rndis DevicePath not found\n"));
>>
>> +        break;
>>
>> +      }
>>
>> +
>>
>> +      Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
>>
>> +
>>
>> +      if (!EFI_ERROR (Status)) {
>>
>> +        *RndisHandle = HandleBuffer[Index];
>>
>> +        *CdcUsbIo    = UsbIo;
>>
>> +        gBS->FreePool (HandleBuffer);
>>
>> +        return Status;
>>
>> +      }
>>
>> +    }
>>
>> +  }   // End of For loop
>>
>> +
>>
>> +  gBS->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 = NULL;
>>
>> +
>>
>> +  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 = 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
>>
>> +         );
>>
>> +
>>
>> +  DEBUG ((EFI_D_ERROR, "UsbRndisDriverStart %x\n", 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)) {
>>
>> +    // Find the parent RNDIS and update the UsbIo for the CDC device
>>
>> +    Status = UpdateRndisDevice (UsbEthPath, &UsbRndisDevice);
>>
>> +
>>
>> +    if (!EFI_ERROR (Status)) {
>>
>> +      DEBUG ((EFI_D_VERBOSE, "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 ((EFI_D_ERROR, "AllocateZeroPool Fail\n"));
>>
>> +
>>
>> +    gBS->CloseProtocol (
>>
>> +           ControllerHandle,
>>
>> +           &gEfiUsbIoProtocolGuid,
>>
>> +           This->DriverBindingHandle,
>>
>> +           ControllerHandle
>>
>> +           );
>>
>> +    return EFI_OUT_OF_RESOURCES;
>>
>> +  }
>>
>> +
>>
>> +  Status = LoadAllDescriptor (UsbIo, &UsbRndisDevice->Config);
>>
>> +  ASSERT_EFI_ERROR (Status);
>>
>> +
>>
>> +  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
>>
>> +  ASSERT_EFI_ERROR (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.GetUsbEthPoewrPatternFilter =
>> 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,
>>
>> +                    &gUsbEthProtocolGuid,
>>
>> +                    EFI_NATIVE_INTERFACE,
>>
>> +                    &(UsbRndisDevice->UsbEth)
>>
>> +                    );
>>
>> +    if (EFI_ERROR (Status)) {
>>
>> +      gBS->CloseProtocol (
>>
>> +             ControllerHandle,
>>
>> +             &gEfiUsbIoProtocolGuid,
>>
>> +             This->DriverBindingHandle,
>>
>> +             ControllerHandle
>>
>> +             );
>>
>> +
>>
>> +      gBS->FreePool (UsbRndisDevice->Config);
>>
>> +      gBS->FreePool (UsbRndisDevice);
>>
>> +      return Status;
>>
>> +    }
>>
>> +
>>
>> +    GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
>>
>> +
>>
>> +    DEBUG ((EFI_D_ERROR, "Rndis DeviceHandle %r\n",
>> UsbRndisDevice->UsbRndisHandle));
>>
>> +    DEBUG ((EFI_D_ERROR, "CDC DeviceHandle %r\n",
>> UsbRndisDevice->UsbCdcDataHandle));
>>
>> +    return EFI_SUCCESS;
>>
>> +  }
>>
>> +
>>
>> +  gBS->FreePool (UsbRndisDevice->Config);
>>
>> +  gBS->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 ((EFI_D_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;
>>
>> +  USB_ETHERNET_PROTOCOL  *UsbEthProtocol;
>>
>> +  USB_RNDIS_DEVICE       *UsbRndisDevice;
>>
>> +
>>
>> +  DEBUG ((EFI_D_ERROR, "UsbRndisDriverStop ControllerHandle %lx\n",
>> ControllerHandle));
>>
>> +
>>
>> +  Status = gBS->OpenProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  (VOID **)&UsbEthProtocol,
>>
>> +                  This->DriverBindingHandle,
>>
>> +                  ControllerHandle,
>>
>> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    Status = CheckandStopRndisDevice (This, ControllerHandle);
>>
>> +
>>
>> +    DEBUG ((EFI_D_ERROR, "CheckandStopRndisDevice %r\n", Status));
>>
>> +
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
>>
>> +
>>
>> +  Status = gBS->CloseProtocol (
>>
>> +                  UsbRndisDevice->UsbCdcDataHandle,
>>
>> +                  &gEfiUsbIoProtocolGuid,
>>
>> +                  This->DriverBindingHandle,
>>
>> +                  UsbRndisDevice->UsbCdcDataHandle
>>
>> +                  );
>>
>> +
>>
>> +  Status = gBS->UninstallProtocolInterface (
>>
>> +                  ControllerHandle,
>>
>> +                  &gUsbEthProtocolGuid,
>>
>> +                  UsbEthProtocol
>>
>> +                  );
>>
>> +  if (EFI_ERROR (Status)) {
>>
>> +    DEBUG ((EFI_D_ERROR, "EFI_ERROR %r\n", Status));
>>
>> +
>>
>> +    return Status;
>>
>> +  }
>>
>> +
>>
>> +  Status = gBS->CloseProtocol (
>>
>> +                  ControllerHandle,
>>
>> +                  &gEfiUsbIoProtocolGuid,
>>
>> +                  This->DriverBindingHandle,
>>
>> +                  ControllerHandle
>>
>> +                  );
>>
>> +
>>
>> +  gBS->FreePool (UsbRndisDevice->Config);
>>
>> +  gBS->FreePool (UsbRndisDevice);
>>
>> +
>>
>> +  DEBUG ((EFI_D_ERROR, "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/UsbRndis.h
>> b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> new file mode 100644
>> index 0000000000..680a9e67c9
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
>> @@ -0,0 +1,569 @@
>> +/** @file
>>
>> +  Header file for for USB Rndis driver
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#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/UsbEthernetProtocol.h>
>>
>> +
>>
>> +typedef struct _REMOTE_NDIS_MSG_HEADER REMOTE_NDIS_MSG_HEADER;
>>
>> +
>>
>> +typedef struct {
>>
>> +  UINT32                       Signature;
>>
>> +  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 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)
>>
>> +
>>
>> +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 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  USB_ETHERNET_PROTOCOL  *This,
>>
>> +  OUT EFI_MAC_ADDRESS        *MacAddress
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UsbEthBulkSize (
>>
>> +  IN  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      USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN      VOID                   *BulkOutData,
>>
>> +  IN OUT  UINTN                  *DataLength
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +RndisUndiReceive (
>>
>> +  IN     PXE_CDB                *Cdb,
>>
>> +  IN     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  USB_ETHERNET_PROTOCOL      *This,
>>
>> +  OUT USB_HEADER_FUN_DESCRIPTOR  *UsbHeaderFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbUnionFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL     *This,
>>
>> +  OUT USB_UNION_FUN_DESCRIPTOR  *UsbUnionFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbRndisFunDescriptor (
>>
>> +  IN  USB_ETHERNET_PROTOCOL        *This,
>>
>> +  OUT USB_ETHERNET_FUN_DESCRIPTOR  *UsbEthFunDescriptor
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbRndisMcastFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN VOID                   *McastAddr
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbRndisPowerFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN UINT16                 Length,
>>
>> +  IN VOID                   *PatternFilter
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetUsbRndisPowerFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN BOOLEAN                *PatternActive
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +SetUsbRndisPacketFilter (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +GetRndisStatistic (
>>
>> +  IN USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN UINT16                 Value,
>>
>> +  IN VOID                   *Statistic
>>
>> +  );
>>
>> +
>>
>> +EFI_STATUS
>>
>> +SendRndisSetMsg (
>>
>> +  IN  USB_RNDIS_DEVICE  *UsbRndisDevice,
>>
>> +  UINT8                 Oid,
>>
>> +  UINT32                Length,
>>
>> +  UINT8                 *Buf
>>
>> +  );
>>
>> +
>>
>> +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
>>
>> +
>>
>> +//
>>
>> +// 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 {
>>
>> +  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 {
>>
>> +  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;
>>
>> +} PACKET_LIST;
>>
>> +
>>
>> +#pragma pack()
>>
>> +
>>
>> +#endif
>>
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> new file mode 100644
>> index 0000000000..909b106059
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
>> @@ -0,0 +1,41 @@
>> +## @file
>> +#   This is Usb Rndis driver for DXE phase.
>> +#
>> +# Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>> +# Subject to AMI licensing agreement.
>> +##
>> +
>> +[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
>> +
>> +[Depex]
>> +  TRUE
>> diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> new file mode 100644
>> index 0000000000..a9b7b54f6a
>> --- /dev/null
>> +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
>> @@ -0,0 +1,1587 @@
>> +/** @file
>>
>> +  This file contains code for USB Ethernet descriptor
>>
>> +  and specific requests implement.
>>
>> +
>>
>> +  Copyright (c) 1985 - 2022, AMI. All rights reserved.<BR>
>>
>> +  Subject to AMI licensing agreement.
>>
>> +**/
>>
>> +
>>
>> +#include "UsbRndis.h"
>>
>> +
>>
>> +UINT16  StopBulkInCnt  = 0;
>>
>> +UINT16  BlockBulkInCnt = 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);
>>
>> +  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 = EFI_NOT_FOUND;
>>
>> +  UINTN                         Offset;
>>
>> +  EFI_USB_INTERFACE_DESCRIPTOR  *Interface;
>>
>> +
>>
>> +  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);
>>
>> +  ASSERT_EFI_ERROR (Status);
>>
>> +
>>
>> +  if (Interface.NumEndpoints == 0 ) {
>>
>> +    Status = UsbSetInterface (UsbIo, 1, 0, &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) {
>>
>> +          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 (((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 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 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 = 0;
>>
>> +
>>
>> +  UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>>
>> +
>>
>> +  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;
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  Retrieves the USB Ethernet Mac Address.
>>
>> +
>>
>> +  @param[in]  This          A pointer to the 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  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;
>>
>> +
>>
>> +  UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
>>
>> +
>>
>> +  Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
>>
>> +  ASSERT_EFI_ERROR (Status);
>>
>> +
>>
>> +  Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
>>
>> +                                    UsbRndisDevice->UsbIo,
>>
>> +                                    0x409,                       //
>> English-US Language ID
>>
>> +                                    UsbEthDescriptor.MacAddress,
>>
>> +                                    &Data
>>
>> +                                    );
>>
>> +  ASSERT_EFI_ERROR (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 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  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
>> 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  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
>> 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  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.
>>
>> +
>>
>> +  @param[in]  This                   A pointer to the
>> 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  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
>> 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 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_ETHRTNET_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
>> 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 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_ETHRTNET_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
>> 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  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 = 0;
>>
>> +  UINT8                        Index1;
>>
>> +  UINT8                        Index2;
>>
>> +  UINT64                       CpbAddr   = Cdb->CPBaddr;
>>
>> +  UINT32                       CpbSize   = Cdb->CPBsize;
>>
>> +  UINT16                       SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
>>
>> +  PXE_CPB_RECEIVE_FILTERS      *Cpb      = (PXE_CPB_RECEIVE_FILTERS
>> *)(UINTN)CpbAddr;
>>
>> +  USB_ETHERNET_FUN_DESCRIPTOR  UsbEthFunDescriptor;
>>
>> +
>>
>> +  // 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;
>>
>> +    }
>>
>> +
>>
>> +    if (Nic->CanReceive) {
>>
>> +      Nic->CanReceive = FALSE;
>>
>> +    }
>>
>> +
>>
>> +    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);
>>
>> +      gBS->FreePool (McastList);
>>
>> +    }
>>
>> +  }
>>
>> +
>>
>> +  return EFI_SUCCESS;
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  This request is used to configure device Ethernet packet filter
>> settings.
>>
>> +
>>
>> +  @param[in]  This              A pointer to the 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 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
>> 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  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
>>
>> +  )
>>
>> +{
>>
>> +  USB_ETHERNET_PROTOCOL  *UsbEthDevice   = Nic->UsbEth;
>>
>> +  USB_RNDIS_DEVICE       *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS
>> (UsbEthDevice);
>>
>> +  PXE_DB_GET_INIT_INFO   *Db;
>>
>> +
>>
>> +  DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
>>
>> +
>>
>> +  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
>>
>> +  )
>>
>> +{
>>
>> +  USB_ETHERNET_PROTOCOL         *UsbEthDriver   = Nic->UsbEth;
>>
>> +  USB_RNDIS_DEVICE              *UsbRndisDevice =
>> USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
>>
>> +  REMOTE_NDIS_INITIALIZE_MSG    RndisInitMsg;
>>
>> +  REMOTE_NDIS_INITIALIZE_CMPLT  RndisInitMsgCmplt;
>>
>> +  EFI_STATUS                    Status;
>>
>> +
>>
>> +  DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
>>
>> +
>>
>> +  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
>>
>> +  )
>>
>> +{
>>
>> +  USB_ETHERNET_PROTOCOL    *UsbEthDriver   = Nic->UsbEth;
>>
>> +  USB_RNDIS_DEVICE         *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS
>> (UsbEthDriver);
>>
>> +  REMOTE_NDIS_RESET_MSG    RndisResetMsg;
>>
>> +  REMOTE_NDIS_RESET_CMPLT  RndisResetCmplt;
>>
>> +  EFI_STATUS               Status;
>>
>> +
>>
>> +  DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
>>
>> +
>>
>> +  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
>>
>> +  )
>>
>> +{
>>
>> +  USB_ETHERNET_PROTOCOL  *UsbEthDriver   = Nic->UsbEth;
>>
>> +  USB_RNDIS_DEVICE       *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS
>> (UsbEthDriver);
>>
>> +  REMOTE_NDIS_HALT_MSG   RndisHltMsg;
>>
>> +  EFI_STATUS             Status;
>>
>> +
>>
>> +  DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
>>
>> +
>>
>> +  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 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      USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN      VOID                   *BulkOutData,
>>
>> +  IN OUT  UINTN                  *DataLength
>>
>> +  )
>>
>> +{
>>
>> +  EFI_STATUS              Status;
>>
>> +  USB_RNDIS_DEVICE        *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS
>> (This);
>>
>> +  REMOTE_NDIS_PACKET_MSG  *RndisPacketMsg;
>>
>> +  UINTN                   TransferLength;
>>
>> +
>>
>> +  DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n",
>> *DataLength));
>>
>> +
>>
>> +  Status = gBS->AllocatePool (EfiBootServicesData, sizeof
>> (REMOTE_NDIS_PACKET_MSG) + *DataLength, (VOID **)&RndisPacketMsg);
>>
>> +
>>
>> +  ZeroMem (RndisPacketMsg, sizeof (REMOTE_NDIS_PACKET_MSG));
>>
>> +
>>
>> +  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;
>>
>> +
>>
>> +  gBS->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));
>>
>> +
>>
>> +  gBS->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 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     USB_ETHERNET_PROTOCOL  *This,
>>
>> +  IN OUT VOID                   *BulkInData,
>>
>> +  IN OUT UINTN                  *DataLength
>>
>> +  )
>>
>> +{
>>
>> +  EFI_STATUS              Status;
>>
>> +  USB_RNDIS_DEVICE        *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS
>> (This);
>>
>> +  REMOTE_NDIS_PACKET_MSG  *RndisPacketMsg;
>>
>> +  UINTN                   TransferLength;
>>
>> +  VOID                    *Buffer;
>>
>> +  PACKET_LIST             *HeadPacket = NULL;
>>
>> +  PACKET_LIST             *PacketList;
>>
>> +  UINT32                  ReceivedBytes = 0;
>>
>> +
>>
>> +  // Check if there is any outstanding packet to receive
>>
>> +  // The buffer allocated has a linked List followed by the packet.
>>
>> +  do {
>>
>> +    Status         = gBS->AllocatePool (EfiBootServicesData, sizeof
>> (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) +
>> UsbRndisDevice->MaxTransferSize, &Buffer);
>>
>> +    RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) +
>> (UINT8 *)Buffer);
>>
>> +    PacketList     = (PACKET_LIST *)Buffer;
>>
>> +    // Save the original address for freeing it up
>>
>> +    PacketList->OrgBuffer       = Buffer;
>>
>> +    PacketList->RemainingLength = UsbRndisDevice->MaxTransferSize;
>>
>> +
>>
>> +    ZeroMem (RndisPacketMsg, sizeof (REMOTE_NDIS_PACKET_MSG));
>>
>> +    TransferLength = UsbRndisDevice->MaxTransferSize;
>>
>> +
>>
>> +    Status = RndisReceiveDataMsg (UsbRndisDevice,
>> (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg, &TransferLength);
>>
>> +
>>
>> +    if (EFI_ERROR (Status) || (TransferLength == 0)) {
>>
>> +      gBS->FreePool (Buffer);
>>
>> +      break;
>>
>> +    }
>>
>> +
>>
>> +    // Handle Multiple packets
>>
>> +    if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - 8)) {
>>
>> +      // Insert Packet
>>
>> +      InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
>>
>> +    }
>>
>> +  } while (1);
>>
>> +
>>
>> +  // Check if they linked list has any received buffer. If yes report it.
>>
>> +  if (IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
>>
>> +    return EFI_NOT_FOUND;
>>
>> +  }
>>
>> +
>>
>> +  HeadPacket = (PACKET_LIST *)GetFirstNode
>> (&UsbRndisDevice->ReceivePacketList);
>>
>> +
>>
>> +  RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)((UINT8 *)HeadPacket +
>> sizeof (PACKET_LIST));
>>
>> +
>>
>> +  PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
>>
>> +
>>
>> +  if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
>> (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - 8)) {
>>
>> +    if (*DataLength >= RndisPacketMsg->DataLength) {
>>
>> +      gBS->CopyMem (BulkInData, (UINT8 *)RndisPacketMsg +
>> RndisPacketMsg->DataOffset + 8, RndisPacketMsg->DataLength);
>>
>> +
>>
>> +      ReceivedBytes                                +=
>> RndisPacketMsg->DataLength;
>>
>> +      BulkInData                                    = ((UINT8
>> *)BulkInData) + RndisPacketMsg->DataLength;
>>
>> +      ((PACKET_LIST *)HeadPacket)->RemainingLength -=
>> RndisPacketMsg->DataLength;
>>
>> +    } else {
>>
>> +      DEBUG ((EFI_D_ERROR, "RndisUndiReceive:Buffer too small %x\n",
>> RndisPacketMsg->DataLength));
>>
>> +      *DataLength = RndisPacketMsg->DataLength;
>>
>> +      return EFI_BUFFER_TOO_SMALL;
>>
>> +    }
>>
>> +
>>
>> +    // check if there this is a multi-packet message. If so update the
>> pointer so that next Receive call will return that data.
>>
>> +    RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)((UINT8 *)RndisPacketMsg
>> + RndisPacketMsg->DataLength);
>>
>> +    PacketList     = (PACKET_LIST *)((UINT8 *)RndisPacketMsg - sizeof
>> (PACKET_LIST));
>>
>> +
>>
>> +    if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG))
>> && \
>>
>> +        (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) && \
>>
>> +        (RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) -
>> 8))
>>
>> +    {
>>
>> +      // Multi-Packet msg is found. Since the first packet is consumed,
>> update the linked list to point this new packet.
>>
>> +      PacketList->OrgBuffer       = HeadPacket->OrgBuffer;
>>
>> +      PacketList->RemainingLength = HeadPacket->RemainingLength;
>>
>> +      RemoveEntryList (&HeadPacket->PacketList);
>>
>> +      InsertHeadList (&UsbRndisDevice->ReceivePacketList,
>> &(PacketList->PacketList));
>>
>> +    } else {
>>
>> +      RemoveEntryList (&HeadPacket->PacketList);
>>
>> +      gBS->FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
>>
>> +    }
>>
>> +  } else {
>>
>> +    // Packet doesn't contain valid header
>>
>> +    DEBUG ((DEBUG_INFO, "RndisUndiReceive:Invalid RNDIS Packet
>> received\n"));
>>
>> +    RemoveEntryList (&(HeadPacket->PacketList));
>>
>> +    gBS->FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
>>
>> +  }
>>
>> +
>>
>> +  if (ReceivedBytes) {
>>
>> +    *DataLength = ReceivedBytes;
>>
>> +  }
>>
>> +
>>
>> +  return EFI_SUCCESS;
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  This is a dummy function which just returns. Unimplimented
>> 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 sends the RNDIS SET_MSG cmd
>>
>> +
>>
>> +  @param[in]  UsbRndisDevice  A pointer to the USB_RNDIS_DEVICE instance.
>>
>> +  @param[in]  Oid             Value of the OID.
>>
>> +  @param[in]  Length          Length of the data buffer.
>>
>> +  @param[in]  Buf             A pointer to the data buffer.
>>
>> +
>>
>> +  @retval EFI_SUCCESS         The request executed successfully.
>>
>> +
>>
>> +**/
>>
>> +EFI_STATUS
>>
>> +SendRndisSetMsg (
>>
>> +  IN  USB_RNDIS_DEVICE  *UsbRndisDevice,
>>
>> +  IN  UINT8             Oid,
>>
>> +  IN  UINT32            Length,
>>
>> +  IN  UINT8             *Buf
>>
>> +  )
>>
>> +{
>>
>> +  REMOTE_NDIS_SET_MSG  *RndisSetMsg;
>>
>> +  EFI_STATUS           Status;
>>
>> +
>>
>> +  RndisSetMsg = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE) + Length);
>>
>> +
>>
>> +  RndisSetMsg->MessageType             = RNDIS_SET_MSG;
>>
>> +  RndisSetMsg->MessageLength           = sizeof (REMOTE_NDIS_SET_MSG) +
>> Length;
>>
>> +  RndisSetMsg->RequestID               = UsbRndisDevice->RequestId;
>>
>> +  RndisSetMsg->Oid                     = Oid;
>>
>> +  RndisSetMsg->InformationBufferLength = Length;
>>
>> +  RndisSetMsg->InformationBufferOffset = sizeof (REMOTE_NDIS_SET_MSG) -
>> 8;
>>
>> +
>>
>> +  gBS->CopyMem (((UINT8 *)RndisSetMsg) + sizeof (REMOTE_NDIS_SET_MSG),
>> Buf, Length);
>>
>> +
>>
>> +  Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER
>> *)RndisSetMsg, NULL);
>>
>> +
>>
>> +  gBS->FreePool (RndisSetMsg);
>>
>> +
>>
>> +  return Status;
>>
>> +}
>>
>> +
>>
>> +/**
>>
>> +  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   = 0;
>>
>> +  UINT32                        SaveResponseLength = 0;
>>
>> +  UINT32                        Index;
>>
>> +  REMOTE_NDIS_INITIALIZE_CMPLT  *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++) {
>>
>> +    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"));
>>
>> +        continue;
>>
>> +      }
>>
>> +
>>
>> +      return Status;
>>
>> +    }
>>
>> +
>>
>> +    RndisMsgResponse->MessageType   = SaveResponseType;
>>
>> +    RndisMsgResponse->MessageLength = SaveResponseLength;
>>
>> +
>>
>> +    gBS->Stall (100000);    // 100msec
>>
>> +  }
>>
>> +
>>
>> +  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) {
>>
>> +    StopBulkInCnt = 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 = 0;
>>
>> +
>>
>> +  if (UsbRndisDevice->BulkInEndpoint == 0) {
>>
>> +    GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
>>
>> +  }
>>
>> +
>>
>> +  // Use StopBulkInCnt to stop BulkIn command
>>
>> +  if (StopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
>>
>> +    Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
>>
>> +
>>  UsbRndisDevice->UsbIoCdcData,
>>
>> +
>>  UsbRndisDevice->BulkInEndpoint,
>>
>> +                                             RndisMsg,
>>
>> +                                             TransferLength,
>>
>> +
>>  USB_RX_ETHERNET_BULK_TIMEOUT,
>>
>> +                                             &UsbStatus
>>
>> +                                             );
>>
>> +
>>
>> +    if (!EFI_ERROR (Status)) {
>>
>> +      StopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
>>
>> +    } else {
>>
>> +      StopBulkInCnt--;
>>
>> +    }
>>
>> +  } else {
>>
>> +    Status          = EFI_TIMEOUT;
>>
>> +    *TransferLength = 0;
>>
>> +    BlockBulkInCnt++;
>>
>> +  }
>>
>> +
>>
>> +  if (BlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
>>
>> +    StopBulkInCnt  = MINIMUM_STOPBULKIN_CNT;
>>
>> +    BlockBulkInCnt = 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 = 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"));
>>
>> +      Length = sizeof (REMOTE_NDIS_QUERY_CMPLT);
>>
>> +      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", RndisMsg[Index]));
>>
>> +      if (((Index % 4) == 3) && (Index != 0)) {
>>
>> +        DEBUG ((DEBUG_INFO, "\n"));
>>
>> +      }
>>
>> +    }
>>
>> +
>>
>> +    if (Index % 4) {
>>
>> +      DEBUG ((DEBUG_INFO, "\n"));
>>
>> +    }
>>
>> +  }
>>
>> +}
>>
>> --
>> 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.
>>
>>
>> 
>>
>>
>>
>
> --
> Pedro Falcato
>


-- 
Pedro Falcato


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#92583): https://edk2.groups.io/g/devel/message/92583
Mute This Topic: https://groups.io/mt/93121092/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/edk2-devel-archive/attachments/20220819/37cb3ea4/attachment-0001.htm>


More information about the edk2-devel-archive mailing list