From: "Chang, Abner" <abner.chang@amd.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
"richardho@ami.com" <richardho@ami.com>,
Rebecca Cran <rebecca@bsdio.com>
Cc: "Andrew Fish" <afish@apple.com>,
"Leif Lindholm" <quic_llindhol@quicinc.com>,
"Michael D Kinney" <michael.d.kinney@intel.com>,
"Michael Kubacki" <mikuback@linux.microsoft.com>,
"Zhiguang Liu" <zhiguang.liu@intel.com>,
"Liming Gao" <gaoliming@byosoft.com.cn>,
"Tinh Nguyen" <tinhnguyen@os.amperecomputing.com>,
"Tony Lo (羅金松)" <TonyLo@ami.com>
Subject: Re: [edk2-devel] [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support
Date: Tue, 11 Apr 2023 05:08:12 +0000 [thread overview]
Message-ID: <MN2PR12MB39664621AB469F3BBC3848F6EA9A9@MN2PR12MB3966.namprd12.prod.outlook.com> (raw)
In-Reply-To: <CY8PR10MB64410A6F8423A86C59AD772BB09A9@CY8PR10MB6441.namprd10.prod.outlook.com>
[AMD Official Use Only - General]
Hi All, are you sure a new package is really needed for the USB network devices that suppose should be located under MdeModulePkg/Bus/Usb for example MdeModulePkg/Bus/Usb/UsbNetwork?
We still can add an entry in Maintainers.txt for MdeModulePkg/Bus/Usb/UsbNetwork.
Abner
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
> RichardHo [???] via groups.io
> Sent: Tuesday, April 11, 2023 10:21 AM
> To: Rebecca Cran <rebecca@bsdio.com>; devel@edk2.groups.io
> Cc: Andrew Fish <afish@apple.com>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Michael D Kinney
> <michael.d.kinney@intel.com>; Michael Kubacki
> <mikuback@linux.microsoft.com>; Zhiguang Liu <zhiguang.liu@intel.com>;
> Liming Gao <gaoliming@byosoft.com.cn>; Tinh Nguyen
> <tinhnguyen@os.amperecomputing.com>; Tony Lo (羅金松)
> <TonyLo@ami.com>
> Subject: Re: [edk2-devel] [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add
> USB RNDIS devices support
>
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
>
>
> Hi Rebecca,
>
> May I add you to reviewer?
>
> To add below.
>
> UsbNetworkPkg
> F: UsbNetworkPkg/
> M: Richard Ho <richardho@ami.com> [richardho]
> R: Rebecca Cran <rebecca@bsdio.com> [bcran]
>
>
> Thanks,
> Richard
>
> -----Original Message-----
> From: Rebecca Cran <rebecca@bsdio.com>
> Sent: 2023年4月11日 12:02 AM
> To: Richard Ho (何明忠) <RichardHo@ami.com>; devel@edk2.groups.io
> Cc: Andrew Fish <afish@apple.com>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Michael D Kinney
> <michael.d.kinney@intel.com>; Michael Kubacki
> <mikuback@linux.microsoft.com>; Zhiguang Liu <zhiguang.liu@intel.com>;
> Liming Gao <gaoliming@byosoft.com.cn>; Tinh Nguyen
> <tinhnguyen@os.amperecomputing.com>; Tony Lo (羅金松)
> <TonyLo@ami.com>
> Subject: [EXTERNAL] Re: [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add USB
> RNDIS devices support
>
>
> **CAUTION: The e-mail below is from an external source. Please exercise
> caution before opening attachments, clicking links, or following guidance.**
>
> You probably don't need to add it in _this_ patch series, but since
> you're adding a new package you'll need to add an entry to Maintainers.txt.
>
>
> --
> Rebecca Cran
>
>
> On 4/7/23 5:27 AM, Richard Ho (何明忠) wrote:
> > This driver provides UEFI driver for USB RNDIS device
> >
> > Signed-off-by: Richard Ho <richardho@ami.com>
> > Cc: Andrew Fish <afish@apple.com>
> > Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > Cc: Michael Kubacki <mikuback@linux.microsoft.com>
> > Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> > Cc: Liming Gao <gaoliming@byosoft.com.cn>
> > Cc: Rebecca Cran <rebecca@bsdio.com>
> > Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
> > Reviewed-by: Tony Lo <tonylo@ami.com>
> > ---
> > .../Protocol/EdkIIUsbEthernetProtocol.h | 878 ++++++++
> > UsbNetworkPkg/NetworkCommon/ComponentName.c | 263 +++
> > UsbNetworkPkg/NetworkCommon/DriverBinding.c | 595 ++++++
> > UsbNetworkPkg/NetworkCommon/DriverBinding.h | 266 +++
> > UsbNetworkPkg/NetworkCommon/NetworkCommon.inf | 49 +
> > UsbNetworkPkg/NetworkCommon/PxeFunction.c | 1803
> +++++++++++++++++
> > UsbNetworkPkg/ReadMe.md | 65 +
> > UsbNetworkPkg/UsbNetworkPkg.ci.yaml | 65 +
> > UsbNetworkPkg/UsbNetworkPkg.dec | 46 +
> > UsbNetworkPkg/UsbNetworkPkg.dsc | 50 +
> > UsbNetworkPkg/UsbNetworkPkg.dsc.inc | 27 +
> > .../UsbNetworkPkgComponentsDxe.dsc.inc | 20 +
> > .../UsbNetworkPkgComponentsDxe.fdf.inc | 20 +
> > UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc | 14 +
> > UsbNetworkPkg/UsbRndis/ComponentName.c | 172 ++
> > UsbNetworkPkg/UsbRndis/UsbRndis.c | 886 ++++++++
> > UsbNetworkPkg/UsbRndis/UsbRndis.h | 586 ++++++
> > UsbNetworkPkg/UsbRndis/UsbRndis.inf | 42 +
> > UsbNetworkPkg/UsbRndis/UsbRndisFunction.c | 1718
> ++++++++++++++++
> > 19 files changed, 7565 insertions(+)
> > create mode 100644
> UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.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/UsbNetworkPkg.ci.yaml
> > create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dec
> > create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dsc
> > create mode 100644 UsbNetworkPkg/UsbNetworkPkg.dsc.inc
> > create mode 100644
> UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc
> > create mode 100644
> UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc
> > create mode 100644 UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc
> > 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/Include/Protocol/EdkIIUsbEthernetProtocol.h
> b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> > new file mode 100644
> > index 0000000000..f54946c7aa
> > --- /dev/null
> > +++ b/UsbNetworkPkg/Include/Protocol/EdkIIUsbEthernetProtocol.h
> > @@ -0,0 +1,878 @@
> > +/** @file
> > + Header file contains code for USB Ethernet Protocol
> > + definitions
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#ifndef EDKII_USB_ETHERNET_PROTOCOL_H_
> > +#define EDKII_USB_ETHERNET_PROTOCOL_H_
> > +
> > +#define EDKII_USB_ETHERNET_PROTOCOL_GUID \
> > + {0x8d8969cc, 0xfeb0, 0x4303, {0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56,
> 0x43}}
> > +
> > +typedef struct _EDKII_USB_ETHERNET_PROTOCOL
> EDKII_USB_ETHERNET_PROTOCOL;
> > +
> > +#define USB_CDC_CLASS 0x02
> > +#define USB_CDC_ACM_SUBCLASS 0x02
> > +#define USB_CDC_ECM_SUBCLASS 0x06
> > +#define USB_CDC_NCM_SUBCLASS 0x0D
> > +#define USB_CDC_DATA_CLASS 0x0A
> > +#define USB_CDC_DATA_SUBCLASS 0x00
> > +#define USB_NO_CLASS_PROTOCOL 0x00
> > +#define USB_NCM_NTB_PROTOCOL 0x01
> > +#define USB_VENDOR_PROTOCOL 0xFF
> > +
> > +// Type Values for the DescriptorType Field
> > +#define CS_INTERFACE 0x24
> > +#define CS_ENDPOINT 0x25
> > +
> > +// Descriptor SubType in Functional Descriptors
> > +#define HEADER_FUN_DESCRIPTOR 0x00
> > +#define UNION_FUN_DESCRIPTOR 0x06
> > +#define ETHERNET_FUN_DESCRIPTOR 0x0F
> > +
> > +#define MAX_LAN_INTERFACE 0x10
> > +
> > +// Table 20: Class-Specific Notification Codes
> > +#define USB_CDC_NETWORK_CONNECTION 0x00
> > +
> > +// 6.3.1 NetworkConnection
> > +#define NETWORK_CONNECTED 0x01
> > +#define NETWORK_DISCONNECT 0x00
> > +
> > +// USB Header functional Descriptor
> > +typedef struct {
> > + UINT8 FunctionLength;
> > + UINT8 DescriptorType;
> > + UINT8 DescriptorSubtype;
> > + UINT16 BcdCdc;
> > +} USB_HEADER_FUN_DESCRIPTOR;
> > +
> > +// USB Union Functional Descriptor
> > +typedef struct {
> > + UINT8 FunctionLength;
> > + UINT8 DescriptorType;
> > + UINT8 DescriptorSubtype;
> > + UINT8 MasterInterface;
> > + UINT8 SlaveInterface;
> > +} USB_UNION_FUN_DESCRIPTOR;
> > +
> > +// USB Ethernet Functional Descriptor
> > +typedef struct {
> > + UINT8 FunctionLength;
> > + UINT8 DescriptorType;
> > + UINT8 DescriptorSubtype;
> > + UINT8 MacAddress;
> > + UINT32 EthernetStatistics;
> > + UINT16 MaxSegmentSize;
> > + UINT16 NumberMcFilters;
> > + UINT8 NumberPowerFilters;
> > +} USB_ETHERNET_FUN_DESCRIPTOR;
> > +
> > +typedef struct {
> > + UINT32 UsBitRate;
> > + UINT32 DsBitRate;
> > +} USB_CONNECT_SPEED_CHANGE;
> > +
> > +// Request Type Codes for USB Ethernet
> > +#define USB_ETHERNET_GET_REQ_TYPE 0xA1
> > +#define USB_ETHERNET_SET_REQ_TYPE 0x21
> > +
> > +// Class-Specific Request Codes for Ethernet subclass
> > +// USB ECM 1.2 specification, Section 6.2
> > +#define SET_ETH_MULTICAST_FILTERS_REQ 0x40
> > +#define SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x41
> > +#define GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ 0x42
> > +#define SET_ETH_PACKET_FILTER_REQ 0x43
> > +#define GET_ETH_STATISTIC_REQ 0x44
> > +
> > +// USB ECM command request length
> > +#define USB_ETH_POWER_FILTER_LENGTH 2 // Section 6.2.3
> > +#define USB_ETH_PACKET_FILTER_LENGTH 0 // Section 6.2.4
> > +#define USB_ETH_STATISTIC 4 // Section 6.2.5
> > +
> > +// USB Ethernet Packet Filter Bitmap
> > +// USB ECM 1.2 specification, Section 6.2.4
> > +#define USB_ETH_PACKET_TYPE_PROMISCUOUS BIT0
> > +#define USB_ETH_PACKET_TYPE_ALL_MULTICAST BIT1
> > +#define USB_ETH_PACKET_TYPE_DIRECTED BIT2
> > +#define USB_ETH_PACKET_TYPE_BROADCAST BIT3
> > +#define USB_ETH_PACKET_TYPE_MULTICAST BIT4
> > +
> > +// USB Ethernet Statistics Feature Selector Codes
> > +// USB ECM 1.2 specification, Section 6.2.5
> > +#define USB_ETH_XMIT_OK 0x01
> > +#define USB_ETH_RCV_OK 0x02
> > +#define USB_ETH_XMIT_ERROR 0x03
> > +#define USB_ETH_RCV_ERROR 0x04
> > +#define USB_ETH_RCV_NO_BUFFER 0x05
> > +#define USB_ETH_DIRECTED_BYTES_XMIT 0x06
> > +#define USB_ETH_DIRECTED_FRAMES_XMIT 0x07
> > +#define USB_ETH_MULTICAST_BYTES_XMIT 0x08
> > +#define USB_ETH_MULTICAST_FRAMES_XMIT 0x09
> > +#define USB_ETH_BROADCAST_BYTES_XMIT 0x0A
> > +#define USB_ETH_BROADCAST_FRAMES_XMIT 0x0B
> > +#define USB_ETH_DIRECTED_BYTES_RCV 0x0C
> > +#define USB_ETH_DIRECTED_FRAMES_RCV 0x0D
> > +#define USB_ETH_MULTICAST_BYTES_RCV 0x0E
> > +#define USB_ETH_MULTICAST_FRAMES_RCV 0x0F
> > +#define USB_ETH_BROADCAST_BYTES_RCV 0x10
> > +#define USB_ETH_BROADCAST_FRAMES_RCV 0x11
> > +#define USB_ETH_RCV_CRC_ERROR 0x12
> > +#define USB_ETH_TRANSMIT_QUEUE_LENGTH 0x13
> > +#define USB_ETH_RCV_ERROR_ALIGNMENT 0x14
> > +#define USB_ETH_XMIT_ONE_COLLISION 0x15
> > +#define USB_ETH_XMIT_MORE_COLLISIONS 0x16
> > +#define USB_ETH_XMIT_DEFERRED 0x17
> > +#define USB_ETH_XMIT_MAX_COLLISIONS 0x18
> > +#define USB_ETH_RCV_OVERRUN 0x19
> > +#define USB_ETH_XMIT_UNDERRUN 0x1A
> > +#define USB_ETH_XMIT_HEARTBEAT_FAILURE 0x1B
> > +#define USB_ETH_XMIT_TIMES_CRS_LOST 0x1C
> > +#define USB_ETH_XMIT_LATE_COLLISIONS 0x1D
> > +
> > +// NIC Information
> > +typedef struct {
> > + UINT32 Signature;
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> > + UINT16 InterrupOpFlag;
> > + UINT64 MappedAddr;
> > + PXE_MAC_ADDR McastList[MAX_MCAST_ADDRESS_CNT];
> > + UINT8 McastCount;
> > + UINT64 MediaHeader[MAX_XMIT_BUFFERS];
> > + UINT8 TxBufferCount;
> > + UINT16 State;
> > + BOOLEAN CanTransmit;
> > + UINT16 ReceiveStatus;
> > + UINT8 RxFilter;
> > + UINT32 RxFrame;
> > + UINT32 TxFrame;
> > + UINT16 NetworkConnect;
> > + UINT8 CableDetect;
> > + UINT16 MaxSegmentSize;
> > + EFI_MAC_ADDRESS MacAddr;
> > + PXE_CPB_START_31 PxeStart;
> > + PXE_CPB_INITIALIZE PxeInit;
> > + UINT8 PermNodeAddress[PXE_MAC_LENGTH];
> > + UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];
> > + UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];
> > + EFI_USB_DEVICE_REQUEST Request;
> > + EFI_EVENT RateLimiter;
> > + UINT32 RateLimitingCredit;
> > + UINT32 RateLimitingCreditCount;
> > + UINT32 RateLimitingPollTimer;
> > + BOOLEAN RateLimitingEnable;
> > +} NIC_DATA;
> > +
> > +#define NIC_DATA_SIGNATURE SIGNATURE_32('n', 'i', 'c', 'd')
> > +#define NIC_DATA_FROM_EDKII_USB_ETHERNET_PROTOCOL(a) CR (a,
> NIC_DATA, UsbEth, NIC_DATA_SIGNATURE)
> > +
> > +/**
> > + This command is used to determine the operational state of the UNDI.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATE)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to change the UNDI operational state from
> stopped to started.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_START)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to change the UNDI operational state from started
> to stopped.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STOP)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to retrieve initialization information that is
> > + needed by drivers and applications to initialized UNDI.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to retrieve configuration information about
> > + the NIC being controlled by the UNDI.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command resets the network adapter and initializes UNDI using
> > + the parameters supplied in the CPB.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INITIALIZE)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command resets the network adapter and reinitializes the UNDI
> > + with the same parameters provided in the Initialize command.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RESET)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + The Shutdown command resets the network adapter and leaves it in a
> > + safe state for another driver to initialize.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_SHUTDOWN)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + The Interrupt Enables command can be used to read and/or change
> > + the current external interrupt enable settings.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to read and change receive filters and,
> > + if supported, read and change the multicast MAC address filter list.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to get current station and broadcast MAC
> addresses
> > + and, if supported, to change the current station MAC address.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to read and clear the NIC traffic statistics.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_STATISTICS)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to read and write (if supported by NIC H/W)
> > + nonvolatile storage on the NIC.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_NV_DATA)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command returns the current interrupt status and/or the
> > + transmitted buffer addresses and the current media status.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_GET_STATUS)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to fill the media header(s) in transmit packet(s).
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_FILL_HEADER)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + The Transmit command is used to place a packet into the transmit queue.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_TRANSMIT)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + When the network adapter has received a frame, this command is used
> > + to copy the frame into driver/application storage.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_UNDI_RECEIVE)(
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command resets the network adapter and initializes UNDI using
> > + the parameters supplied in the CPB.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in, out] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_INITIALIZE)(
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + );
> > +
> > +/**
> > + This command is used to read and clear the NIC traffic statistics.
> > +
> > + @param[in] Nic A pointer to the Network interface controller data.
> > + @param[in] DbAddr Data Block Address.
> > + @param[in] DbSize Data Block Size.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_STATISTICS)(
> > + IN NIC_DATA *Nic,
> > + IN UINT64 DbAddr,
> > + IN UINT16 DbSize
> > + );
> > +
> > +/**
> > + This function is used to manage a USB device with the bulk transfer pipe.
> The endpoint is Bulk in.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in, out] Packet A pointer to the buffer of data that will be
> transmitted to USB
> > + device or received from USB device.
> > + @param[in, out] PacketLength A pointer to the PacketLength.
> > +
> > + @retval EFI_SUCCESS The bulk transfer has been successfully
> executed.
> > + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is
> returned in status.
> > + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> > + @retval EFI_OUT_OF_RESOURCES The request could not be submitted
> due to a lack of resources.
> > + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_RECEIVE)(
> > + IN PXE_CDB *Cdb,
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN OUT VOID *Packet,
> > + IN OUT UINTN *PacketLength
> > + );
> > +
> > +/**
> > + This function is used to manage a USB device with the bulk transfer pipe.
> The endpoint is Bulk out.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in, out] Packet A pointer to the buffer of data that will be
> transmitted to USB
> > + device or received from USB device.
> > + @param[in, out] PacketLength A pointer to the PacketLength.
> > +
> > + @retval EFI_SUCCESS The bulk transfer has been successfully
> executed.
> > + @retval EFI_DEVICE_ERROR The transfer failed. The transfer status is
> returned in status.
> > + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> > + @retval EFI_OUT_OF_RESOURCES The request could not be submitted
> due to a lack of resources.
> > + @retval EFI_TIMEOUT The control transfer fails due to timeout.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_TRANSMIT)(
> > + IN PXE_CDB *Cdb,
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN OUT VOID *Packet,
> > + IN OUT UINTN *PacketLength
> > + );
> > +
> > +/**
> > + This function is used to manage a USB device with an interrupt transfer
> pipe.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted
> to USB controller. If
> > + FALSE, the interrupt transfer is deleted from the device's
> interrupt
> > + transfer queue.
> > + @param[in] PollingInterval Indicates the periodic rate, in milliseconds,
> that the transfer is to be
> > + executed.This parameter is required when IsNewTransfer
> is TRUE. The
> > + value must be between 1 to 255, otherwise
> EFI_INVALID_PARAMETER is returned.
> > + The units are in milliseconds.
> > + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST
> data.
> > +
> > + @retval EFI_SUCCESS The asynchronous USB transfer request
> transfer has been successfully executed.
> > + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request
> failed.
> > +
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_INTERRUPT)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN BOOLEAN IsNewTransfer,
> > + IN UINTN PollingInterval,
> > + IN EFI_USB_DEVICE_REQUEST *Request
> > + );
> > +
> > +/**
> > + Retrieves the USB Ethernet Mac Address.
> > +
> > + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL
> instance.
> > + @param[out] MacAddress A pointer to the caller allocated USB
> Ethernet Mac Address.
> > +
> > + @retval EFI_SUCCESS The USB Header Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Header Functional descriptor was
> not found.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_GET_ETH_MAC_ADDRESS)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT EFI_MAC_ADDRESS *MacAddress
> > + );
> > +
> > +/**
> > + Retrieves the USB Ethernet Bulk transfer data size.
> > +
> > + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL
> instance.
> > + @param[out] BulkSize A pointer to the Bulk transfer data size.
> > +
> > + @retval EFI_SUCCESS The USB Header Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Header Functional descriptor was
> not found.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETH_MAX_BULK_SIZE)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT UINTN *BulkSize
> > + );
> > +
> > +/**
> > + Retrieves the USB Header functional Descriptor.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated
> USB Header Functional Descriptor.
> > +
> > + @retval EFI_SUCCESS The USB Header Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Header Functional descriptor was
> not found.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> > + );
> > +
> > +/**
> > + Retrieves the USB Union functional Descriptor.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated
> USB Union Functional Descriptor.
> > +
> > + @retval EFI_SUCCESS The USB Union Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Union Functional descriptor was
> not found.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> > + );
> > +
> > +/**
> > + Retrieves the USB Ethernet functional Descriptor.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[out] UsbEthFunDescriptor A pointer to the caller allocated
> USB Ethernet Functional Descriptor.
> > +
> > + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor
> was not found.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> > + );
> > +
> > +/**
> > + This request sets the Ethernet device multicast filters as specified in the
> > + sequential list of 48 bit Ethernet multicast addresses.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value Number of filters.
> > + @param[in] McastAddr A pointer to the value of the multicast
> addresses.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN VOID *McastAddr
> > + );
> > +
> > +/**
> > + This request sets up the specified Ethernet power management pattern
> filter as
> > + described in the data structure.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value Number of filters.
> > + @param[in] Length Size of the power management pattern filter
> data.
> > + @param[in] PatternFilter A pointer to the power management
> pattern filter structure.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI
> *EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN UINT16 Length,
> > + IN VOID *PatternFilter
> > + );
> > +
> > +/**
> > + This request retrieves the status of the specified Ethernet power
> management
> > + pattern filter from the device.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value The filter number.
> > + @param[out] PatternActive A pointer to the pattern active boolean.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI
> *EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + OUT BOOLEAN *PatternActive
> > + );
> > +
> > +/**
> > + This request is used to configure device Ethernet packet filter settings.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value Packet Filter Bitmap.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value
> > + );
> > +
> > +/**
> > + This request is used to retrieve a statistic based on the feature selector.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] FeatureSelector Value of the feature selector.
> > + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *EDKII_USB_ETHERNET_GET_ETH_STATISTIC)(
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 FeatureSelector,
> > + OUT VOID *Statistic
> > + );
> > +
> > +typedef struct {
> > + EDKII_USB_ETHERNET_UNDI_GET_STATE UsbEthUndiGetState;
> > + EDKII_USB_ETHERNET_UNDI_START UsbEthUndiStart;
> > + EDKII_USB_ETHERNET_UNDI_STOP UsbEthUndiStop;
> > + EDKII_USB_ETHERNET_UNDI_GET_INIT_INFO UsbEthUndiGetInitInfo;
> > + EDKII_USB_ETHERNET_UNDI_GET_CONFIG_INFO
> UsbEthUndiGetConfigInfo;
> > + EDKII_USB_ETHERNET_UNDI_INITIALIZE UsbEthUndiInitialize;
> > + EDKII_USB_ETHERNET_UNDI_RESET UsbEthUndiReset;
> > + EDKII_USB_ETHERNET_UNDI_SHUTDOWN UsbEthUndiShutdown;
> > + EDKII_USB_ETHERNET_UNDI_INTERRUPT_ENABLE
> UsbEthUndiInterruptEnable;
> > + EDKII_USB_ETHERNET_UNDI_RECEIVE_FILTER
> UsbEthUndiReceiveFilter;
> > + EDKII_USB_ETHERNET_UNDI_STATION_ADDRESS
> UsbEthUndiStationAddress;
> > + EDKII_USB_ETHERNET_UNDI_STATISTICS UsbEthUndiStatistics;
> > + EDKII_USB_ETHERNET_UNDI_MCAST_IPTOMAC
> UsbEthUndiMcastIp2Mac;
> > + EDKII_USB_ETHERNET_UNDI_NV_DATA UsbEthUndiNvData;
> > + EDKII_USB_ETHERNET_UNDI_GET_STATUS UsbEthUndiGetStatus;
> > + EDKII_USB_ETHERNET_UNDI_FILL_HEADER UsbEthUndiFillHeader;
> > + EDKII_USB_ETHERNET_UNDI_TRANSMIT UsbEthUndiTransmit;
> > + EDKII_USB_ETHERNET_UNDI_RECEIVE UsbEthUndiReceive;
> > +} EDKII_USB_ETHERNET_UNDI;
> > +
> > +// The EDKII_USB_ETHERNET_PROTOCOL provides some basic USB
> Ethernet device relevant
> > +// descriptor and specific requests.
> > +struct _EDKII_USB_ETHERNET_PROTOCOL {
> > + EDKII_USB_ETHERNET_UNDI UsbEthUndi;
> > + // for calling the UNDI child functions
> > + EDKII_USB_ETHERNET_INITIALIZE UsbEthInitialize;
> > + EDKII_USB_ETHERNET_STATISTICS UsbEthStatistics;
> > + EDKII_USB_ETHERNET_RECEIVE UsbEthReceive;
> > + EDKII_USB_ETHERNET_TRANSMIT UsbEthTransmit;
> > + EDKII_USB_ETHERNET_INTERRUPT UsbEthInterrupt;
> > + EDKII_USB_GET_ETH_MAC_ADDRESS UsbEthMacAddress;
> > + EDKII_USB_ETH_MAX_BULK_SIZE UsbEthMaxBulkSize;
> > + EDKII_USB_HEADER_FUNCTIONAL_DESCRIPTOR
> UsbHeaderFunDescriptor;
> > + EDKII_USB_UNION_FUNCTIONAL_DESCRIPTOR
> UsbUnionFunDescriptor;
> > + EDKII_USB_ETHERNET_FUNCTIONAL_DESCRIPTOR
> UsbEthFunDescriptor;
> > + EDKII_USB_ETHERNET_SET_ETH_MULTICAST_FILTERS
> SetUsbEthMcastFilter;
> > + EDKII_USB_ETHERNET_SET_ETH_POWER_MANAGE_PATTERN_FILTER
> SetUsbEthPowerPatternFilter;
> > + EDKII_USB_ETHERNET_GET_ETH_POWER_MANAGE_PATTERN_FILTER
> GetUsbEthPowerPatternFilter;
> > + EDKII_USB_ETHERNET_SET_ETH_PACKET_FILTER
> SetUsbEthPacketFilter;
> > + EDKII_USB_ETHERNET_GET_ETH_STATISTIC
> GetUsbEthStatistic;
> > +};
> > +
> > +extern EFI_GUID gEdkIIUsbEthProtocolGuid;
> > +
> > +#endif
> > diff --git a/UsbNetworkPkg/NetworkCommon/ComponentName.c
> b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> > new file mode 100644
> > index 0000000000..e83469e130
> > --- /dev/null
> > +++ b/UsbNetworkPkg/NetworkCommon/ComponentName.c
> > @@ -0,0 +1,263 @@
> > +/** @file
> > + This file contains code for USB network common driver
> > + component name definitions
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include "DriverBinding.h"
> > +
> > +extern EFI_DRIVER_BINDING_PROTOCOL
> gNetworkCommonDriverBinding;
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> gNetworkCommonDriverNameTable[] = {
> > + {
> > + "eng;en",
> > + L"Network Common Driver"
> > + },
> > + {
> > + NULL,
> > + NULL
> > + }
> > +};
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> *gNetworkCommonControllerNameTable = NULL;
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_HANDLE ChildHandle OPTIONAL,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > + );
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME_PROTOCOL gNetworkCommonComponentName
> = {
> > + NetworkCommonComponentNameGetDriverName,
> > + NetworkCommonComponentNameGetControllerName,
> > + "eng"
> > +};
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME2_PROTOCOL
> gNetworkCommonComponentName2 = {
> > +
> (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)NetworkCommonCompon
> entNameGetDriverName,
> > +
> (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)NetworkCommonCo
> mponentNameGetControllerName,
> > + "en"
> > +};
> > +
> > +/**
> > + Retrieves a Unicode string that is the user readable name of the driver.
> > +
> > + This function retrieves the user readable name of a driver in the form of
> a
> > + Unicode string. If the driver specified by This has a user readable name in
> > + the language specified by Language, then a pointer to the driver name is
> > + returned in DriverName, and EFI_SUCCESS is returned. If the driver
> specified
> > + by This does not support the language specified by Language,
> > + then EFI_UNSUPPORTED is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > + @param[in] Language A pointer to a Null-terminated ASCII string
> > + array indicating the language. This is the
> > + language of the driver name that the caller is
> > + requesting, and it must match one of the
> > + languages specified in SupportedLanguages. The
> > + number of languages supported by a driver is up
> > + to the driver writer. Language is specified
> > + in RFC 4646 or ISO 639-2 language code format.
> > + @param[out] DriverName A pointer to the Unicode string to return.
> > + This Unicode string is the name of the
> > + driver specified by This in the language
> > + specified by Language.
> > +
> > + @retval EFI_SUCCESS The Unicode string for the Driver specified by
> > + This and the language specified by Language was
> > + returned in DriverName.
> > + @retval EFI_INVALID_PARAMETER Language is NULL.
> > + @retval EFI_INVALID_PARAMETER DriverName is NULL.
> > + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> > + the language specified by Language.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > + )
> > +{
> > + return LookupUnicodeString2 (
> > + Language,
> > + This->SupportedLanguages,
> > + gNetworkCommonDriverNameTable,
> > + DriverName,
> > + (BOOLEAN)(This == &gNetworkCommonComponentName)
> > + );
> > +}
> > +
> > +/**
> > + Retrieves a Unicode string that is the user readable name of the
> controller
> > + that is being managed by a driver.
> > +
> > + This function retrieves the user readable name of the controller specified
> by
> > + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> > + driver specified by This has a user readable name in the language
> specified by
> > + Language, then a pointer to the controller name is returned in
> ControllerName,
> > + and EFI_SUCCESS is returned. If the driver specified by This is not
> currently
> > + managing the controller specified by ControllerHandle and ChildHandle,
> > + then EFI_UNSUPPORTED is returned. If the driver specified by This does
> not
> > + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> > +
> > + @param[in] This A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > + @param[in] Controller The handle of a controller that the driver
> > + specified by This is managing. This handle
> > + specifies the controller whose name is to be
> > + returned.
> > + @param[in] ChildHandle The handle of the child controller to retrieve
> > + the name of. This is an optional parameter that
> > + may be NULL. It will be NULL for device
> > + drivers. It will also be NULL for a bus drivers
> > + that wish to retrieve the name of the bus
> > + controller. It will not be NULL for a bus
> > + driver that wishes to retrieve the name of a
> > + child controller.
> > + @param[in] Language A pointer to a Null-terminated ASCII string
> > + array indicating the language. This is the
> > + language of the driver name that the caller is
> > + requesting, and it must match one of the
> > + languages specified in SupportedLanguages. The
> > + number of languages supported by a driver is up
> > + to the driver writer. Language is specified in
> > + RFC 4646 or ISO 639-2 language code format.
> > + @param[out] ControllerName A pointer to the Unicode string to return.
> > + This Unicode string is the name of the
> > + controller specified by ControllerHandle and
> > + ChildHandle in the language specified by
> > + Language from the point of view of the driver
> > + specified by This.
> > +
> > + @retval EFI_SUCCESS The Unicode string for the user readable
> name in
> > + the language specified by Language for the
> > + driver specified by This was returned in
> > + DriverName.
> > + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid
> EFI_HANDLE.
> > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> > + EFI_HANDLE.
> > + @retval EFI_INVALID_PARAMETER Language is NULL.
> > + @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> > + @retval EFI_UNSUPPORTED The driver specified by This is not
> currently
> > + managing the controller specified by
> > + ControllerHandle and ChildHandle.
> > + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> > + the language specified by Language.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_HANDLE ChildHandle OPTIONAL,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > + )
> > +{
> > + EFI_STATUS Status;
> > + CHAR16 *HandleName;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + EFI_USB_DEVICE_DESCRIPTOR DevDesc;
> > +
> > + if (!Language || !ControllerName) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (ChildHandle == NULL) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + //
> > + // Make sure this driver is currently managing ControllerHandle
> > + //
> > + Status = EfiTestManagedDevice (
> > + Controller,
> > + gNetworkCommonDriverBinding.DriverBindingHandle,
> > + &gEdkIIUsbEthProtocolGuid
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Make sure this driver produced ChildHandle
> > + //
> > + Status = EfiTestChildHandle (
> > + Controller,
> > + ChildHandle,
> > + &gEdkIIUsbEthProtocolGuid
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->HandleProtocol (Controller, &gEfiUsbIoProtocolGuid,
> (VOID **)&UsbIo);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = UsbIo->UsbGetStringDescriptor (UsbIo, 0x409,
> DevDesc.StrManufacturer, &HandleName);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + *ControllerName = HandleName;
> > +
> > + if (gNetworkCommonControllerNameTable != NULL) {
> > + FreeUnicodeStringTable (gNetworkCommonControllerNameTable);
> > + gNetworkCommonControllerNameTable = NULL;
> > + }
> > +
> > + Status = AddUnicodeString2 (
> > + "eng",
> > + gNetworkCommonComponentName.SupportedLanguages,
> > + &gNetworkCommonControllerNameTable,
> > + HandleName,
> > + TRUE
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = AddUnicodeString2 (
> > + "en",
> > + gNetworkCommonComponentName2.SupportedLanguages,
> > + &gNetworkCommonControllerNameTable,
> > + HandleName,
> > + FALSE
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + return LookupUnicodeString2 (
> > + Language,
> > + This->SupportedLanguages,
> > + gNetworkCommonControllerNameTable,
> > + ControllerName,
> > + (BOOLEAN)(This == &gNetworkCommonComponentName)
> > + );
> > + }
> > +
> > + return EFI_UNSUPPORTED;
> > +}
> > diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> > new file mode 100644
> > index 0000000000..23b7913620
> > --- /dev/null
> > +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.c
> > @@ -0,0 +1,595 @@
> > +/** @file
> > + This file contains code for USB network binding driver
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include "DriverBinding.h"
> > +
> > +PXE_SW_UNDI *gPxe = NULL;
> > +NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> > +UINT32 gRateLimitingCredit;
> > +UINT32 gRateLimitingPollTimer;
> > +BOOLEAN gRateLimitingEnable;
> > +
> > +EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
> > + NetworkCommonSupported,
> > + NetworkCommonDriverStart,
> > + NetworkCommonDriverStop,
> > + NETWORK_COMMON_DRIVER_VERSION,
> > + NULL,
> > + NULL
> > +};
> > +
> > +/**
> > + Create MAC Device Path
> > +
> > + @param[in, out] Dev A pointer to the
> EFI_DEVICE_PATH_PROTOCOL instance.
> > + @param[in] BaseDev A pointer to the
> EFI_DEVICE_PATH_PROTOCOL instance.
> > + @param[in] Nic A pointer to the Network interface controller
> data.
> > +
> > + @retval EFI_OUT_OF_RESOURCES The device path could not be
> created successfully due to a lack of resources.
> > + @retval EFI_SUCCESS MAC device path created successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +CreateMacDevicePath (
> > + IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
> > + IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > + MAC_ADDR_DEVICE_PATH MacAddrNode;
> > + EFI_DEVICE_PATH_PROTOCOL *EndNode;
> > + UINT8 *DevicePath;
> > + UINT16 TotalLength;
> > + UINT16 BaseLength;
> > +
> > + ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
> > + CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof
> (EFI_MAC_ADDRESS));
> > +
> > + MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
> > + MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
> > + MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
> > + MacAddrNode.Header.Length[1] = 0;
> > +
> > + EndNode = BaseDev;
> > +
> > + while (!IsDevicePathEnd (EndNode)) {
> > + EndNode = NextDevicePathNode (EndNode);
> > + }
> > +
> > + BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
> > + TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof
> (EFI_DEVICE_PATH_PROTOCOL));
> > +
> > + Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID
> **)&DevicePath);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + *Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
> > + CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
> > + DevicePath += BaseLength;
> > + CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof
> (MacAddrNode));
> > + DevicePath += sizeof (MacAddrNode);
> > + CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof
> (EFI_DEVICE_PATH_PROTOCOL));
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Network Common Driver Binding Support.
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to test.
> > + @param[in] RemainingDevicePath Optional parameter use to pick a
> specific child
> > + device to start.
> > +
> > + @retval EFI_SUCCESS This driver supports this device.
> > + @retval EFI_ALREADY_STARTED This driver is already running on this
> device.
> > + @retval other This driver does not support this device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + (VOID **)&UsbEth,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return Status;
> > +}
> > +
> > +/**
> > + Network Common Driver Binding Start.
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to bind driver to.
> > + @param[in] RemainingDevicePath Optional parameter use to pick a
> specific child
> > + device to start.
> > +
> > + @retval EFI_SUCCESS This driver is added to ControllerHandle
> > + @retval EFI_DEVICE_ERROR This driver could not be started due to
> a device error
> > + @retval EFI_OUT_OF_RESOURCES The driver could not install
> successfully due to a lack of resources.
> > + @retval other This driver does not support this device
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonDriverStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> > + EFI_MAC_ADDRESS MacAddress;
> > + UINTN BulkDataSize;
> > + NIC_DEVICE *NicDevice;
> > + UINT8 *TmpPxePointer;
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + (VOID **)&UsbEth,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbEthPath,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return Status;
> > + }
> > +
> > + ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
> > +
> > + Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
> > + ASSERT_EFI_ERROR (Status);
> > + Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
> > +
> > + if (EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return Status;
> > + }
> > +
> > + NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize +
> 4096);
> > + if (!NicDevice) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + // for alignment adjustment
> > + if (gPxe == NULL) {
> > + TmpPxePointer = NULL;
> > + TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
> > + if (!TmpPxePointer) {
> > + if (NicDevice != NULL) {
> > + FreePool (NicDevice);
> > + }
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > +
> > + return EFI_OUT_OF_RESOURCES;
> > + } else {
> > + // check for paragraph alignment here
> > + if (((UINTN)TmpPxePointer & 0x0F) != 0) {
> > + gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
> > + } else {
> > + gPxe = (PXE_SW_UNDI *)TmpPxePointer;
> > + }
> > +
> > + if (!gPxe) {
> > + if (NicDevice != NULL) {
> > + FreePool (NicDevice);
> > + }
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + PxeStructInit (gPxe);
> > + }
> > + }
> > +
> > + NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
> > + NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
> > +
> > + UpdateNicNum (&NicDevice->NicInfo, gPxe);
> > +
> > + NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
> > +
> > + NicDevice->NicInfo.UsbEth = UsbEth;
> > + NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
> > + NicDevice->NicInfo.CableDetect = 0;
> > + NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice,
> 4096);
> > +
> > + CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8
> *)&MacAddress, sizeof (MacAddress));
> > +
> > + NicDevice->NicInfo.TxBufferCount = 0;
> > +
> > + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> > + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
> > + } else {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > +
> > + if (TmpPxePointer != NULL) {
> > + FreePool (TmpPxePointer);
> > + }
> > +
> > + if (NicDevice != NULL) {
> > + FreePool (NicDevice);
> > + }
> > +
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + Status = CreateMacDevicePath (
> > + &NicDevice->DevPath,
> > + UsbEthPath,
> > + &NicDevice->NicInfo
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + UpdateNicNum (NULL, gPxe);
> > + if (TmpPxePointer != NULL) {
> > + FreePool (TmpPxePointer);
> > + }
> > + }
> > +
> > + NicDevice->Signature = UNDI_DEV_SIGNATURE;
> > + NicDevice->NiiProtocol.Revision =
> EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
> > + NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
> > + NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
> > + NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
> > + NicDevice->NiiProtocol.ImageSize = 0;
> > + NicDevice->NiiProtocol.ImageAddr = 0;
> > + NicDevice->NiiProtocol.Ipv6Supported = TRUE;
> > +
> > + NicDevice->NiiProtocol.StringId[0] = 'U';
> > + NicDevice->NiiProtocol.StringId[1] = 'N';
> > + NicDevice->NiiProtocol.StringId[2] = 'D';
> > + NicDevice->NiiProtocol.StringId[3] = 'I';
> > + NicDevice->DeviceHandle = NULL;
> > +
> > + NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
> > + NicDevice->NicInfo.RateLimitingCreditCount = 0;
> > + NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
> > + NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
> > + NicDevice->NicInfo.RateLimiter = NULL;
> > +
> > + ZeroMem (&NicDevice->NicInfo.Request, sizeof
> (EFI_USB_DEVICE_REQUEST));
> > +
> > + Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE,
> NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
> > + ASSERT_EFI_ERROR (Status);
> > +
> > + Status = gBS->InstallMultipleProtocolInterfaces (
> > + &NicDevice->DeviceHandle,
> > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> > + &NicDevice->NiiProtocol,
> > + &gEfiDevicePathProtocolGuid,
> > + NicDevice->DevPath,
> > + NULL
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
> > + gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
> > + }
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > +
> > + if (TmpPxePointer != NULL) {
> > + FreePool (TmpPxePointer);
> > + }
> > +
> > + if (NicDevice->DevPath != NULL) {
> > + FreePool (NicDevice->DevPath);
> > + }
> > +
> > + if (NicDevice != NULL) {
> > + FreePool (NicDevice);
> > + }
> > +
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + (VOID **)&UsbEth,
> > + This->DriverBindingHandle,
> > + NicDevice->DeviceHandle,
> > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> > + );
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Network Common Driver Binding Stop.
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to stop driver on
> > + @param[in] NumberOfChildren Number of Handles in
> ChildHandleBuffer. If number of
> > + children is zero stop the entire bus driver.
> > + @param[in] ChildHandleBuffer List of Child Handles to Stop.
> > +
> > + @retval EFI_SUCCESS This driver is removed ControllerHandle
> > + @retval other This driver was not removed from this device
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonDriverStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + )
> > +{
> > + EFI_STATUS Status;
> > + BOOLEAN AllChildrenStopped;
> > + UINTN Index;
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
> > + NIC_DEVICE *NicDevice;
> > + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
> > +
> > + if (NumberOfChildren == 0) {
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> > + (VOID **)&NiiProtocol,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return EFI_SUCCESS;
> > + }
> > +
> > + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> > + Status = gBS->UninstallMultipleProtocolInterfaces (
> > + ControllerHandle,
> > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> > + &NicDevice->NiiProtocol,
> > + &gEfiDevicePathProtocolGuid,
> > + NicDevice->DevPath,
> > + NULL
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + FreePool (NicDevice->DevPath);
> > + FreePool (NicDevice);
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return EFI_SUCCESS;
> > + }
> > +
> > + AllChildrenStopped = TRUE;
> > +
> > + for (Index = 0; Index < NumberOfChildren; Index++) {
> > + Status = gBS->OpenProtocol (
> > + ChildHandleBuffer[Index],
> > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> > + (VOID **)&NiiProtocol,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > + );
> > + if (EFI_ERROR (Status)) {
> > + AllChildrenStopped = FALSE;
> > + continue;
> > + }
> > +
> > + NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + This->DriverBindingHandle,
> > + ChildHandleBuffer[Index]
> > + );
> > +
> > + Status = gBS->UninstallMultipleProtocolInterfaces (
> > + ChildHandleBuffer[Index],
> > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
> > + &NicDevice->NiiProtocol,
> > + &gEfiDevicePathProtocolGuid,
> > + NicDevice->DevPath,
> > + NULL
> > + );
> > + if (EFI_ERROR (Status)) {
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + (VOID **)&UsbEth,
> > + This->DriverBindingHandle,
> > + ChildHandleBuffer[Index],
> > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> > + );
> > + } else {
> > + FreePool (NicDevice->DevPath);
> > + FreePool (NicDevice);
> > + }
> > + }
> > +
> > + if (!AllChildrenStopped) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Entrypoint of Network Common Driver.
> > +
> > + This function is the entrypoint of Network Common Driver. It installs
> Driver Binding
> > + Protocols together with Component Name Protocols.
> > +
> > + @param[in] ImageHandle The firmware allocated handle for the EFI
> image.
> > + @param[in] SystemTable A pointer to the EFI System Table.
> > +
> > + @retval EFI_SUCCESS The entry point is executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonEntry (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
> > + gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
> > + gRateLimitingEnable = PcdGetBool (EnableRateLimiting);
> > + gRateLimitingCredit = PcdGet32 (RateLimitingCredit);
> > + gRateLimitingPollTimer = PcdGet32 (RateLimitingFactor);
> > +
> > + Status = gBS->InstallMultipleProtocolInterfaces (
> > + &gNetworkCommonDriverBinding.DriverBindingHandle,
> > + &gEfiDriverBindingProtocolGuid,
> > + &gNetworkCommonDriverBinding,
> > + &gEfiComponentName2ProtocolGuid,
> > + &gNetworkCommonComponentName2,
> > + NULL
> > + );
> > + return Status;
> > +}
> > diff --git a/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> > new file mode 100644
> > index 0000000000..0416ce1323
> > --- /dev/null
> > +++ b/UsbNetworkPkg/NetworkCommon/DriverBinding.h
> > @@ -0,0 +1,266 @@
> > +/** @file
> > + Header file for for USB network common driver
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#ifndef _DRIVER_BINDING_H_
> > +#define _DRIVER_BINDING_H_
> > +
> > +#include <Library/UefiDriverEntryPoint.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiLib.h>
> > +#include <Library/DevicePathLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/UefiUsbLib.h>
> > +#include <Protocol/UsbIo.h>
> > +#include <Protocol/NetworkInterfaceIdentifier.h>
> > +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> > +
> > +#define NETWORK_COMMON_DRIVER_VERSION 1
> > +#define NETWORK_COMMON_POLLING_INTERVAL 0x10
> > +#define RX_BUFFER_COUNT 32
> > +#define TX_BUFFER_COUNT 32
> > +#define MEMORY_REQUIRE 0
> > +
> > +#define UNDI_DEV_SIGNATURE SIGNATURE_32('u','n','d','i')
> > +#define UNDI_DEV_FROM_THIS(a) CR(a, NIC_DEVICE, NiiProtocol,
> UNDI_DEV_SIGNATURE)
> > +#define UNDI_DEV_FROM_NIC(a) CR(a, NIC_DEVICE, NicInfo,
> UNDI_DEV_SIGNATURE)
> > +
> > +#pragma pack(1)
> > +typedef struct {
> > + UINT8 DestAddr[PXE_HWADDR_LEN_ETHER];
> > + UINT8 SrcAddr[PXE_HWADDR_LEN_ETHER];
> > + UINT16 Protocol;
> > +} EthernetHeader;
> > +#pragma pack()
> > +
> > +typedef struct {
> > + UINTN Signature;
> > + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NiiProtocol;
> > + EFI_HANDLE DeviceHandle;
> > + EFI_DEVICE_PATH_PROTOCOL *BaseDevPath;
> > + EFI_DEVICE_PATH_PROTOCOL *DevPath;
> > + NIC_DATA NicInfo;
> > + VOID *ReceiveBuffer;
> > +} NIC_DEVICE;
> > +
> > +typedef VOID (*API_FUNC)(
> > + PXE_CDB *,
> > + NIC_DATA *
> > + );
> > +
> > +extern PXE_SW_UNDI *gPxe;
> > +extern NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
> > +extern EFI_COMPONENT_NAME2_PROTOCOL
> gNetworkCommonComponentName2;
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonDriverStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +NetworkCommonDriverStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + );
> > +
> > +VOID
> > +PxeStructInit (
> > + OUT PXE_SW_UNDI *PxeSw
> > + );
> > +
> > +VOID
> > +UpdateNicNum (
> > + IN NIC_DATA *Nic,
> > + IN OUT PXE_SW_UNDI *PxeSw
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UndiApiEntry (
> > + IN UINT64 Cdb
> > + );
> > +
> > +UINTN
> > +MapIt (
> > + IN NIC_DATA *Nic,
> > + IN UINT64 MemAddr,
> > + IN UINT32 Size,
> > + IN UINT32 Direction,
> > + OUT UINT64 MappedAddr
> > + );
> > +
> > +VOID
> > +UnMapIt (
> > + IN NIC_DATA *Nic,
> > + IN UINT64 MemAddr,
> > + IN UINT32 Size,
> > + IN UINT32 Direction,
> > + IN UINT64 MappedAddr
> > + );
> > +
> > +VOID
> > +UndiGetState (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiStart (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiStop (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiGetInitInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiGetConfigInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiInitialize (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiReset (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiShutdown (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiInterruptEnable (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiReceiveFilter (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiStationAddress (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiStatistics (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiMcastIp2Mac (
> > + IN OUT PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiNvData (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiGetStatus (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiFillHeader (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiTransmit (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +VOID
> > +UndiReceive (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +UINT16
> > +Initialize (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + );
> > +
> > +UINT16
> > +Transmit (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic,
> > + IN UINT64 CpbAddr,
> > + IN UINT16 OpFlags
> > + );
> > +
> > +UINT16
> > +Receive (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic,
> > + IN UINT64 CpbAddr,
> > + IN OUT UINT64 DbAddr
> > + );
> > +
> > +UINT16
> > +SetFilter (
> > + IN NIC_DATA *Nic,
> > + IN UINT16 SetFilter,
> > + IN UINT64 CpbAddr,
> > + IN UINT32 CpbSize
> > + );
> > +
> > +UINT16
> > +Statistics (
> > + IN NIC_DATA *Nic,
> > + IN UINT64 DbAddr,
> > + IN UINT16 DbSize
> > + );
> > +
> > +#endif
> > diff --git a/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> > new file mode 100644
> > index 0000000000..8923102bc3
> > --- /dev/null
> > +++ b/UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> > @@ -0,0 +1,49 @@
> > +## @file
> > +# This is Usb Network Common driver for DXE phase.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > +[Defines]
> > + INF_VERSION = 0x00010005
> > + BASE_NAME = NetworkCommon
> > + FILE_GUID = ca6eb4f4-f1d6-4375-97d6-18856871e1bf
> > + MODULE_TYPE = DXE_DRIVER
> > + VERSION_STRING = 1.0
> > + ENTRY_POINT = NetworkCommonEntry
> > +
> > +[Sources]
> > + DriverBinding.c
> > + DriverBinding.h
> > + ComponentName.c
> > + PxeFunction.c
> > +
> > +[Packages]
> > + MdePkg/MdePkg.dec
> > + MdeModulePkg/MdeModulePkg.dec
> > + UsbNetworkPkg/UsbNetworkPkg.dec
> > +
> > +[LibraryClasses]
> > + UefiDriverEntryPoint
> > + UefiBootServicesTableLib
> > + UefiLib
> > + DebugLib
> > + UefiUsbLib
> > + MemoryAllocationLib
> > + BaseMemoryLib
> > +
> > +[Protocols]
> > + gEfiNetworkInterfaceIdentifierProtocolGuid_31
> > + gEfiUsbIoProtocolGuid
> > + gEfiDevicePathProtocolGuid
> > + gEfiDriverBindingProtocolGuid
> > + gEdkIIUsbEthProtocolGuid
> > +
> > +[Pcd]
> > + gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting
> > + gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit
> > + gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor
> > +
> > +[Depex]
> > + TRUE
> > diff --git a/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> > new file mode 100644
> > index 0000000000..687cabca4c
> > --- /dev/null
> > +++ b/UsbNetworkPkg/NetworkCommon/PxeFunction.c
> > @@ -0,0 +1,1803 @@
> > +/** @file
> > + This file contains code for UNDI command based on UEFI specification.
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include "DriverBinding.h"
> > +
> > +// API table, defined in UEFI specification
> > +API_FUNC gUndiApiTable[] = {
> > + UndiGetState,
> > + UndiStart,
> > + UndiStop,
> > + UndiGetInitInfo,
> > + UndiGetConfigInfo,
> > + UndiInitialize,
> > + UndiReset,
> > + UndiShutdown,
> > + UndiInterruptEnable,
> > + UndiReceiveFilter,
> > + UndiStationAddress,
> > + UndiStatistics,
> > + UndiMcastIp2Mac,
> > + UndiNvData,
> > + UndiGetStatus,
> > + UndiFillHeader,
> > + UndiTransmit,
> > + UndiReceive
> > +};
> > +
> > +/**
> > + Callback function for enable Rate Limiter
> > +
> > + @param[in] Event Event whose notification function is being
> invoked
> > + @param[in] Context Pointer to the notification function's context
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +UndiRateLimiterCallback (
> > + IN EFI_EVENT Event,
> > + IN VOID *Context
> > + )
> > +{
> > + NIC_DATA *Nic = Context;
> > +
> > + if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
> > + Nic->RateLimitingCreditCount++;
> > + }
> > +}
> > +
> > +/**
> > + This command is used to determine the operational state of the UNDI.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiGetState (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + Cdb->StatFlags = Cdb->StatFlags | Nic->State;
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to change the UNDI operational state from
> stopped to started.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiStart (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_CPB_START_31 *Cpb;
> > + EFI_STATUS Status;
> > + BOOLEAN EventError;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_START) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED;
> > + return;
> > + }
> > +
> > + Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
> > +
> > + Nic->PxeStart.Delay = Cpb->Delay;
> > + Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
> > + Nic->PxeStart.Block = Cpb->Block;
> > + Nic->PxeStart.Map_Mem = 0;
> > + Nic->PxeStart.UnMap_Mem = 0;
> > + Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem;
> > + Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
> > + EventError = FALSE;
> > + Status = EFI_SUCCESS;
> > + if (Nic->RateLimitingEnable == TRUE) {
> > + Status = gBS->CreateEvent (
> > + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> > + TPL_NOTIFY,
> > + UndiRateLimiterCallback,
> > + Nic,
> > + &Nic->RateLimiter
> > + );
> > + if (!EFI_ERROR (Status)) {
> > + Status = gBS->SetTimer (
> > + Nic->RateLimiter,
> > + TimerPeriodic,
> > + Nic->RateLimitingPollTimer * 10000
> > + );
> > + if (EFI_ERROR (Status)) {
> > + EventError = TRUE;
> > + }
> > + }
> > + }
> > +
> > + if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError
> == FALSE)) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
> > + }
> > +
> > + if (!EFI_ERROR (Status)) {
> > + // Initial the state for UNDI start.
> > + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + } else {
> > + if (Nic->RateLimitingEnable == TRUE) {
> > + if (!EventError) {
> > + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> > + }
> > +
> > + if (Nic->RateLimiter) {
> > + gBS->CloseEvent (&Nic->RateLimiter);
> > + Nic->RateLimiter = 0;
> > + }
> > + }
> > +
> > + // Initial the state when UNDI start is fail
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE;
> > + }
> > +}
> > +
> > +/**
> > + This command is used to change the UNDI operational state from started
> to stopped.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiStop (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> > + return;
> > + }
> > +
> > + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN;
> > + return;
> > + }
> > +
> > + Nic->PxeStart.Delay = 0;
> > + Nic->PxeStart.Virt2Phys = 0;
> > + Nic->PxeStart.Block = 0;
> > + Nic->PxeStart.Map_Mem = 0;
> > + Nic->PxeStart.UnMap_Mem = 0;
> > + Nic->PxeStart.Sync_Mem = 0;
> > + Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED;
> > +
> > + if (Nic->RateLimitingEnable == TRUE) {
> > + gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
> > + gBS->CloseEvent (&Nic->RateLimiter);
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to retrieve initialization information that is
> > + needed by drivers and applications to initialized UNDI.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiGetInitInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_DB_GET_INIT_INFO *Db;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> > + (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> > + return;
> > + }
> > +
> > + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> > +
> > + Db->MemoryRequired = MEMORY_REQUIRE;
> > + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> > + Db->LinkSpeeds[0] = 10;
> > + Db->LinkSpeeds[1] = 100;
> > + Db->LinkSpeeds[2] = 1000;
> > + Db->LinkSpeeds[3] = 0;
> > + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> > + Db->HWaddrLen = PXE_HWADDR_LEN_ETHER;
> > + Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
> > + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> > + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> > + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> > + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> > + Db->IFtype = PXE_IFTYPE_ETHERNET;
> > + Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT;
> > + Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
> > +
> > + Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
> > + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to retrieve configuration information about
> > + the NIC being controlled by the UNDI.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiGetConfigInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_DB_GET_CONFIG_INFO *Db;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> > + (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> > + return;
> > + }
> > +
> > + Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
> > +
> > + Db->pci.BusType = PXE_BUSTYPE_USB;
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb,
> Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command resets the network adapter and initializes UNDI using
> > + the parameters supplied in the CPB.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in, out] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiInitialize (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + )
> > +{
> > + PXE_CPB_INITIALIZE *Cpb;
> > + PXE_DB_INITIALIZE *Db;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + }
> > +
> > + if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_STARTED;
> > + return;
> > + }
> > +
> > + if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
> > + (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED;
> > + return;
> > + }
> > +
> > + Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
> > + Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
> > +
> > + Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed;
> > + Nic->PxeInit.DuplexMode = Cpb->DuplexMode;
> > + Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
> > + Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr;
> > + Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
> > + Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT;
> > + Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize;
> > + Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT;
> > + Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize;
> > +
> > + Cdb->StatCode = Initialize (Cdb, Nic);
> > +
> > + Db->MemoryUsed = MEMORY_REQUIRE;
> > + Db->TxBufCnt = Nic->PxeInit.TxBufCnt;
> > + Db->TxBufSize = Nic->PxeInit.TxBufSize;
> > + Db->RxBufCnt = Nic->PxeInit.RxBufCnt;
> > + Db->RxBufSize = Nic->PxeInit.RxBufSize;
> > +
> > + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> > + Nic->CanTransmit = FALSE;
> > +
> > + if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
> > + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) &&
> (Nic->Request.Value == NETWORK_DISCONNECT)) {
> > + Nic->CableDetect = 0;
> > + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION)
> && (Nic->Request.Value == NETWORK_CONNECTED)) {
> > + Nic->CableDetect = 1;
> > + }
> > +
> > + if (Nic->CableDetect == 0) {
> > + Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
> > + }
> > + }
> > +
> > + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + } else {
> > + Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + Initialize Network interface controller data.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in, out] Nic A pointer to the Network interface controller data.
> > +
> > + @retval Status A value of Pxe statcode.
> > +
> > +**/
> > +UINT16
> > +Initialize (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + )
> > +{
> > + UINTN Status;
> > + UINT32 Index;
> > + EFI_STATUS EfiStatus;
> > +
> > + Status = MapIt (
> > + Nic,
> > + Nic->PxeInit.MemoryAddr,
> > + Nic->PxeInit.MemoryLength,
> > + TO_AND_FROM_DEVICE,
> > + (UINT64)(UINTN)&Nic->MappedAddr
> > + );
> > +
> > + if (Status != 0) {
> > + return (UINT16)Status;
> > + }
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
> > + }
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> > + }
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + Nic->BroadcastNodeAddress[Index] = 0xFF;
> > + }
> > +
> > + for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH;
> Index++) {
> > + Nic->CurrentNodeAddress[Index] = 0;
> > + Nic->PermNodeAddress[Index] = 0;
> > + Nic->BroadcastNodeAddress[Index] = 0;
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthInitialize != NULL) {
> > + EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
> > + if (EFI_ERROR (EfiStatus)) {
> > + return PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +
> > + return (UINT16)Status;
> > +}
> > +
> > +/**
> > + This command resets the network adapter and reinitializes the UNDI
> > + with the same parameters provided in the Initialize command.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiReset (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
> > + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
> > + (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
> > + Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
> > + }
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
> > + Nic->InterrupOpFlag = 0;
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + The Shutdown command resets the network adapter and leaves it in a
> > + safe state for another driver to initialize.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in, out] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiShutdown (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + Nic->CanTransmit = FALSE;
> > +
> > + Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + The Interrupt Enables command can be used to read and/or change
> > + the current external interrupt enable settings.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiInterruptEnable (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb,
> Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to read and change receive filters and,
> > + if supported, read and change the multicast MAC address filter list.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiReceiveFilter (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + UINT16 NewFilter;
> > + PXE_DB_RECEIVE_FILTERS *Db;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> > +
> > + switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
> > + case PXE_OPFLAGS_RECEIVE_FILTER_READ:
> > + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + }
> > +
> > + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST)
> == 0) {
> > + if ((Cdb->DBsize != 0)) {
> > + Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
> > + CopyMem (Db, &Nic->McastList, Nic->McastCount);
> > + }
> > + }
> > +
> > + break;
> > +
> > + case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
> > + if (NewFilter == 0) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +
> > + if (Cdb->CPBsize != 0) {
> > + if (((NewFilter &
> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
> > + ((NewFilter &
> PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> > + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) !=
> 0) ||
> > + ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +
> > + if ((Cdb->OpFlags &
> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
> > + if (((Cdb->OpFlags &
> PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
> > + ((Cdb->OpFlags &
> PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +
> > + if ((Cdb->CPBsize == 0)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +
> > + Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb-
> >CPBsize);
> > + break;
> > +
> > + case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
> > + if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + }
> > +
> > + break;
> > +
> > + default:
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + }
> > +
> > + Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + Set PXE receive filter.
> > +
> > + @param[in] Nic A pointer to the Network interface controller data.
> > + @param[in] SetFilter PXE receive filter
> > + @param[in] CpbAddr Command Parameter Block Address
> > + @param[in] CpbSize Command Parameter Block Size
> > +
> > +**/
> > +UINT16
> > +SetFilter (
> > + IN NIC_DATA *Nic,
> > + IN UINT16 SetFilter,
> > + IN UINT64 CpbAddr,
> > + IN UINT32 CpbSize
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 *McastList;
> > + UINT8 Count;
> > + UINT8 Index1;
> > + UINT8 Index2;
> > + PXE_CPB_RECEIVE_FILTERS *Cpb;
> > + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> > +
> > + Count = 0;
> > + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> > +
> > + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> > + Nic->RxFilter = (UINT8)SetFilter;
> > +
> > + if (((SetFilter &
> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb !=
> NULL)) {
> > + if (Cpb != NULL) {
> > + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> > + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> > + }
> > +
> > + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth,
> &UsbEthFunDescriptor);
> > + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> > + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> > + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> > + } else {
> > + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6,
> (VOID **)&McastList);
> > + if (EFI_ERROR (Status)) {
> > + return PXE_STATCODE_INVALID_PARAMETER;
> > + }
> > +
> > + if (Cpb != NULL) {
> > + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> > + for (Index2 = 0; Index2 < 6; Index2++) {
> > + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> > + }
> > + }
> > + }
> > +
> > + Nic->RxFilter |=
> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> > + if (Cpb != NULL) {
> > + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount,
> McastList);
> > + }
> > +
> > + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> > + FreePool (McastList);
> > + }
> > + }
> > +
> > + return PXE_STATCODE_SUCCESS;
> > +}
> > +
> > +/**
> > + This command is used to get current station and broadcast MAC
> addresses
> > + and, if supported, to change the current station MAC address.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiStationAddress (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_CPB_STATION_ADDRESS *Cpb;
> > + PXE_DB_STATION_ADDRESS *Db;
> > + UINT16 Index;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
> > + if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic-
> >PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
> > + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> > + Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
> > + }
> > + }
> > + }
> > +
> > + if (Cdb->CPBaddr != 0) {
> > + Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
> > + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> > + Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
> > + }
> > + }
> > +
> > + if (Cdb->DBaddr != 0) {
> > + Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
> > + for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
> > + Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index];
> > + Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
> > + Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
> > + }
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb,
> Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to read and clear the NIC traffic statistics.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiStatistics (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
> > + (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + Return data for DB data.
> > +
> > + @param[in] Nic A pointer to the Network interface controller data.
> > + @param[in] DbAddr Data Block Address.
> > + @param[in] DbSize Data Block Size.
> > +
> > +**/
> > +UINT16
> > +Statistics (
> > + IN NIC_DATA *Nic,
> > + IN UINT64 DbAddr,
> > + IN UINT16 DbSize
> > + )
> > +{
> > + PXE_DB_STATISTICS *DbStatistic;
> > + EFI_STATUS Status;
> > +
> > + DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
> > +
> > + if (DbSize == 0) {
> > + return PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + DbStatistic->Supported = 0x802;
> > + DbStatistic->Data[0x01] = Nic->RxFrame;
> > + DbStatistic->Data[0x0B] = Nic->TxFrame;
> > +
> > + if (Nic->UsbEth->UsbEthStatistics != NULL) {
> > + Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
> > + if (EFI_ERROR (Status)) {
> > + return PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +
> > + return PXE_STATCODE_SUCCESS;
> > +}
> > +
> > +/**
> > + Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
> > +
> > + @param[in, out] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiMcastIp2Mac (
> > + IN OUT PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_CPB_MCAST_IP_TO_MAC *Cpb;
> > + PXE_DB_MCAST_IP_TO_MAC *Db;
> > + UINT8 *Tmp;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
> > + (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
> > + Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> > + return;
> > + }
> > +
> > + Tmp = (UINT8 *)(&Cpb->IP.IPv4);
> > +
> > + if ((Tmp[0] & 0xF0) != 0xE0) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CPB;
> > + }
> > +
> > + Db->MAC[0] = 0x01;
> > + Db->MAC[1] = 0x00;
> > + Db->MAC[2] = 0x5E;
> > + Db->MAC[3] = Tmp[1] & 0x7F;
> > + Db->MAC[4] = Tmp[2];
> > + Db->MAC[5] = Tmp[3];
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to read and write (if supported by NIC H/W)
> > + nonvolatile storage on the NIC.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiNvData (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command returns the current interrupt status and/or the
> > + transmitted buffer addresses and the current media status.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiGetStatus (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_DB_GET_STATUS *Db;
> > + PXE_DB_GET_STATUS TmpGetStatus;
> > + UINT16 NumEntries;
> > + UINTN Index;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
> > + (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + TmpGetStatus.RxFrameLen = 0;
> > + TmpGetStatus.reserved = 0;
> > + Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
> > +
> > + if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
> > + CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
> > + } else {
> > + CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
> > + }
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
> > + if (Cdb->DBsize == 0) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + NumEntries = Cdb->DBsize - sizeof (UINT64);
> > + Cdb->DBsize = sizeof (UINT32) * 2;
> > +
> > + for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -=
> sizeof (UINT64)) {
> > + if (Nic->TxBufferCount > 0) {
> > + Nic->TxBufferCount--;
> > + Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
> > + }
> > + }
> > + }
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
> > + if (Nic->ReceiveStatus != 0) {
> > + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
> > + }
> > + }
> > +
> > + if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) &&
> (Nic->Request.Value == NETWORK_DISCONNECT)) {
> > + Nic->CableDetect = 0;
> > + } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION)
> && (Nic->Request.Value == NETWORK_CONNECTED)) {
> > + Nic->CableDetect = 1;
> > + }
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
> > + if (Nic->CableDetect == 0) {
> > + Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
> > + }
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + This command is used to fill the media header(s) in transmit packet(s).
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiFillHeader (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + PXE_CPB_FILL_HEADER *CpbFillHeader;
> > + PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill;
> > + EthernetHeader *MacHeader;
> > + UINTN Index;
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + return;
> > + }
> > +
> > + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
> > + CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb-
> >CPBaddr;
> > +
> > + if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen <
> PXE_MAC_HEADER_LEN_ETHER)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + MacHeader = (EthernetHeader *)(UINTN)CpbFill-
> >FragDesc[0].FragAddr;
> > + MacHeader->Protocol = CpbFill->Protocol;
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
> > + MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index];
> > + }
> > + } else {
> > + CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
> > +
> > + MacHeader = (EthernetHeader *)(UINTN)CpbFillHeader-
> >MediaHeader;
> > + MacHeader->Protocol = CpbFillHeader->Protocol;
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
> > + MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index];
> > + }
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + The Transmit command is used to place a packet into the transmit queue.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiTransmit (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
> > + (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
> > + (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + return;
> > + }
> > +
> > + if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +
> > + return;
> > + }
> > +
> > + Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
> > +
> > + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +}
> > +
> > +/**
> > + Use USB Ethernet Protocol Bulk out command to transmit data.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in, out] Nic A pointer to the Network interface controller data.
> > + @param[in] CpbAddr Command Parameter Block Address.
> > + @param[in] OpFlags Operation Flags.
> > +
> > +**/
> > +UINT16
> > +Transmit (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic,
> > + IN UINT64 CpbAddr,
> > + IN UINT16 OpFlags
> > + )
> > +{
> > + EFI_STATUS Status;
> > + PXE_CPB_TRANSMIT *Cpb;
> > + UINT64 BulkOutData;
> > + UINTN DataLength;
> > + UINTN TransmitLength;
> > + UINTN Map;
> > + UINT32 Counter;
> > + UINT16 StatCode;
> > +
> > + BulkOutData = 0;
> > + Counter = 0;
> > + Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
> > +
> > + if (Nic->CanTransmit) {
> > + return PXE_STATCODE_BUSY;
> > + }
> > +
> > + Nic->CanTransmit = TRUE;
> > +
> > + if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
> > + return PXE_STATCODE_INVALID_PARAMETER;
> > + }
> > +
> > + Map = MapIt (
> > + Nic,
> > + Cpb->FrameAddr,
> > + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> > + TO_DEVICE,
> > + (UINT64)(UINTN)&BulkOutData
> > + );
> > +
> > + if (Map != 0) {
> > + Nic->CanTransmit = FALSE;
> > + return PXE_STATCODE_INVALID_PARAMETER;
> > + }
> > +
> > + if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
> > + Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
> > + Nic->TxBufferCount++;
> > + }
> > +
> > + DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
> > +
> > + while (1) {
> > + if (Counter >= 3) {
> > + StatCode = PXE_STATCODE_BUSY;
> > + break;
> > + }
> > +
> > + TransmitLength = DataLength;
> > +
> > + Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID
> *)(UINTN)BulkOutData, &TransmitLength);
> > + if (EFI_ERROR (Status)) {
> > + StatCode = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +
> > + if (Status == EFI_INVALID_PARAMETER) {
> > + StatCode = PXE_STATCODE_INVALID_PARAMETER;
> > + break;
> > + }
> > +
> > + if (Status == EFI_DEVICE_ERROR) {
> > + StatCode = PXE_STATCODE_DEVICE_FAILURE;
> > + break;
> > + }
> > +
> > + if (!EFI_ERROR (Status)) {
> > + Nic->TxFrame++;
> > + StatCode = PXE_STATCODE_SUCCESS;
> > + break;
> > + }
> > +
> > + Counter++;
> > + }
> > +
> > + UnMapIt (
> > + Nic,
> > + Cpb->FrameAddr,
> > + Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
> > + TO_DEVICE,
> > + BulkOutData
> > + );
> > +
> > + Nic->CanTransmit = FALSE;
> > +
> > + return StatCode;
> > +}
> > +
> > +/**
> > + When the network adapter has received a frame, this command is used
> > + to copy the frame into driver/application storage.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > +**/
> > +VOID
> > +UndiReceive (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
> > + (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
> > + (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
> > + (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
> > + (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
> > + (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
> > + (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
> > + {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_INVALID_CDB;
> > + return;
> > + } else {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
> > + Cdb->StatCode = PXE_STATCODE_SUCCESS;
> > + }
> > +
> > + if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED;
> > + return;
> > + }
> > +
> > + if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
> > + Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +
> > + return;
> > + }
> > +
> > + Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
> > +
> > + if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
> > + Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
> > + }
> > +}
> > +
> > +/**
> > + Use USB Ethernet Protocol Bulk in command to receive data.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in, out] Nic A pointer to the Network interface controller data.
> > + @param[in] CpbAddr Command Parameter Block Address.
> > + @param[in, out] DbAddr Data Block Address.
> > +
> > +**/
> > +UINT16
> > +Receive (
> > + IN PXE_CDB *Cdb,
> > + IN OUT NIC_DATA *Nic,
> > + IN UINT64 CpbAddr,
> > + IN OUT UINT64 DbAddr
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN Index;
> > + PXE_FRAME_TYPE FrameType;
> > + PXE_CPB_RECEIVE *Cpb;
> > + PXE_DB_RECEIVE *Db;
> > + NIC_DEVICE *NicDevice;
> > + UINT8 *BulkInData;
> > + UINTN DataLength;
> > + EthernetHeader *Header;
> > + EFI_TPL OriginalTpl;
> > +
> > + FrameType = PXE_FRAME_TYPE_NONE;
> > + NicDevice = UNDI_DEV_FROM_NIC (Nic);
> > + BulkInData = NicDevice->ReceiveBuffer;
> > + DataLength = (UINTN)Nic->MaxSegmentSize;
> > + Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
> > + Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
> > +
> > + if (!BulkInData) {
> > + return PXE_STATCODE_INVALID_PARAMETER;
> > + }
> > +
> > + if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable ==
> TRUE)) {
> > + return PXE_STATCODE_NO_DATA;
> > + }
> > +
> > + Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID
> *)BulkInData, &DataLength);
> > + if (EFI_ERROR (Status)) {
> > + Nic->ReceiveStatus = 0;
> > + if (Nic->RateLimitingEnable == TRUE) {
> > + OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
> > + if (Nic->RateLimitingCreditCount != 0) {
> > + Nic->RateLimitingCreditCount--;
> > + }
> > +
> > + gBS->RestoreTPL (OriginalTpl);
> > + }
> > +
> > + return PXE_STATCODE_NO_DATA;
> > + }
> > +
> > + Nic->RxFrame++;
> > +
> > + if (DataLength != 0) {
> > + if (DataLength > Cpb->BufferLen) {
> > + DataLength = (UINTN)Cpb->BufferLen;
> > + }
> > +
> > + CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData,
> DataLength);
> > +
> > + Header = (EthernetHeader *)BulkInData;
> > +
> > + Db->FrameLen = (UINT32)DataLength;
> > + Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
> > + break;
> > + }
> > + }
> > +
> > + if (Index >= PXE_HWADDR_LEN_ETHER) {
> > + FrameType = PXE_FRAME_TYPE_UNICAST;
> > + } else {
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index])
> {
> > + break;
> > + }
> > + }
> > +
> > + if (Index >= PXE_HWADDR_LEN_ETHER) {
> > + FrameType = PXE_FRAME_TYPE_BROADCAST;
> > + } else {
> > + if ((Header->DestAddr[0] & 1) == 1) {
> > + FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
> > + } else {
> > + FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
> > + }
> > + }
> > + }
> > +
> > + Db->Type = FrameType;
> > + Db->Protocol = Header->Protocol;
> > +
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + Db->SrcAddr[Index] = Header->SrcAddr[Index];
> > + Db->DestAddr[Index] = Header->DestAddr[Index];
> > + }
> > + }
> > +
> > + if (FrameType == PXE_FRAME_TYPE_NONE) {
> > + Nic->ReceiveStatus = 0;
> > + } else {
> > + Nic->ReceiveStatus = 1;
> > + }
> > +
> > + return PXE_STATCODE_SUCCESS;
> > +}
> > +
> > +/**
> > + Fill out PXE SW UNDI structure.
> > +
> > + @param[out] PxeSw A pointer to the PXE SW UNDI structure.
> > +
> > +**/
> > +VOID
> > +PxeStructInit (
> > + OUT PXE_SW_UNDI *PxeSw
> > + )
> > +{
> > + PxeSw->Signature = PXE_ROMID_SIGNATURE;
> > + PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI);
> > + PxeSw->Fudge = 0;
> > + PxeSw->IFcnt = 0;
> > + PxeSw->IFcntExt = 0;
> > + PxeSw->Rev = PXE_ROMID_REV;
> > + PxeSw->MajorVer = PXE_ROMID_MAJORVER;
> > + PxeSw->MinorVer = PXE_ROMID_MINORVER;
> > + PxeSw->reserved1 = 0;
> > +
> > + PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
> > + PXE_ROMID_IMP_FRAG_SUPPORTED |
> > + PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
> > + PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
> > +
> PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
> > + PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
> > + PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
> > + PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
> > +
> > + PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry;
> > + PxeSw->reserved2[0] = 0;
> > + PxeSw->reserved2[1] = 0;
> > + PxeSw->reserved2[2] = 0;
> > + PxeSw->BusCnt = 1;
> > + PxeSw->BusType[0] = PXE_BUSTYPE_USB;
> > + PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw,
> PxeSw->Len);
> > +}
> > +
> > +/**
> > + Update NIC number.
> > +
> > + @param[in] Nic A pointer to the Network interface controller data.
> > + @param[in, out] PxeSw A pointer to the PXE SW UNDI structure.
> > +
> > +**/
> > +VOID
> > +UpdateNicNum (
> > + IN NIC_DATA *Nic,
> > + IN OUT PXE_SW_UNDI *PxeSw
> > + )
> > +{
> > + UINT16 NicNum;
> > +
> > + NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
> > +
> > + if (Nic == NULL) {
> > + if (NicNum > 0) {
> > + NicNum--;
> > + }
> > +
> > + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> > + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> > + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID
> *)PxeSw, PxeSw->Len));
> > + return;
> > + }
> > +
> > + NicNum++;
> > +
> > + PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte
> > + PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
> > + PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID
> *)PxeSw, PxeSw->Len));
> > +}
> > +
> > +/**
> > + UNDI API table entry.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UndiApiEntry (
> > + IN UINT64 Cdb
> > + )
> > +{
> > + PXE_CDB *CdbPtr;
> > + NIC_DATA *Nic;
> > +
> > + if (Cdb == 0) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + CdbPtr = (PXE_CDB *)(UINTN)Cdb;
> > + Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
> > + gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Map virtual memory address for DMA. This field can be set to
> > + zero if there is no mapping service.
> > +
> > + @param[in] Nic A pointer to the Network interface controller data.
> > + @param[in] MemAddr Virtual address to be mapped.
> > + @param[in] Size Size of memory to be mapped.
> > + @param[in] Direction Direction of data flow for this memory's usage:
> > + cpu->device, device->cpu or both ways.
> > + @param[out] MappedAddr Pointer to return the mapped device
> address.
> > +
> > +**/
> > +UINTN
> > +MapIt (
> > + IN NIC_DATA *Nic,
> > + IN UINT64 MemAddr,
> > + IN UINT32 Size,
> > + IN UINT32 Direction,
> > + OUT UINT64 MappedAddr
> > + )
> > +{
> > + UINT64 *PhyAddr;
> > +
> > + PhyAddr = (UINT64 *)(UINTN)MappedAddr;
> > +
> > + if (Nic->PxeStart.Map_Mem == 0) {
> > + *PhyAddr = MemAddr;
> > + } else {
> > + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic-
> >PxeStart.Map_Mem)(
> > + Nic->PxeStart.Unique_ID,
> > + MemAddr,
> > + Size,
> > + Direction,
> > + MappedAddr
> > + );
> > + }
> > +
> > + return PXE_STATCODE_SUCCESS;
> > +}
> > +
> > +/**
> > + Un-map previously mapped virtual memory address. This field can be set
> > + to zero only if the Map_Mem() service is also set to zero.
> > +
> > + @param[in] Nic A pointer to the Network interface controller data.
> > + @param[in] MemAddr Virtual address to be mapped.
> > + @param[in] Size Size of memory to be mapped.
> > + @param[in] Direction Direction of data flow for this memory's usage:
> > + cpu->device, device->cpu or both ways.
> > + @param[in] MappedAddr Pointer to return the mapped device
> address.
> > +
> > +**/
> > +VOID
> > +UnMapIt (
> > + IN NIC_DATA *Nic,
> > + IN UINT64 MemAddr,
> > + IN UINT32 Size,
> > + IN UINT32 Direction,
> > + IN UINT64 MappedAddr
> > + )
> > +{
> > + if (Nic->PxeStart.UnMap_Mem != 0) {
> > + ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic-
> >PxeStart.UnMap_Mem)(
> > + Nic->PxeStart.Unique_ID,
> > + MemAddr,
> > + Size,
> > + Direction,
> > + MappedAddr
> > + );
> > + }
> > +
> > + return;
> > +}
> > diff --git a/UsbNetworkPkg/ReadMe.md b/UsbNetworkPkg/ReadMe.md
> > new file mode 100644
> > index 0000000000..cb70684f0b
> > --- /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/UsbNetworkPkg.ci.yaml
> b/UsbNetworkPkg/UsbNetworkPkg.ci.yaml
> > new file mode 100644
> > index 0000000000..7ee1ef3cf0
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkg.ci.yaml
> > @@ -0,0 +1,65 @@
> > +## @file
> > +# CI configuration for UsbNetworkPkg
> > +#
> > +# Copyright (c) Microsoft Corporation
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +{
> > + ## options defined .pytool/Plugin/LicenseCheck
> > + "LicenseCheck": {
> > + "IgnoreFiles": []
> > + },
> > + "EccCheck": {
> > + ## Exception sample looks like below:
> > + ## "ExceptionList": [
> > + ## "<ErrorID>", "<KeyWord>"
> > + ## ]
> > + "ExceptionList": [
> > + ],
> > + ## Both file path and directory path are accepted.
> > + "IgnoreFiles": [
> > + ]
> > + },
> > + "CompilerPlugin": {
> > + "DscPath": "UsbNetworkPkg.dsc"
> > + },
> > + "CharEncodingCheck": {
> > + "IgnoreFiles": []
> > + },
> > + "DependencyCheck": {
> > + "AcceptableDependencies": [
> > + "MdePkg/MdePkg.dec",
> > + "MdeModulePkg/MdeModulePkg.dec",
> > + "NetworkPkg/NetworkPkg.dec"
> > + ],
> > + # For host based unit tests
> > + "AcceptableDependencies-HOST_APPLICATION":[],
> > + # For UEFI shell based apps
> > + "AcceptableDependencies-UEFI_APPLICATION":[],
> > + "IgnoreInf": []
> > + },
> > + "DscCompleteCheck": {
> > + "DscPath": "UsbNetworkPkg.dsc",
> > + "IgnoreInf": []
> > + },
> > + "GuidCheck": {
> > + "IgnoreGuidName": [],
> > + "IgnoreGuidValue": [],
> > + "IgnoreFoldersAndFiles": []
> > + },
> > +
> > + ## options defined .pytool/Plugin/LibraryClassCheck
> > + "LibraryClassCheck": {
> > + "IgnoreHeaderFile": []
> > + },
> > +
> > + ## options defined .pytool/Plugin/SpellCheck
> > + "SpellCheck": {
> > + "AuditOnly": True, # Fails test but run in AuditOnly mode to
> collect log
> > + "IgnoreFiles": [], # use gitignore syntax to ignore errors in
> matching files
> > + "ExtendWords": [], # words to extend to the dictionary for this
> package
> > + "IgnoreStandardPaths": [], # Standard Plugin defined paths that
> should be ignore
> > + "AdditionalIncludePaths": [] # Additional paths to spell check
> (wildcards supported)
> > + }
> > +}
> > diff --git a/UsbNetworkPkg/UsbNetworkPkg.dec
> b/UsbNetworkPkg/UsbNetworkPkg.dec
> > new file mode 100644
> > index 0000000000..30e4e4c8aa
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkg.dec
> > @@ -0,0 +1,46 @@
> > +## @file
> > +# This package defines Usb network specific interfaces and library classes
> > +# as well as configuration for standard edk2 packages.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > +[Defines]
> > + DEC_SPECIFICATION = 0x00010005
> > + PACKAGE_NAME = UsbNetworkPkg
> > + PACKAGE_GUID = abfab91e-37ea-4cb4-80a6-563dbb0bcec6
> > + PACKAGE_VERSION = 0.1
> > +
> > +[Includes]
> > + Include
> > +
> > +[Protocols]
> > + ## Include/Protocol/EdkIIUsbEthernet.h
> > + gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a,
> 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
> > +
> > +[Guids]
> > + ## Usb Network package token space GUID
> > + gUsbNetworkPkgTokenSpaceGuid = { 0xA1231E82, 0x21B8, 0x4204,
> { 0x92, 0xBB, 0x37, 0x3A, 0xFB, 0x01, 0xC6, 0xA1 } }
> > +
> > +[PcdsFeatureFlag]
> > +
> > + ## Set the PCD 'UsbCdcEcmSupport' to 'TRUE' if 'Usb Cdc Ecm device'
> need to be enabled.
> > +
> gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE|BOOLEAN|0x
> 00000001
> > +
> > + ## Set the PCD 'UsbCdcNcmSupport' to 'TRUE' if 'Usb Cdc Ncm device'
> need to be enabled.
> > +
> gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE|BOOLEAN|0x
> 00000002
> > +
> > + ## Set the PCD 'UsbRndisSupport' to 'TRUE' if 'Usb Rndis device' need to
> be enabled.
> > +
> gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE|BOOLEAN|0x000
> 00003
> > +
> > +[PcdsFixedAtBuild, PcdsPatchableInModule]
> > + ## Support rate limiting
> > +
> gUsbNetworkPkgTokenSpaceGuid.EnableRateLimiting|FALSE|BOOLEAN|0x0
> 0010001
> > +
> > + ## The rate limiting Credit value is check in rate limiter event.
> > + # It is to control the RateLimitingCreditCount max value.
> > +
> gUsbNetworkPkgTokenSpaceGuid.RateLimitingCredit|10|UINT32|0x0001000
> 2
> > +
> > + ## The value of rate limiter event for timeout check. Default value is
> 100(unit 1ms).
> > +
> gUsbNetworkPkgTokenSpaceGuid.RateLimitingFactor|100|UINT32|0x000100
> 03
> > diff --git a/UsbNetworkPkg/UsbNetworkPkg.dsc
> b/UsbNetworkPkg/UsbNetworkPkg.dsc
> > new file mode 100644
> > index 0000000000..c2bbfcb2db
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkg.dsc
> > @@ -0,0 +1,50 @@
> > +## @file
> > +# Global DSC definitions to be included into project DSC file.
> > +#
> > +# Copyright (c) 1985 - 2023, AMI. All rights reserved.<BR>
> > +# Subject to AMI licensing agreement.
> > +##
> > +
> > +[Defines]
> > + PLATFORM_NAME = NetworkPkg
> > + PLATFORM_GUID = C5995C1C-1E5C-43F9-826D-27E43A7243B8
> > + PLATFORM_VERSION = 1
> > + DSC_SPECIFICATION = 0x00010005
> > + OUTPUT_DIRECTORY = Build/UsbNetworkPkg
> > + SUPPORTED_ARCHITECTURES =
> IA32|X64|EBC|ARM|AARCH64|RISCV64|LOONGARCH64
> > + BUILD_TARGETS = DEBUG|RELEASE|NOOPT
> > + SKUID_IDENTIFIER = DEFAULT
> > +
> > +[PcdsFeatureFlag]
> > + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|TRUE
> > + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|TRUE
> > + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> > +
> > +!include MdePkg/MdeLibs.dsc.inc
> > +
> > +[LibraryClasses]
> > + #
> > + # Entry Point Libraries
> > + #
> > +
> UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry
> Point.inf
> > + #
> > + # Common Libraries
> > + #
> > + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> > + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> > + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> > + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> > + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> > +
> MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemo
> ryAllocationLib.inf
> > +
> UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBo
> otServicesTableLib.inf
> > +
> UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib
> /UefiRuntimeServicesTableLib.inf
> > + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
> > +
> DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/Bas
> eDebugPrintErrorLevelLib.inf
> > +
> DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> > + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
> > +
> > +[Components]
> > +!include UsbNetworkPkg/UsbNetworkPkg.dsc.inc
> > +
> > +[BuildOptions]
> > + *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
> > diff --git a/UsbNetworkPkg/UsbNetworkPkg.dsc.inc
> b/UsbNetworkPkg/UsbNetworkPkg.dsc.inc
> > new file mode 100644
> > index 0000000000..f5df11ace6
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkg.dsc.inc
> > @@ -0,0 +1,27 @@
> > +## @file
> > +# Global DSC definitions to be included into project DSC file.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > +[Defines]
> > +
> > +!ifndef PLATFORMX64_ENABLE
> > + #
> > + # PLATFORMX64_ENABLE is set to TRUE when PEI is IA32 and DXE is X64
> platform
> > + #
> > + DEFINE PLATFORMX64_ENABLE = FALSE
> > +!endif
> > +
> > +!include UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc
> > +
> > +!if $(PLATFORMX64_ENABLE) == TRUE
> > +[Components.X64]
> > +!include UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc
> > +
> > +!else
> > +[Components.IA32, Components.X64, Components.ARM,
> Components.AARCH64, Components.RISCV64, Components.LOONGARCH64]
> > +!include UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc
> > +
> > +!endif
> > diff --git a/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc
> b/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc
> > new file mode 100644
> > index 0000000000..544df8404c
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.dsc.inc
> > @@ -0,0 +1,20 @@
> > +## @file
> > +# List of Core Components.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > + UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> > +
> > +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> > + UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> > +!endif
> > +
> > +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> > + UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> > +!endif
> > +
> > +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> > + UsbNetworkPkg/UsbRndis/UsbRndis.inf
> > +!endif
> > diff --git a/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc
> b/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc
> > new file mode 100644
> > index 0000000000..10616d97ed
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkgComponentsDxe.fdf.inc
> > @@ -0,0 +1,20 @@
> > +## @file
> > +# List of Core Components.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > + INF UsbNetworkPkg/NetworkCommon/NetworkCommon.inf
> > +
> > +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport
> > + INF UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
> > +!endif
> > +
> > +!if gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport
> > + INF UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
> > +!endif
> > +
> > +!if gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport
> > + INF UsbNetworkPkg/UsbRndis/UsbRndis.inf
> > +!endif
> > diff --git a/UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc
> b/UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc
> > new file mode 100644
> > index 0000000000..51382d18d3
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbNetworkPkgPcds.dsc.inc
> > @@ -0,0 +1,14 @@
> > +## @file
> > +# Global switches enable/disable project features.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > +[Packages]
> > + UsbNetworkPkg/UsbNetworkPkg.dec
> > +
> > +[PcdsFeatureFlag]
> > + gUsbNetworkPkgTokenSpaceGuid.UsbCdcEcmSupport|FALSE
> > + gUsbNetworkPkgTokenSpaceGuid.UsbCdcNcmSupport|FALSE
> > + gUsbNetworkPkgTokenSpaceGuid.UsbRndisSupport|TRUE
> > diff --git a/UsbNetworkPkg/UsbRndis/ComponentName.c
> b/UsbNetworkPkg/UsbRndis/ComponentName.c
> > new file mode 100644
> > index 0000000000..b9ba170c13
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbRndis/ComponentName.c
> > @@ -0,0 +1,172 @@
> > +/** @file
> > + This file contains code for USB RNDIS Driver Component
> > + Name definitions
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include "UsbRndis.h"
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> gUsbRndisDriverNameTable[] = {
> > + {
> > + "eng;en",
> > + L"USB RNDIS Driver"
> > + },
> > + {
> > + NULL,
> > + NULL
> > + }
> > +};
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_HANDLE ChildHandle OPTIONAL,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > + );
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME_PROTOCOL gUsbRndisComponentName = {
> > + UsbRndisComponentNameGetDriverName,
> > + UsbRndisComponentNameGetControllerName,
> > + "eng"
> > +};
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME2_PROTOCOL gUsbRndisComponentName2 = {
> > +
> (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbRndisComponentNam
> eGetDriverName,
> > +
> (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbRndisComponent
> NameGetControllerName,
> > + "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..92830771e4
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.c
> > @@ -0,0 +1,886 @@
> > +/** @file
> > + This file contains code for USB Remote Network Driver
> > + Interface Spec. Driver Binding
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include "UsbRndis.h"
> > +
> > +EFI_DRIVER_BINDING_PROTOCOL gUsbRndisDriverBinding = {
> > + UsbRndisDriverSupported,
> > + UsbRndisDriverStart,
> > + UsbRndisDriverStop,
> > + USB_RNDIS_DRIVER_VERSION,
> > + NULL,
> > + NULL
> > +};
> > +
> > +/**
> > + Check if this interface is USB Rndis SubType
> > +
> > + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> > +
> > + @retval TRUE USB Rndis SubType.
> > + @retval FALSE Not USB Rndis SubType.
> > +
> > +**/
> > +BOOLEAN
> > +IsSupportedDevice (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
> &InterfaceDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + // Check specific device/RNDIS and CDC-DATA
> > + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> > + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0x1)) || \
> > + ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0x00))
> > + )
> > + {
> > + return TRUE;
> > + }
> > +
> > + return FALSE;
> > +}
> > +
> > +/**
> > + Check if this interface is USB Rndis SubType but not CDC Data interface
> > +
> > + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> > +
> > + @retval TRUE USB Rndis SubType.
> > + @retval FALSE Not USB Rndis SubType.
> > +**/
> > +BOOLEAN
> > +IsRndisInterface (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
> &InterfaceDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + // Check for specific device/RNDIS and CDC-DATA
> > + if (((InterfaceDescriptor.InterfaceClass == 0x2) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0xFF)) || \
> > + ((InterfaceDescriptor.InterfaceClass == 0xEF) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x4) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0x1))
> > + )
> > + {
> > + return TRUE;
> > + }
> > +
> > + return FALSE;
> > +}
> > +
> > +/**
> > + Check if the USB RNDIS and USB CDC Data interfaces are from the same
> device.
> > +
> > + @param[in] UsbRndisDataPath A pointer to the
> EFI_DEVICE_PATH_PROTOCOL instance.
> > + @param[in] UsbCdcDataPath A pointer to the
> EFI_DEVICE_PATH_PROTOCOL instance.
> > +
> > + @retval EFI_SUCCESS Is the same device.
> > + @retval EFI_UNSUPPORTED Is not the same device.
> > +
> > +**/
> > +EFI_STATUS
> > +IsSameDevice (
> > + IN EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath,
> > + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath
> > + )
> > +{
> > + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Entry \n"));
> > + while (1) {
> > + if (IsDevicePathEnd (NextDevicePathNode (UsbRndisDataPath))) {
> > + if (((USB_DEVICE_PATH *)UsbRndisDataPath)->ParentPortNumber ==
> > + ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
> > + {
> > + return EFI_SUCCESS;
> > + } else {
> > + return EFI_UNSUPPORTED;
> > + }
> > + } else {
> > + if (CompareMem (UsbCdcDataPath, UsbRndisDataPath, sizeof
> (EFI_DEVICE_PATH_PROTOCOL)) != 0) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + UsbRndisDataPath = NextDevicePathNode (UsbRndisDataPath);
> > + UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
> > + }
> > + }
> > +
> > + DEBUG ((DEBUG_VERBOSE, "IsSameDevice Exit \n"));
> > +}
> > +
> > +/**
> > + Check if the USB CDC Data(UsbIo) installed and return USB CDC Data
> Handle.
> > +
> > + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> > +
> > + @retval TRUE USB CDC Data(UsbIo) installed.
> > + @retval FALSE USB CDC Data(UsbIo) did not installed.
> > +
> > +**/
> > +BOOLEAN
> > +IsUsbCdcData (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
> &InterfaceDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + // Check for CDC-DATA
> > + if ((InterfaceDescriptor.InterfaceClass == 0xA) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x0) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0x0))
> > + {
> > + return TRUE;
> > + }
> > +
> > + return FALSE;
> > +}
> > +
> > +/**
> > + Check if the USB Rndis(UsbIo) installed
> > +
> > + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
> > +
> > + @retval TRUE USB Rndis(UsbIo) installed.
> > + @retval FALSE USB Rndis(UsbIo) did not installed.
> > +
> > +**/
> > +BOOLEAN
> > +IsUsbRndis (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo,
> &InterfaceDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + // Check for Rndis
> > + if ((InterfaceDescriptor.InterfaceClass == 0x2) &&
> > + (InterfaceDescriptor.InterfaceSubClass == 0x2) &&
> > + (InterfaceDescriptor.InterfaceProtocol == 0xFF))
> > + {
> > + return TRUE;
> > + }
> > +
> > + return FALSE;
> > +}
> > +
> > +/**
> > + Control comes here when a CDC device is found.Check if a RNDIS
> interface is already found for this device or not.
> > + For one device two USBIO will be installed each for CDC and RNDIS
> interface.
> > +
> > + @param[in] UsbEthPath A pointer to the
> EFI_DEVICE_PATH_PROTOCOL instance.
> > + @param[out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
> Data.
> > +
> > + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC
> Data is found.
> > + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this
> CDC Data is not found.
> > +
> > +**/
> > +EFI_STATUS
> > +UpdateRndisDevice (
> > + IN EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath,
> > + OUT USB_RNDIS_DEVICE **UsbRndisDevice
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN Index;
> > + UINTN HandleCount;
> > + EFI_HANDLE *HandleBuffer;
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + BOOLEAN IsRndisInterfaceFlag;
> > +
> > + IsRndisInterfaceFlag = FALSE;
> > +
> > + Status = gBS->LocateHandleBuffer (
> > + ByProtocol,
> > + &gEdkIIUsbEthProtocolGuid,
> > + NULL,
> > + &HandleCount,
> > + &HandleBuffer
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + for (Index = 0; Index < HandleCount; Index++) {
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEdkIIUsbEthProtocolGuid,
> > + (VOID **)&UsbEthDevice
> > + );
> > + if (EFI_ERROR (Status)) {
> > + continue;
> > + }
> > +
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **)&UsbIo
> > + );
> > + if (EFI_ERROR (Status)) {
> > + continue;
> > + }
> > +
> > + IsRndisInterfaceFlag = IsRndisInterface (UsbIo);
> > + if (IsRndisInterfaceFlag == FALSE) {
> > + continue;
> > + }
> > +
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbRndisDataPath
> > + );
> > + if (EFI_ERROR (Status)) {
> > + continue;
> > + }
> > +
> > + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> > +
> > + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> > +
> > + if (!EFI_ERROR (Status)) {
> > + *UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> > + FreePool (HandleBuffer);
> > + return EFI_SUCCESS;
> > + }
> > + } // End of For loop
> > +
> > + FreePool (HandleBuffer);
> > + return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +
> > + For the given Rndis Device, find a matching CDC device already exists or
> not. If found update the handle
> > + and UsbIO protocol.
> > +
> > + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
> data.
> > +
> > +**/
> > +VOID
> > +FindMatchingCdcData (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN Index;
> > + UINTN HandleCount;
> > + EFI_HANDLE *HandleBuffer;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> > +
> > + // Find the parent RNDIS and update the UsbIo for the CDC device
> > + Status = gBS->HandleProtocol (
> > + UsbRndisDevice->UsbRndisHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbRndisDataPath
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + return;
> > + }
> > +
> > + Status = gBS->LocateHandleBuffer (
> > + ByProtocol,
> > + &gEfiUsbIoProtocolGuid,
> > + NULL,
> > + &HandleCount,
> > + &HandleBuffer
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return;
> > + }
> > +
> > + for (Index = 0; Index < HandleCount; Index++) {
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **)&UsbIo
> > + );
> > + ASSERT_EFI_ERROR (Status);
> > +
> > + if (IsUsbCdcData (UsbIo)) {
> > + DEBUG ((DEBUG_VERBOSE, "Rndis FindMatchingCdcData CDCData
> interface found\n"));
> > +
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbCdcDataPath
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_VERBOSE, "Rndis CDCData DevicePath not
> found\n"));
> > + FreePool (HandleBuffer);
> > + return;
> > + }
> > +
> > + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> > + DEBUG ((DEBUG_VERBOSE, "Rndis IsSameDevice %r\n", Status));
> > + if (!EFI_ERROR (Status)) {
> > + UsbRndisDevice->UsbCdcDataHandle = HandleBuffer[Index];
> > + UsbRndisDevice->UsbIoCdcData = UsbIo;
> > + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> > + FreePool (HandleBuffer);
> > + return;
> > + }
> > + }
> > + } // End of For loop
> > +
> > + FreePool (HandleBuffer);
> > +}
> > +
> > +/**
> > +
> > + For the given UsbIo CdcData, find a matching RNDIS device already exists
> or not.
> > +
> > + @param[in] CdcHandle A pointer to the EFI_HANDLE for USB CDC
> Data.
> > + @param[out] CdcUsbIo A pointer for retrieve the
> EFI_USB_IO_PROTOCOL instance.
> > + @param[out] RndisHandle A pointer for retrieve the handle of RNDIS
> device.
> > +
> > + @retval EFI_SUCCESS The USB_RNDIS_DEVICE matching this CDC
> Data is found.
> > + @retval EFI_NOT_FOUND The USB_RNDIS_DEVICE matching this
> CDC Data is not found.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +FindMatchingRndisDev (
> > + IN EFI_HANDLE CdcHandle,
> > + OUT EFI_USB_IO_PROTOCOL **CdcUsbIo,
> > + OUT EFI_HANDLE *RndisHandle
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN Index;
> > + UINTN HandleCount;
> > + EFI_HANDLE *HandleBuffer;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbRndisDataPath;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbCdcDataPath;
> > +
> > + // Find the parent RNDIS and update the UsbIo for the CDC device
> > + Status = gBS->HandleProtocol (
> > + CdcHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbCdcDataPath
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->LocateHandleBuffer (
> > + ByProtocol,
> > + &gEfiUsbIoProtocolGuid,
> > + NULL,
> > + &HandleCount,
> > + &HandleBuffer
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + for (Index = 0; Index < HandleCount; Index++) {
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **)&UsbIo
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + if (IsUsbRndis (UsbIo)) {
> > + Status = gBS->HandleProtocol (
> > + HandleBuffer[Index],
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbRndisDataPath
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Usb Rndis DevicePath not found\n"));
> > + break;
> > + }
> > +
> > + Status = IsSameDevice (UsbRndisDataPath, UsbCdcDataPath);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + *RndisHandle = HandleBuffer[Index];
> > + *CdcUsbIo = UsbIo;
> > + FreePool (HandleBuffer);
> > + return Status;
> > + }
> > + }
> > + } // End of For loop
> > +
> > + FreePool (HandleBuffer);
> > +
> > + return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > + USB Rndis Driver Binding Support.
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to test.
> > + @param[in] RemainingDevicePath Optional parameter use to pick a
> specific child
> > + device to start.
> > +
> > + @retval EFI_SUCCESS This driver supports this device.
> > + @retval EFI_ALREADY_STARTED This driver is already running on this
> device.
> > + @retval other This driver does not support this device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisDriverSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **)&UsbIo,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return Status;
> > +}
> > +
> > +/**
> > + USB RNDIS Driver Binding Start.
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to bind driver to.
> > + @param[in] RemainingDevicePath Optional parameter use to pick a
> specific child
> > + device to start.
> > +
> > + @retval EFI_SUCCESS This driver is added to ControllerHandle
> > + @retval EFI_DEVICE_ERROR This driver could not be started due to
> a device error
> > + @retval EFI_OUT_OF_RESOURCES The driver could not install
> successfully due to a lack of resources.
> > + @retval other This driver does not support this device
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisDriverStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> > + EFI_HANDLE RndisHandle;
> > +
> > + RndisHandle = ControllerHandle;
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **)&UsbIo,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID **)&UsbEthPath,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return Status;
> > + }
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > +
> > + // Controls come here for RNDIS and CDC. If it is CDC, check whether
> RNDIS is present on the same controller or not.
> > + if (IsUsbCdcData (UsbIo)) {
> > + DEBUG ((DEBUG_INFO, "Rndis CDCData interface found\n"));
> > +
> > + // Find the parent RNDIS and update the UsbIo for the CDC device
> > + Status = UpdateRndisDevice (
> > + UsbEthPath,
> > + &UsbRndisDevice
> > + );
> > +
> > + if (!EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_INFO, "Rndis Matching interface found\n"));
> > + UsbRndisDevice->UsbCdcDataHandle = ControllerHandle;
> > + UsbRndisDevice->UsbIoCdcData = UsbIo;
> > + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> > + return Status;
> > + } else {
> > + // Check if RnDis exist
> > + Status = FindMatchingRndisDev (
> > + ControllerHandle,
> > + &UsbIo,
> > + &RndisHandle
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return Status;
> > + }
> > + }
> > + }
> > +
> > + UsbRndisDevice = AllocateZeroPool (sizeof (USB_RNDIS_DEVICE));
> > +
> > + if (!UsbRndisDevice) {
> > + DEBUG ((DEBUG_ERROR, "AllocateZeroPool Fail\n"));
> > +
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + Status = LoadAllDescriptor (
> > + UsbIo,
> > + &UsbRndisDevice->Config
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:LoadAllDescriptor status = %r\n",
> __FUNCTION__, Status));
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + FreePool (UsbRndisDevice);
> > + return Status;
> > + }
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (
> > + UsbIo,
> > + &Interface
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =
> %r\n", __FUNCTION__, Status));
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + FreePool (UsbRndisDevice->Config);
> > + FreePool (UsbRndisDevice);
> > + return Status;
> > + }
> > +
> > + UsbRndisDevice->Signature = USB_RNDIS_SIGNATURE;
> > + UsbRndisDevice->NumOfInterface =
> Interface.InterfaceNumber;
> > + UsbRndisDevice->UsbRndisHandle = RndisHandle;
> > + UsbRndisDevice->UsbCdcDataHandle = 0;
> > + UsbRndisDevice->UsbIo = UsbIo;
> > + UsbRndisDevice->UsbEth.UsbEthReceive = RndisUndiReceive;
> > + UsbRndisDevice->UsbEth.UsbEthTransmit = RndisUndiTransmit;
> > + UsbRndisDevice->UsbEth.UsbEthInterrupt = UsbRndisInterrupt;
> > + UsbRndisDevice->UsbEth.UsbEthMacAddress =
> GetUsbEthMacAddress;
> > + UsbRndisDevice->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
> > + UsbRndisDevice->UsbEth.UsbHeaderFunDescriptor =
> GetUsbHeaderFunDescriptor;
> > + UsbRndisDevice->UsbEth.UsbUnionFunDescriptor =
> GetUsbUnionFunDescriptor;
> > + UsbRndisDevice->UsbEth.UsbEthFunDescriptor =
> GetUsbRndisFunDescriptor;
> > + UsbRndisDevice->UsbEth.SetUsbEthMcastFilter =
> SetUsbRndisMcastFilter;
> > + UsbRndisDevice->UsbEth.SetUsbEthPowerPatternFilter =
> SetUsbRndisPowerFilter;
> > + UsbRndisDevice->UsbEth.GetUsbEthPowerPatternFilter =
> GetUsbRndisPowerFilter;
> > + UsbRndisDevice->UsbEth.SetUsbEthPacketFilter =
> SetUsbRndisPacketFilter;
> > + UsbRndisDevice->UsbEth.GetUsbEthStatistic = GetRndisStatistic;
> > +
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetState =
> RndisDummyReturn;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStart =
> RndisUndiStart;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStop =
> RndisUndiStop;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetInitInfo =
> RndisUndiGetInitInfo;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetConfigInfo =
> RndisUndiGetConfigInfo;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInitialize =
> RndisUndiInitialize;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReset =
> RndisUndiReset;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiShutdown =
> RndisUndiShutdown;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiInterruptEnable =
> RndisDummyReturn;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceiveFilter =
> RndisUndiReceiveFilter;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStationAddress =
> RndisDummyReturn;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiStatistics = NULL;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiMcastIp2Mac =
> RndisDummyReturn;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiNvData =
> RndisDummyReturn;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiGetStatus =
> RndisUndiGetStatus;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiFillHeader =
> RndisDummyReturn;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiTransmit = NULL;
> > + UsbRndisDevice->UsbEth.UsbEthUndi.UsbEthUndiReceive = NULL;
> > +
> > + UsbRndisDevice->MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> > + UsbRndisDevice->MaxPacketsPerTransfer = 1;
> > + UsbRndisDevice->PacketAlignmentFactor = 0;
> > +
> > + InitializeListHead (&UsbRndisDevice->ReceivePacketList);
> > +
> > + // This is a RNDIS interface. See whether CDC-DATA interface has already
> been connected or not
> > + FindMatchingCdcData (UsbRndisDevice);
> > +
> > + if (UsbRndisDevice->UsbIoCdcData) {
> > + Status = gBS->InstallProtocolInterface (
> > + &ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + EFI_NATIVE_INTERFACE,
> > + &(UsbRndisDevice->UsbEth)
> > + );
> > + if (EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > +
> > + FreePool (UsbRndisDevice->Config);
> > + FreePool (UsbRndisDevice);
> > + return Status;
> > + }
> > +
> > + GetEndpoint (UsbRndisDevice->UsbIo, UsbRndisDevice);
> > +
> > + DEBUG ((DEBUG_INFO, "Rndis DeviceHandle %r\n", UsbRndisDevice-
> >UsbRndisHandle));
> > + DEBUG ((DEBUG_INFO, "CDC DeviceHandle %r\n", UsbRndisDevice-
> >UsbCdcDataHandle));
> > + return EFI_SUCCESS;
> > + }
> > +
> > + FreePool (UsbRndisDevice->Config);
> > + FreePool (UsbRndisDevice);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + CheckandStopRndisDevice
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to bind driver to.
> > +
> > + @retval EFI_SUCCESS This driver is added to ControllerHandle
> > + @retval EFI_DEVICE_ERROR This driver could not be started due to a
> device error
> > + @retval other This driver does not support this device
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CheckandStopRndisDevice (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **)&UsbIo,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + if (IsUsbRndis (UsbIo)) {
> > + Status = gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > + DEBUG ((DEBUG_ERROR, "Rndis ControllerHandle Stop %r\n", Status));
> > + return Status;
> > + }
> > +
> > + return EFI_UNSUPPORTED;
> > +}
> > +
> > +/**
> > + USB Rndis Driver Binding Stop.
> > +
> > + @param[in] This Protocol instance pointer.
> > + @param[in] ControllerHandle Handle of device to stop driver on
> > + @param[in] NumberOfChildren Number of Handles in
> ChildHandleBuffer. If number of
> > + children is zero stop the entire bus driver.
> > + @param[in] ChildHandleBuffer List of Child Handles to Stop.
> > +
> > + @retval EFI_SUCCESS This driver is removed ControllerHandle
> > + @retval other This driver was not removed from this device
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisDriverStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEthProtocol;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop ControllerHandle %lx\n",
> ControllerHandle));
> > +
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + (VOID **)&UsbEthProtocol,
> > + This->DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > + );
> > + if (EFI_ERROR (Status)) {
> > + Status = CheckandStopRndisDevice (This, ControllerHandle);
> > + return Status;
> > + }
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthProtocol);
> > +
> > + Status = gBS->CloseProtocol (
> > + UsbRndisDevice->UsbCdcDataHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + UsbRndisDevice->UsbCdcDataHandle
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:CloseProtocol status = %r\n",
> __FUNCTION__, Status));
> > + }
> > +
> > + Status = gBS->UninstallProtocolInterface (
> > + ControllerHandle,
> > + &gEdkIIUsbEthProtocolGuid,
> > + UsbEthProtocol
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + ControllerHandle
> > + );
> > +
> > + FreePool (UsbRndisDevice->Config);
> > + FreePool (UsbRndisDevice);
> > +
> > + DEBUG ((DEBUG_INFO, "UsbRndisDriverStop %r\n", Status));
> > + return Status;
> > +}
> > +
> > +/**
> > + Entrypoint of RNDIS Driver.
> > +
> > + This function is the entrypoint of RNDIS Driver. It installs Driver Binding
> > + Protocols together with Component Name Protocols.
> > +
> > + @param[in] ImageHandle The firmware allocated handle for the EFI
> image.
> > + @param[in] SystemTable A pointer to the EFI System Table.
> > +
> > + @retval EFI_SUCCESS The entry point is executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisEntry (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > + gUsbRndisDriverBinding.DriverBindingHandle = ImageHandle;
> > + gUsbRndisDriverBinding.ImageHandle = ImageHandle;
> > +
> > + return gBS->InstallMultipleProtocolInterfaces (
> > + &gUsbRndisDriverBinding.DriverBindingHandle,
> > + &gEfiDriverBindingProtocolGuid,
> > + &gUsbRndisDriverBinding,
> > + &gEfiComponentName2ProtocolGuid,
> > + &gUsbRndisComponentName2,
> > + NULL
> > + );
> > +}
> > diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.h
> b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> > new file mode 100644
> > index 0000000000..7758070424
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.h
> > @@ -0,0 +1,586 @@
> > +/** @file
> > + Header file for for USB Rndis driver
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#ifndef _USB_RNDIS_H_
> > +#define _USB_RNDIS_H_
> > +
> > +#include <Library/UefiDriverEntryPoint.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiLib.h>
> > +#include <Library/DevicePathLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/UefiUsbLib.h>
> > +#include <Protocol/UsbIo.h>
> > +#include <Protocol/EdkIIUsbEthernetProtocol.h>
> > +
> > +typedef struct _REMOTE_NDIS_MSG_HEADER
> REMOTE_NDIS_MSG_HEADER;
> > +
> > +typedef struct {
> > + UINT32 Signature;
> > + EDKII_USB_ETHERNET_PROTOCOL UsbEth;
> > + EFI_HANDLE UsbCdcDataHandle;
> > + EFI_HANDLE UsbRndisHandle;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + EFI_USB_IO_PROTOCOL *UsbIoCdcData;
> > + EFI_USB_CONFIG_DESCRIPTOR *Config;
> > + UINT8 NumOfInterface;
> > + UINT8 BulkInEndpoint;
> > + UINT8 BulkOutEndpoint;
> > + UINT8 InterrupEndpoint;
> > + EFI_MAC_ADDRESS MacAddress;
> > + UINT32 RequestId;
> > + UINT32 Medium;
> > + UINT32 MaxPacketsPerTransfer;
> > + UINT32 MaxTransferSize;
> > + UINT32 PacketAlignmentFactor;
> > + LIST_ENTRY ReceivePacketList;
> > +} USB_RNDIS_DEVICE;
> > +
> > +#define USB_RNDIS_DRIVER_VERSION 1
> > +#define USB_TX_ETHERNET_BULK_TIMEOUT 3000
> > +#define USB_RX_ETHERNET_BULK_TIMEOUT 3
> > +#define USB_ETHERNET_TRANSFER_TIMEOUT 200
> > +
> > +#define LAN_BULKIN_CMD_CONTROL 1
> > +#define MAXIMUM_STOPBULKIN_CNT 300 // Indicating maximum
> counts for waiting bulk in command
> > +#define MINIMUM_STOPBULKIN_CNT 3 // Indicating minimum
> counts for waiting bulk in command
> > +#define BULKIN_CMD_POLLING_CNT 300 // Indicating the waiting
> counts for send bulk in command when system pending
> > +#define RNDIS_RESERVED_BYTE_LENGTH 8
> > +
> > +#define USB_RNDIS_SIGNATURE SIGNATURE_32('r', 'n', 'd', 's')
> > +#define USB_RNDIS_DEVICE_FROM_THIS(a) CR (a, USB_RNDIS_DEVICE,
> UsbEth, USB_RNDIS_SIGNATURE)
> > +
> > +extern EFI_COMPONENT_NAME2_PROTOCOL
> gUsbRndisComponentName2;
> > +
> > +struct BIT_MAP {
> > + unsigned int Src;
> > + unsigned int Dst;
> > +};
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisDriverSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisDriverStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisDriverStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + );
> > +
> > +EFI_STATUS
> > +LoadAllDescriptor (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> > + );
> > +
> > +BOOLEAN
> > +NextDescriptor (
> > + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> > + IN OUT UINTN *Offset
> > + );
> > +
> > +EFI_STATUS
> > +GetFunctionalDescriptor (
> > + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> > + IN UINT8 FunDescriptorType,
> > + OUT VOID *DataBuffer
> > + );
> > +
> > +VOID
> > +GetEndpoint (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisInterrupt (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN BOOLEAN IsNewTransfer,
> > + IN UINTN PollingInterval,
> > + IN EFI_USB_DEVICE_REQUEST *Requst
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +InterruptCallback (
> > + IN VOID *Data,
> > + IN UINTN DataLength,
> > + IN VOID *Context,
> > + IN UINT32 Status
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbEthMacAddress (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT EFI_MAC_ADDRESS *MacAddress
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbEthBulkSize (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT UINTN *BulkSize
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisDummyReturn (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiStart (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiStop (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiGetInitInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiGetConfigInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiInitialize (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiTransmit (
> > + IN PXE_CDB *Cdb,
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN VOID *BulkOutData,
> > + IN OUT UINTN *DataLength
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiReceive (
> > + IN PXE_CDB *Cdb,
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN OUT VOID *BulkInData,
> > + IN OUT UINTN *DataLength
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiReset (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiShutdown (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiReceiveFilter (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiGetStatus (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbHeaderFunDescriptor (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbUnionFunDescriptor (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbRndisFunDescriptor (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +SetUsbRndisMcastFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN VOID *McastAddr
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +SetUsbRndisPowerFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN UINT16 Length,
> > + IN VOID *PatternFilter
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbRndisPowerFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN BOOLEAN *PatternActive
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +SetUsbRndisPacketFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value
> > + );
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +GetRndisStatistic (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN VOID *Statistic
> > + );
> > +
> > +EFI_STATUS
> > +RndisControlMsg (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> > + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> > + );
> > +
> > +EFI_STATUS
> > +RndisTransmitDataMsg (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> > + UINTN *TransferLength
> > + );
> > +
> > +EFI_STATUS
> > +RndisReceiveDataMsg (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> > + UINTN *TransferLength
> > + );
> > +
> > +VOID
> > +PrintRndisMsg (
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> > + );
> > +
> > +#define RNDIS_MAJOR_VERSION 0x00000001
> > +#define RNDIS_MINOR_VERSION 0x00000000
> > +#define RNDIS_MAX_TRANSFER_SIZE 0x4000
> > +
> > +#define RNDIS_PACKET_MSG 0x00000001
> > +#define RNDIS_INITIALIZE_MSG 0x00000002
> > +#define RNDIS_INITIALIZE_CMPLT 0x80000002
> > +#define RNDIS_HLT_MSG 0x00000003
> > +#define RNDIS_QUERY_MSG 0x00000004
> > +#define RNDIS_QUERY_CMPLT 0x80000004
> > +#define RNDIS_SET_MSG 0x00000005
> > +#define RNDIS_SET_CMPLT 0x80000005
> > +#define RNDIS_RESET_MSG 0x00000006
> > +#define RNDIS_RESET_CMPLT 0x80000006
> > +#define RNDIS_INDICATE_STATUS_MSG 0x00000007
> > +#define RNDIS_KEEPALIVE_MSG 0x00000008
> > +#define RNDIS_KEEPALIVE_CMPLT 0x80000008
> > +
> > +#define RNDIS_STATUS_SUCCESS 0x00000000
> > +#define RNDIS_STATUS_FAILURE 0xC0000001
> > +#define RNDIS_STATUS_INVALID_DATA 0xC0010015
> > +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BB
> > +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000B
> > +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000C
> > +
> > +#define RNDIS_CONTROL_TIMEOUT 10000 // 10sec
> > +#define RNDIS_KEEPALIVE_TIMEOUT 5000 // 5sec
> > +
> > +#define SEND_ENCAPSULATED_COMMAND 0x00000000
> > +#define GET_ENCAPSULATED_RESPONSE 0x00000001
> > +
> > +//
> > +// General Objects
> > +//
> > +// Taken from NTDDNDIS.H
> > +#define OID_GEN_SUPPORTED_LIST 0x00010101
> > +#define OID_GEN_HARDWARE_STATUS 0x00010102
> > +#define OID_GEN_MEDIA_SUPPORTED 0x00010103
> > +#define OID_GEN_MEDIA_IN_USE 0x00010104
> > +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
> > +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
> > +#define OID_GEN_LINK_SPEED 0x00010107
> > +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
> > +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
> > +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
> > +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
> > +#define OID_GEN_VENDOR_ID 0x0001010C
> > +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
> > +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
> > +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
> > +#define OID_GEN_DRIVER_VERSION 0x00010110
> > +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
> > +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
> > +#define OID_GEN_MAC_OPTIONS 0x00010113
> > +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
> > +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
> > +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
> > +
> > +#define OID_GEN_XMIT_OK 0x00020101
> > +#define OID_GEN_RCV_OK 0x00020102
> > +#define OID_GEN_XMIT_ERROR 0x00020103
> > +#define OID_GEN_RCV_ERROR 0x00020104
> > +#define OID_GEN_RCV_NO_BUFFER 0x00020105
> > +
> > +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
> > +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
> > +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
> > +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
> > +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
> > +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
> > +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
> > +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
> > +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
> > +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
> > +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
> > +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
> > +#define OID_GEN_RCV_CRC_ERROR 0x0002020D
> > +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
> > +
> > +#define OID_802_3_CURRENT_ADDRESS 0x01010102
> > +//
> > +// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
> > +//
> > +#define NDIS_PACKET_TYPE_DIRECTED 0x0001
> > +#define NDIS_PACKET_TYPE_MULTICAST 0x0002
> > +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
> > +#define NDIS_PACKET_TYPE_BROADCAST 0x0008
> > +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
> > +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
> > +#define NDIS_PACKET_TYPE_SMT 0x0040
> > +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
> > +#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
> > +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
> > +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
> > +#define NDIS_PACKET_TYPE_GROUP 0x1000
> > +
> > +#pragma pack(1)
> > +
> > +typedef struct _REMOTE_NDIS_MSG_HEADER {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > +} REMOTE_NDIS_MSG_HEADER;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 MajorVersion;
> > + UINT32 MinorVersion;
> > + UINT32 MaxTransferSize;
> > +} REMOTE_NDIS_INITIALIZE_MSG;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > +} REMOTE_NDIS_HALT_MSG;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 Oid;
> > + UINT32 InformationBufferLength;
> > + UINT32 InformationBufferOffset;
> > + UINT32 Reserved;
> > +} REMOTE_NDIS_QUERY_MSG;
> > +
> > +typedef struct {
> > + REMOTE_NDIS_QUERY_MSG QueryMsg;
> > + UINT8 Addr[6];
> > +} REMOTE_NDIS_QUERY_MAC_MSG;
> > +
> > +typedef struct {
> > + REMOTE_NDIS_QUERY_MSG QueryMsg;
> > + UINT32 MaxTotalSize;
> > +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 Oid;
> > + UINT32 InformationBufferLength;
> > + UINT32 InformationBufferOffset;
> > + UINT32 Reserved;
> > +} REMOTE_NDIS_SET_MSG;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 Reserved;
> > +} REMOTE_NDIS_RESET_MSG;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 Status;
> > + UINT32 StatusBufferLength;
> > + UINT32 StatusBufferOffset;
> > +} REMOTE_NDIS_INDICATE_STATUS_MSG;
> > +
> > +typedef struct {
> > + UINT32 DiagStatus;
> > + UINT32 ErrorOffset;
> > +} RNDIS_DIAGNOSTIC_INFO;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > +} REMOTE_NDIS_KEEPALIVE_MSG;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 Status;
> > + UINT32 MajorVersion;
> > + UINT32 MinorVersion;
> > + UINT32 DeviceFlags;
> > + UINT32 Medium;
> > + UINT32 MaxPacketsPerTransfer;
> > + UINT32 MaxTransferSize;
> > + UINT32 PacketAlignmentFactor;
> > + UINT64 Reserved;
> > +} REMOTE_NDIS_INITIALIZE_CMPLT;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 Status;
> > + UINT32 InformationBufferLength;
> > + UINT32 InformationBufferOffset;
> > +} REMOTE_NDIS_QUERY_CMPLT;
> > +
> > +typedef struct {
> > + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> > + UINT8 Addr[6];
> > +} REMOTE_NDIS_QUERY_MAC_CMPLT;
> > +
> > +typedef struct {
> > + REMOTE_NDIS_QUERY_CMPLT QueryCmplt;
> > + UINT32 MaxTotalSize;
> > +} REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 Status;
> > +} REMOTE_NDIS_SET_CMPLT;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 Status;
> > + UINT32 AddressingReset;
> > +} REMOTE_NDIS_RESET_CMPLT;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 RequestID;
> > + UINT32 Status;
> > +} REMOTE_NDIS_KEEPALIVE_CMPLT;
> > +
> > +typedef struct {
> > + UINT32 MessageType;
> > + UINT32 MessageLength;
> > + UINT32 DataOffset;
> > + UINT32 DataLength;
> > + UINT32 OutOfBandDataOffset;
> > + UINT32 OutOfBandDataLength;
> > + UINT32 NumOutOfBandDataElements;
> > + UINT32 PerPacketInfoOffset;
> > + UINT32 PerPacketInfoLength;
> > + UINT32 Reserved1;
> > + UINT32 Reserved2;
> > +} REMOTE_NDIS_PACKET_MSG;
> > +
> > +typedef struct {
> > + UINT32 Size;
> > + UINT32 Type;
> > + UINT32 ClassInformationOffset;
> > +} OUT_OF_BAND_DATA_RECORD;
> > +
> > +typedef struct {
> > + UINT32 Size;
> > + UINT32 Type;
> > + UINT32 ClassInformationOffset;
> > +} PER_PACKET_INFO_DATA_RECORD;
> > +
> > +typedef struct {
> > + LIST_ENTRY PacketList;
> > + UINT8 *OrgBuffer;
> > + UINTN RemainingLength;
> > + UINT8 *PacketStartBuffer; // Variable size data to follow
> > +} PACKET_LIST;
> > +
> > +#pragma pack()
> > +
> > +#endif
> > diff --git a/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> > new file mode 100644
> > index 0000000000..64205e4277
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbRndis/UsbRndis.inf
> > @@ -0,0 +1,42 @@
> > +## @file
> > +# This is Usb Rndis driver for DXE phase.
> > +#
> > +# Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +##
> > +
> > +[Defines]
> > + INF_VERSION = 0x00010005
> > + BASE_NAME = UsbRndis
> > + FILE_GUID = 11E32C34-60B5-4991-8DEA-63D3E8C876DE
> > + MODULE_TYPE = DXE_DRIVER
> > + VERSION_STRING = 1.0
> > + ENTRY_POINT = UsbRndisEntry
> > +
> > +[Sources]
> > + UsbRndis.c
> > + UsbRndis.h
> > + UsbRndisFunction.c
> > + ComponentName.c
> > +
> > +[Packages]
> > + MdePkg/MdePkg.dec
> > + UsbNetworkPkg/UsbNetworkPkg.dec
> > +
> > +[LibraryClasses]
> > + UefiDriverEntryPoint
> > + UefiBootServicesTableLib
> > + UefiLib
> > + DebugLib
> > + UefiUsbLib
> > + MemoryAllocationLib
> > + BaseMemoryLib
> > +
> > +[Protocols]
> > + gEfiUsbIoProtocolGuid
> > + gEfiDevicePathProtocolGuid
> > + gEfiDriverBindingProtocolGuid
> > + gEdkIIUsbEthProtocolGuid
> > +
> > +[Depex]
> > + TRUE
> > diff --git a/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> > new file mode 100644
> > index 0000000000..e3fe737cde
> > --- /dev/null
> > +++ b/UsbNetworkPkg/UsbRndis/UsbRndisFunction.c
> > @@ -0,0 +1,1718 @@
> > +/** @file
> > + This file contains code for USB Ethernet descriptor
> > + and specific requests implement.
> > +
> > + Copyright (c) 2023, American Megatrends International LLC. All rights
> reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include "UsbRndis.h"
> > +
> > +UINT16 gStopBulkInCnt = 0;
> > +UINT16 gBlockBulkInCnt = 0;
> > +
> > +/**
> > + Load All of device descriptor.
> > +
> > + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL
> instance.
> > + @param[out] ConfigDesc A pointer to the configuration descriptor.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_OUT_OF_RESOURCES The request could not be completed
> because the
> > + buffer specified by DescriptorLength and Descriptor
> > + is not large enough to hold the result of the request.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> The transfer
> > + status is returned in Status.
> > +**/
> > +EFI_STATUS
> > +LoadAllDescriptor (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + OUT EFI_USB_CONFIG_DESCRIPTOR **ConfigDesc
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 TransStatus;
> > + EFI_USB_CONFIG_DESCRIPTOR Tmp;
> > +
> > + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n",
> __FUNCTION__, Status));
> > + return Status;
> > + }
> > +
> > + Status = gBS->AllocatePool (
> > + EfiBootServicesData,
> > + Tmp.TotalLength,
> > + (VOID **)ConfigDesc
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n",
> __FUNCTION__, Status));
> > + return Status;
> > + }
> > +
> > + Status = UsbGetDescriptor (
> > + UsbIo,
> > + USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1),
> // zero based
> > + 0,
> > + Tmp.TotalLength,
> > + *ConfigDesc,
> > + &TransStatus
> > + );
> > + return Status;
> > +}
> > +
> > +/**
> > + Returns pointer to the next descriptor for the pack of USB descriptors
> > + located in continues memory segment
> > +
> > + @param[in] Desc A pointer to the CONFIG_DESCRIPTOR instance.
> > + @param[in, out] Offset A pointer to the sum of descriptor length.
> > +
> > + @retval TRUE The request executed successfully.
> > + @retval FALSE No next descriptor.
> > +
> > +**/
> > +BOOLEAN
> > +NextDescriptor (
> > + IN EFI_USB_CONFIG_DESCRIPTOR *Desc,
> > + IN OUT UINTN *Offset
> > + )
> > +{
> > + if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
> > + return FALSE;
> > + }
> > +
> > + if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length
> == 0) {
> > + return FALSE;
> > + }
> > +
> > + *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))-
> >Length;
> > + if ( *Offset >= Desc->TotalLength ) {
> > + return FALSE;
> > + }
> > +
> > + return TRUE;
> > +}
> > +
> > +/**
> > + Read Function descriptor
> > +
> > + @param[in] Config A pointer to all of configuration.
> > + @param[in] FunDescriptorType USB CDC class descriptor SubType.
> > + @param[out] DataBuffer A pointer to the Data of corresponding to
> device capability.
> > +
> > + @retval EFI_SUCCESS The device capability descriptor was retrieved
> > + successfully.
> > + @retval EFI_UNSUPPORTED No supported.
> > + @retval EFI_NOT_FOUND The device capability descriptor was not
> found.
> > +
> > +**/
> > +EFI_STATUS
> > +GetFunctionalDescriptor (
> > + IN EFI_USB_CONFIG_DESCRIPTOR *Config,
> > + IN UINT8 FunDescriptorType,
> > + OUT VOID *DataBuffer
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN Offset;
> > + EFI_USB_INTERFACE_DESCRIPTOR *Interface;
> > +
> > + Status = EFI_NOT_FOUND;
> > +
> > + for (Offset = 0; NextDescriptor (Config, &Offset);) {
> > + Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config +
> Offset);
> > + if (Interface->DescriptorType == CS_INTERFACE) {
> > + if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype
> == FunDescriptorType) {
> > + switch (FunDescriptorType) {
> > + case HEADER_FUN_DESCRIPTOR:
> > + CopyMem (
> > + DataBuffer,
> > + (USB_HEADER_FUN_DESCRIPTOR *)Interface,
> > + sizeof (USB_HEADER_FUN_DESCRIPTOR)
> > + );
> > + return EFI_SUCCESS;
> > + case UNION_FUN_DESCRIPTOR:
> > + CopyMem (
> > + DataBuffer,
> > + (USB_UNION_FUN_DESCRIPTOR *)Interface,
> > + ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
> > + );
> > + return EFI_SUCCESS;
> > + case ETHERNET_FUN_DESCRIPTOR:
> > + CopyMem (
> > + DataBuffer,
> > + (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
> > + sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
> > + );
> > + return EFI_SUCCESS;
> > + default:
> > + Status = EFI_UNSUPPORTED;
> > + break;
> > + }
> > + }
> > + }
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
> > +
> > + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL
> instance.
> > + @param[in, out] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
> instance.
> > +
> > +**/
> > +VOID
> > +GetEndpoint (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 Index;
> > + UINT32 Result;
> > + EFI_USB_INTERFACE_DESCRIPTOR Interface;
> > + EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =
> %r\n", __FUNCTION__, Status));
> > + return;
> > + }
> > +
> > + if (Interface.NumEndpoints == 0 ) {
> > + Status = UsbSetInterface (UsbIo, 1, 0, &Result);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n",
> __FUNCTION__, Status));
> > + return;
> > + }
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status =
> %r\n", __FUNCTION__, Status));
> > + return;
> > + }
> > + }
> > +
> > + for (Index = 0; Index < Interface.NumEndpoints; Index++) {
> > + Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status =
> %r\n", __FUNCTION__, Status));
> > + return;
> > + }
> > +
> > + switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
> > + case USB_ENDPOINT_BULK:
> > + if (Endpoint.EndpointAddress & BIT7) {
> > + UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
> > + } else {
> > + UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
> > + }
> > +
> > + break;
> > + case USB_ENDPOINT_INTERRUPT:
> > + UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
> > + break;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + Async USB transfer callback routine.
> > +
> > + @param[in] Data Data received or sent via the USB Asynchronous
> Transfer, if the
> > + transfer completed successfully.
> > + @param[in] DataLength The length of Data received or sent via the
> Asynchronous
> > + Transfer, if transfer successfully completes.
> > + @param[in] Context Data passed from UsbAsyncInterruptTransfer()
> request.
> > + @param[in] Status Indicates the result of the asynchronous transfer.
> > +
> > + @retval EFI_SUCCESS The asynchronous USB transfer request has
> been successfully executed.
> > + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request
> failed.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +InterruptCallback (
> > + IN VOID *Data,
> > + IN UINTN DataLength,
> > + IN VOID *Context,
> > + IN UINT32 Status
> > + )
> > +{
> > + if ((Data == NULL) || (Context == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == 0) {
> > + CopyMem (
> > + (EFI_USB_DEVICE_REQUEST *)Context,
> > + (EFI_USB_DEVICE_REQUEST *)Data,
> > + sizeof (EFI_USB_DEVICE_REQUEST)
> > + );
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is used to manage a USB device with an interrupt transfer
> pipe.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] IsNewTransfer If TRUE, a new transfer will be submitted
> to USB controller. If
> > + FALSE, the interrupt transfer is deleted from the device's
> interrupt
> > + transfer queue.
> > + @param[in] PollingInterval Indicates the periodic rate, in milliseconds,
> that the transfer is to be
> > + executed.This parameter is required when IsNewTransfer
> is TRUE. The
> > + value must be between 1 to 255, otherwise
> EFI_INVALID_PARAMETER is returned.
> > + The units are in milliseconds.
> > + @param[in] Request A pointer to the EFI_USB_DEVICE_REQUEST
> data.
> > +
> > + @retval EFI_SUCCESS The asynchronous USB transfer request
> transfer has been successfully executed.
> > + @retval EFI_DEVICE_ERROR The asynchronous USB transfer request
> failed.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbRndisInterrupt (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN BOOLEAN IsNewTransfer,
> > + IN UINTN PollingInterval,
> > + IN EFI_USB_DEVICE_REQUEST *Requst
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + UINTN DataLength;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > + DataLength = 0;
> > +
> > + if (IsNewTransfer == TRUE) {
> > + DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof
> (USB_CONNECT_SPEED_CHANGE);
> > + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> > + UsbRndisDevice->UsbIo,
> > + UsbRndisDevice->InterrupEndpoint,
> > + IsNewTransfer,
> > + PollingInterval,
> > + DataLength,
> > + InterruptCallback,
> > + Requst
> > + );
> > +
> > + if (Status == EFI_INVALID_PARAMETER) {
> > + // Because of Stacked AsyncInterrupt request are not supported
> > + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> > + UsbRndisDevice->UsbIo,
> > + UsbRndisDevice->InterrupEndpoint,
> > + 0,
> > + 0,
> > + 0,
> > + NULL,
> > + NULL
> > + );
> > + }
> > + } else {
> > + Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
> > + UsbRndisDevice->UsbIo,
> > + UsbRndisDevice->InterrupEndpoint,
> > + IsNewTransfer,
> > + 0,
> > + 0,
> > + NULL,
> > + NULL
> > + );
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This function is used to read USB interrupt transfer before the response
> RNDIS message.
> > +
> > + @param[in] This A pointer to the USB_RNDIS_DEVICE instance.
> > +
> > + @retval EFI_SUCCESS The USB interrupt transfer has been
> successfully executed.
> > + @retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadRndisResponseInterrupt (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 Data[2];
> > + UINT32 UsbStatus;
> > + UINTN DataLength;
> > +
> > + DataLength = 8;
> > +
> > + ZeroMem (Data, sizeof (Data));
> > +
> > + Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
> > + UsbRndisDevice->UsbIo,
> > + UsbRndisDevice->InterrupEndpoint,
> > + &Data,
> > + &DataLength,
> > + 0x20,
> > + &UsbStatus
> > + );
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Retrieves the USB Ethernet Mac Address.
> > +
> > + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL
> instance.
> > + @param[out] MacAddress A pointer to the caller allocated USB
> Ethernet Mac Address.
> > +
> > + @retval EFI_SUCCESS The USB Header Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Header Functional descriptor was
> not found.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbEthMacAddress (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT EFI_MAC_ADDRESS *MacAddress
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
> > + CHAR16 *Data;
> > + CHAR16 *DataPtr;
> > + CHAR16 TmpStr[1];
> > + UINT8 Index;
> > + UINT8 Hi;
> > + UINT8 Low;
> > +
> > + REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
> > + REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + ZeroMem (&RndisQueryMsg, sizeof
> (REMOTE_NDIS_QUERY_MAC_MSG));
> > + ZeroMem (&RndisQueryMsgCmplt, sizeof
> (REMOTE_NDIS_QUERY_MAC_CMPLT));
> > +
> > + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> > + RndisQueryMsg.QueryMsg.MessageLength = sizeof
> (REMOTE_NDIS_QUERY_MAC_MSG);
> > + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> > + RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
> > +
> > + RndisQueryMsgCmplt.QueryCmplt.MessageType =
> RNDIS_QUERY_CMPLT;
> > + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof
> (REMOTE_NDIS_QUERY_MAC_CMPLT);
> > +
> > + Status = RndisControlMsg (
> > + UsbRndisDevice,
> > + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> > + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> > + );
> > + if (!EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS
> message.\n"));
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
> > + }
> > +
> > + UsbRndisDevice->RequestId++;
> > + return Status;
> > + }
> > +
> > + // If it is not support the OID_802_3_CURRENT_ADDRESS.
> > + // To check USB Ethernet functional Descriptor
> > + Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n",
> __FUNCTION__, Status));
> > + return Status;
> > + }
> > +
> > + Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
> > + UsbRndisDevice->UsbIo,
> > + 0x409, // English-US Language ID
> > + UsbEthDescriptor.MacAddress,
> > + &Data
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n",
> __FUNCTION__, Status));
> > + return Status;
> > + }
> > +
> > + DataPtr = Data;
> > + for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
> > + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> > + DataPtr++;
> > + Hi = (UINT8)StrHexToUintn (TmpStr);
> > + CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
> > + DataPtr++;
> > + Low = (UINT8)StrHexToUintn (TmpStr);
> > + MacAddress->Addr[Index] = (Hi << 4) | Low;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Retrieves the USB Ethernet Bulk transfer data size.
> > +
> > + @param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL
> instance.
> > + @param[out] BulkSize A pointer to the Bulk transfer data size.
> > +
> > + @retval EFI_SUCCESS The bulk transfer data size was retrieved
> successfully.
> > + @retval other Failed to retrieve the bulk transfer data size.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbEthBulkSize (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT UINTN *BulkSize
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
> > + REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT
> RndisQueryMsgCmplt;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + ZeroMem (&RndisQueryMsg, sizeof
> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
> > + ZeroMem (&RndisQueryMsgCmplt, sizeof
> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
> > +
> > + RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
> > + RndisQueryMsg.QueryMsg.MessageLength = sizeof
> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
> > + RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
> > + RndisQueryMsg.QueryMsg.Oid =
> OID_GEN_MAXIMUM_TOTAL_SIZE;
> > +
> > + RndisQueryMsgCmplt.QueryCmplt.MessageType =
> RNDIS_QUERY_CMPLT;
> > + RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof
> (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
> > +
> > + Status = RndisControlMsg (
> > + UsbRndisDevice,
> > + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
> > + (REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
> > + );
> > + if (!EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n",
> RndisQueryMsgCmplt.MaxTotalSize));
> > + *BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
> > + UsbRndisDevice->RequestId++;
> > + return Status;
> > + }
> > +
> > + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
> > + return Status;
> > +}
> > +
> > +/**
> > + Retrieves the USB Header functional Descriptor.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated
> USB Header Functional Descriptor.
> > +
> > + @retval EFI_SUCCESS The USB Header Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Header Functional descriptor was
> not found.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbHeaderFunDescriptor (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_HEADER_FUN_DESCRIPTOR *UsbHeaderFunDescriptor
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + if (UsbHeaderFunDescriptor == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Status = GetFunctionalDescriptor (
> > + UsbRndisDevice->Config,
> > + HEADER_FUN_DESCRIPTOR,
> > + UsbHeaderFunDescriptor
> > + );
> > + return Status;
> > +}
> > +
> > +/**
> > + Retrieves the USB Union functional Descriptor.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[out] UsbUnionFunDescriptor A pointer to the caller allocated
> USB Union Functional Descriptor.
> > +
> > + @retval EFI_SUCCESS The USB Union Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Union Functional descriptor was
> not found.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbUnionFunDescriptor (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_UNION_FUN_DESCRIPTOR *UsbUnionFunDescriptor
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + if (UsbUnionFunDescriptor == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Status = GetFunctionalDescriptor (
> > + UsbRndisDevice->Config,
> > + UNION_FUN_DESCRIPTOR,
> > + UsbUnionFunDescriptor
> > + );
> > + return Status;
> > +}
> > +
> > +/**
> > + Retrieves the USB Ethernet functional Descriptor.
> > +
> > + This function get the Mac Address, Ethernet statistics, maximum
> segment size,
> > + number of multicast filters, and number of pattern filters from Ethernet
> > + functional Descriptor.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[out] UsbEthFunDescriptor A pointer to the caller allocated
> USB Ethernet Functional Descriptor.
> > +
> > + @retval EFI_SUCCESS The USB Ethernet Functional descriptor was
> retrieved successfully.
> > + @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
> > + @retval EFI_NOT_FOUND The USB Ethernet Functional descriptor
> was not found.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbRndisFunDescriptor (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + if (UsbEthFunDescriptor == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Status = GetFunctionalDescriptor (
> > + UsbRndisDevice->Config,
> > + ETHERNET_FUN_DESCRIPTOR,
> > + UsbEthFunDescriptor
> > + );
> > + return Status;
> > +}
> > +
> > +/**
> > + This request sets the Ethernet device multicast filters as specified in the
> > + sequential list of 48 bit Ethernet multicast addresses.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value Number of filters.
> > + @param[in] McastAddr A pointer to the value of the multicast
> addresses.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SetUsbRndisMcastFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN VOID *McastAddr
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_DEVICE_REQUEST Request;
> > + UINT32 TransStatus;
> > + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> > + Request.Request = SET_ETH_MULTICAST_FILTERS_REQ;
> > + Request.Value = Value;
> > + Request.Index = UsbRndisDevice->NumOfInterface;
> > + Request.Length = Value * 6;
> > +
> > + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> > + UsbRndisDevice->UsbIo,
> > + &Request,
> > + EfiUsbDataOut,
> > + USB_ETHERNET_TRANSFER_TIMEOUT,
> > + McastAddr,
> > + Request.Length,
> > + &TransStatus
> > + );
> > +}
> > +
> > +/**
> > + This request sets up the specified Ethernet power management pattern
> filter as
> > + described in the data structure.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value Number of filters.
> > + @param[in] Length Size of the power management pattern filter
> data.
> > + @param[in] PatternFilter A pointer to the power management
> pattern filter structure.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SetUsbRndisPowerFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + IN UINT16 Length,
> > + IN VOID *PatternFilter
> > + )
> > +{
> > + EFI_USB_DEVICE_REQUEST Request;
> > + UINT32 TransStatus;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
> > + Request.Request =
> SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> > + Request.Value = Value;
> > + Request.Index = UsbRndisDevice->NumOfInterface;
> > + Request.Length = Length;
> > +
> > + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> > + UsbRndisDevice->UsbIo,
> > + &Request,
> > + EfiUsbDataOut,
> > + USB_ETHERNET_TRANSFER_TIMEOUT,
> > + PatternFilter,
> > + Length,
> > + &TransStatus
> > + );
> > +}
> > +
> > +/**
> > + This request retrieves the status of the specified Ethernet power
> management
> > + pattern filter from the device.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value The filter number.
> > + @param[out] PatternActive A pointer to the pattern active boolean.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetUsbRndisPowerFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value,
> > + OUT BOOLEAN *PatternActive
> > + )
> > +{
> > + EFI_USB_DEVICE_REQUEST Request;
> > + UINT32 TransStatus;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
> > + Request.Request =
> GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
> > + Request.Value = Value;
> > + Request.Index = UsbRndisDevice->NumOfInterface;
> > + Request.Length = USB_ETH_POWER_FILTER_LENGTH;
> > +
> > + return UsbRndisDevice->UsbIo->UsbControlTransfer (
> > + UsbRndisDevice->UsbIo,
> > + &Request,
> > + EfiUsbDataIn,
> > + USB_ETHERNET_TRANSFER_TIMEOUT,
> > + PatternActive,
> > + USB_ETH_POWER_FILTER_LENGTH,
> > + &TransStatus
> > + );
> > +}
> > +
> > +/**
> > +
> > + Converts PXE filter settings to RNDIS values
> > +
> > + @param[in] Value PXE filter data.
> > + @param[out] CdcFilter A pointer to the Ethernet Packet Filter Bitmap
> value converted by PXE_OPFLAGS.
> > +
> > +**/
> > +VOID
> > +ConvertFilter (
> > + IN UINT16 Value,
> > + OUT UINT16 *CdcFilter
> > + )
> > +{
> > + UINT32 Index;
> > + UINT32 Count;
> > + static struct BIT_MAP Table[] = {
> > + { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST,
> NDIS_PACKET_TYPE_DIRECTED },
> > + { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST,
> NDIS_PACKET_TYPE_BROADCAST },
> > + { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST,
> NDIS_PACKET_TYPE_MULTICAST },
> > + { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS,
> NDIS_PACKET_TYPE_PROMISCUOUS },
> > + { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST,
> NDIS_PACKET_TYPE_ALL_MULTICAST },
> > + };
> > +
> > + Count = sizeof (Table)/sizeof (Table[0]);
> > +
> > + for (Index = 0; (Table[Index].Src != 0) && (Index < Count); Index++) {
> > + if (Table[Index].Src & Value) {
> > + *CdcFilter |= Table[Index].Dst;
> > + }
> > + }
> > +}
> > +
> > +/**
> > +
> > + Updates Filter settings on the device.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_STATUS
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiReceiveFilter (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 *McastList;
> > + UINT8 Count;
> > + UINT8 Index1;
> > + UINT8 Index2;
> > + UINT64 CpbAddr;
> > + UINT32 CpbSize;
> > + UINT16 SetFilter;
> > + PXE_CPB_RECEIVE_FILTERS *Cpb;
> > + USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
> > +
> > + Count = 0;
> > + CpbAddr = Cdb->CPBaddr;
> > + CpbSize = Cdb->CPBsize;
> > + SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
> > + Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
> > +
> > + // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
> > + Nic->RxFilter = (UINT8)SetFilter;
> > +
> > + if (((SetFilter &
> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb !=
> NULL)) {
> > + if (Cpb != NULL) {
> > + Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
> > + CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
> > + } else {
> > + Nic->McastCount = 0;
> > + }
> > +
> > + Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth,
> &UsbEthFunDescriptor);
> > + if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
> > + Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
> > + DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth
> %lx ", Nic, Nic->UsbEth));
> > + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> > + } else {
> > + Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6,
> (VOID **)&McastList);
> > + if (EFI_ERROR (Status)) {
> > + return PXE_STATCODE_INVALID_PARAMETER;
> > + }
> > +
> > + if (Cpb != NULL) {
> > + for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
> > + for (Index2 = 0; Index2 < 6; Index2++) {
> > + McastList[Count++] = Cpb->MCastList[Index1][Index2];
> > + }
> > + }
> > + }
> > +
> > + Nic->RxFilter |=
> PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
> > + if (Cpb != NULL) {
> > + Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount,
> McastList);
> > + }
> > +
> > + Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
> > + FreePool (McastList);
> > + }
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This request is used to configure device Ethernet packet filter settings.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] Value Packet Filter Bitmap.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SetUsbRndisPacketFilter (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 Value
> > + )
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This request is used to retrieve a statistic based on the feature selector.
> > +
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] FeatureSelector Value of the feature selector.
> > + @param[out] Statistic A pointer to the 32 bit unsigned integer.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_TIMEOUT A timeout occurred executing the request.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid
> value.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetRndisStatistic (
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN UINT16 FeatureSelector,
> > + OUT VOID *Statistic
> > + )
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is called when UndiStart is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiStart (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n",
> Nic, Cdb, Nic->State));
> > +
> > + // Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED
> state
> > + Status = RndisUndiReset (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + RndisUndiReset (Cdb, Nic);
> > + }
> > +
> > + Status = RndisUndiInitialize (Cdb, Nic);
> > + if (EFI_ERROR (Status)) {
> > + RndisUndiInitialize (Cdb, Nic);
> > + }
> > +
> > + RndisUndiShutdown (Cdb, Nic);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is called when Undistop is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiStop (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is called when UndiGetInitInfo is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiGetInitInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + PXE_DB_GET_INIT_INFO *Db;
> > +
> > + DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
> > +
> > + UsbEthDevice = Nic->UsbEth;
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
> > +
> > + Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
> > +
> > + Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof
> (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
> > + // Limit Max MTU size to 1500 bytes as RNDIS spec.
> > + if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
> > + Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
> > + }
> > +
> > + DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db-
> >FrameDataLen));
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is called when RndisUndiGetConfigInfo is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiGetConfigInfo (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is called when UndiInitialize is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_UNSUPPORTED Not supported.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiInitialize (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
> > + REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
> > + EFI_STATUS Status;
> > +
> > + DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
> > +
> > + UsbEthDriver = Nic->UsbEth;
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> > +
> > + ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
> > + ZeroMem (&RndisInitMsgCmplt, sizeof
> (REMOTE_NDIS_INITIALIZE_CMPLT));
> > +
> > + RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
> > + RndisInitMsg.MessageLength = sizeof
> (REMOTE_NDIS_INITIALIZE_MSG);
> > + RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
> > + RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
> > + RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
> > + RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
> > +
> > + RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
> > + RndisInitMsgCmplt.MessageLength = sizeof
> (REMOTE_NDIS_INITIALIZE_CMPLT);
> > +
> > + Status = RndisControlMsg (UsbRndisDevice,
> (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg,
> (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
> > +
> > + UsbRndisDevice->RequestId++;
> > +
> > + if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
> > + return Status;
> > + }
> > +
> > + // Only Wired Medium is supported
> > + if (RndisInitMsgCmplt.Medium) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
> > + UsbRndisDevice->MaxPacketsPerTransfer =
> RndisInitMsgCmplt.MaxPacketsPerTransfer;
> > + UsbRndisDevice->MaxTransferSize =
> RndisInitMsgCmplt.MaxTransferSize;
> > + UsbRndisDevice->PacketAlignmentFactor =
> RndisInitMsgCmplt.PacketAlignmentFactor;
> > +
> > + DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
> > + DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n",
> RndisInitMsgCmplt.MaxPacketsPerTransfer));
> > + DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n",
> RndisInitMsgCmplt.MaxTransferSize));
> > + DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n",
> RndisInitMsgCmplt.PacketAlignmentFactor));
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This function is called when UndiReset is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_DEVICE_ERROR The request failed due to a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiReset (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + REMOTE_NDIS_RESET_MSG RndisResetMsg;
> > + REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
> > + EFI_STATUS Status;
> > +
> > + DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
> > +
> > + UsbEthDriver = Nic->UsbEth;
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> > +
> > + ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
> > + ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
> > +
> > + RndisResetMsg.MessageType = RNDIS_RESET_MSG;
> > + RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
> > +
> > + RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
> > + RndisResetCmplt.MessageLength = sizeof
> (REMOTE_NDIS_RESET_CMPLT);
> > +
> > + Status = RndisControlMsg (UsbRndisDevice,
> (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg,
> (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
> > +
> > + UsbRndisDevice->RequestId = 1; // Let's start with 1
> > +
> > + if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function is called when UndiShutdown is invoked.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiShutdown (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + REMOTE_NDIS_HALT_MSG RndisHltMsg;
> > + EFI_STATUS Status;
> > +
> > + DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
> > +
> > + UsbEthDriver = Nic->UsbEth;
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
> > +
> > + ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
> > +
> > + RndisHltMsg.MessageType = RNDIS_HLT_MSG;
> > + RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
> > +
> > + Status = RndisControlMsg (UsbRndisDevice,
> (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
> > +
> > + if (Status == EFI_DEVICE_ERROR) {
> > + Status = EFI_SUCCESS;
> > + }
> > +
> > + UsbRndisDevice->RequestId = 1;
> > + return Status;
> > +}
> > +
> > +/**
> > + Update the Media connection.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiGetStatus (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Transmit the data after appending RNDIS header.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in] BulkOutData A pointer to the buffer of data that will be
> transmitted to USB
> > + device or received from USB device.
> > + @param[in, out] DataLength A pointer to the PacketLength.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiTransmit (
> > + IN PXE_CDB *Cdb,
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN VOID *BulkOutData,
> > + IN OUT UINTN *DataLength
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> > + UINTN TransferLength;
> > +
> > + DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n",
> *DataLength));
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > +
> > + RndisPacketMsg = AllocateZeroPool (sizeof
> (REMOTE_NDIS_PACKET_MSG) + *DataLength);
> > + if (RndisPacketMsg == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
> > + RndisPacketMsg->MessageLength = sizeof
> (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
> > + RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) -
> 8;
> > + RndisPacketMsg->DataLength = (UINT32)*DataLength;
> > +
> > + CopyMem (
> > + ((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
> > + BulkOutData,
> > + *DataLength
> > + );
> > +
> > + TransferLength = RndisPacketMsg->MessageLength;
> > +
> > + Status = RndisTransmitDataMsg (
> > + UsbRndisDevice,
> > + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> > + &TransferLength
> > + );
> > +
> > + DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n",
> TransferLength));
> > +
> > + FreePool (RndisPacketMsg);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Receives and removes RNDIS header and returns the raw data.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] This A pointer to the
> EDKII_USB_ETHERNET_PROTOCOL instance.
> > + @param[in, out] BulkInData A pointer to the buffer of data that will be
> transmitted to USB
> > + device or received from USB device.
> > + @param[in, out] DataLength A pointer to the PacketLength.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > + @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
> > + @retval EFI_NOT_FOUND No buffer was found in the list.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisUndiReceive (
> > + IN PXE_CDB *Cdb,
> > + IN EDKII_USB_ETHERNET_PROTOCOL *This,
> > + IN OUT VOID *BulkInData,
> > + IN OUT UINTN *DataLength
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_RNDIS_DEVICE *UsbRndisDevice;
> > + REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
> > + UINTN TransferLength;
> > + VOID *Buffer;
> > + PACKET_LIST *HeadPacket;
> > + PACKET_LIST *PacketList;
> > +
> > + // Check if there is any outstanding packet to receive
> > + // The buffer allocated has a linked List followed by the packet.
> > +
> > + UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
> > + Buffer = NULL;
> > + HeadPacket = NULL;
> > +
> > + while (1) {
> > + Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof
> (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
> > + if (Buffer == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof
> (PACKET_LIST) + (UINT8 *)Buffer);
> > + PacketList = (PACKET_LIST *)Buffer;
> > + PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
> > + // Save the original address for freeing it up
> > + PacketList->OrgBuffer = (UINT8 *)Buffer;
> > + TransferLength = UsbRndisDevice->MaxTransferSize;
> > +
> > + Status = RndisReceiveDataMsg (
> > + UsbRndisDevice,
> > + (REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
> > + &TransferLength
> > + );
> > +
> > + if (EFI_ERROR (Status) || (TransferLength == 0)) {
> > + FreePool (Buffer);
> > + break;
> > + }
> > +
> > + // Collect all the RNDIS packet in Linked list.
> > + if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
> > + (RndisPacketMsg->DataOffset == sizeof
> (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
> > + (TransferLength >= RndisPacketMsg->MessageLength))
> > + {
> > + // Insert Packet
> > + PacketList->RemainingLength = TransferLength;
> > + InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
> > + } else {
> > + FreePool (Buffer);
> > + }
> > + }
> > +
> > + while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
> > + HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice-
> >ReceivePacketList);
> > +
> > + RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8
> *)HeadPacket->PacketStartBuffer;
> > +
> > + PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
> > +
> > + // Check whether the packet is valid RNDIS packet.
> > + if ((HeadPacket->RemainingLength > sizeof
> (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType ==
> RNDIS_PACKET_MSG) &&
> > + (RndisPacketMsg->DataOffset == (sizeof
> (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
> > + (HeadPacket->RemainingLength >= RndisPacketMsg-
> >MessageLength))
> > + {
> > + if (*DataLength >= RndisPacketMsg->DataLength) {
> > + CopyMem (
> > + BulkInData,
> > + (UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset +
> RNDIS_RESERVED_BYTE_LENGTH),
> > + RndisPacketMsg->DataLength
> > + );
> > +
> > + *DataLength = RndisPacketMsg->DataLength;
> > +
> > + HeadPacket->RemainingLength = HeadPacket->RemainingLength -
> RndisPacketMsg->MessageLength;
> > + HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg +
> RndisPacketMsg->MessageLength;
> > +
> > + return EFI_SUCCESS;
> > + } else {
> > + *DataLength = RndisPacketMsg->DataLength;
> > + return EFI_BUFFER_TOO_SMALL;
> > + }
> > + }
> > +
> > + RemoveEntryList (&HeadPacket->PacketList);
> > + FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
> > + }
> > +
> > + return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > + This is a dummy function which just returns. Unimplemented
> EDKII_USB_ETHERNET_PROTOCOL functions
> > + point to this function.
> > +
> > + @param[in] Cdb A pointer to the command descriptor block.
> > + @param[in] Nic A pointer to the Network interface controller data.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +RndisDummyReturn (
> > + IN PXE_CDB *Cdb,
> > + IN NIC_DATA *Nic
> > + )
> > +{
> > + DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function send the RNDIS command through the device's control
> endpoint
> > +
> > + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
> instance.
> > + @param[in] RndisMsg A pointer to the
> REMOTE_NDIS_MSG_HEADER data.
> > + @param[out] RndisMsgResponse A pointer to the
> REMOTE_NDIS_MSG_HEADER data for getting responses.
> > +
> > + @retval EFI_SUCCESS The bulk transfer has been successfully
> executed.
> > +
> > +**/
> > +EFI_STATUS
> > +RndisControlMsg (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> > + OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
> > + )
> > +{
> > + EFI_USB_IO_PROTOCOL *UsbIo = UsbRndisDevice->UsbIo;
> > + EFI_USB_DEVICE_REQUEST DevReq;
> > + UINT32 UsbStatus;
> > + EFI_STATUS Status;
> > + UINT32 SaveResponseType;
> > + UINT32 SaveResponseLength;
> > + UINT32 Index;
> > + REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
> > +
> > + SaveResponseType = 0;
> > + SaveResponseLength = 0;
> > + RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT
> *)RndisMsgResponse;
> > +
> > + if (RndisMsgResponse) {
> > + SaveResponseType = RndisMsgResponse->MessageType;
> > + SaveResponseLength = RndisMsgResponse->MessageLength;
> > + }
> > +
> > + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> > +
> > + DevReq.RequestType = USB_REQ_TYPE_CLASS |
> USB_TARGET_INTERFACE;
> > + DevReq.Request = SEND_ENCAPSULATED_COMMAND;
> > + DevReq.Value = 0;
> > + DevReq.Index = 0;
> > + DevReq.Length = (UINT16)RndisMsg->MessageLength;
> > +
> > + PrintRndisMsg (RndisMsg);
> > +
> > + Status = UsbIo->UsbControlTransfer (
> > + UsbIo,
> > + &DevReq,
> > + EfiUsbDataOut,
> > + USB_ETHERNET_TRANSFER_TIMEOUT,
> > + RndisMsg,
> > + RndisMsg->MessageLength,
> > + &UsbStatus
> > + );
> > +
> > + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r
> RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
> > +
> > + // Error or no response expected
> > + if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
> > + DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status :
> %r\n", UsbStatus, Status));
> > + return Status;
> > + }
> > +
> > + for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
> > + ReadRndisResponseInterrupt (UsbRndisDevice);
> > + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
> > +
> > + DevReq.RequestType = USB_ENDPOINT_DIR_IN |
> USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
> > + DevReq.Request = GET_ENCAPSULATED_RESPONSE;
> > + DevReq.Value = 0;
> > + DevReq.Index = 0;
> > + DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
> > +
> > + Status = UsbIo->UsbControlTransfer (
> > + UsbIo,
> > + &DevReq,
> > + EfiUsbDataIn,
> > + USB_ETHERNET_TRANSFER_TIMEOUT,
> > + RndisMsgResponse,
> > + RndisMsgResponse->MessageLength,
> > + &UsbStatus
> > + );
> > +
> > + DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x
> Status : %r \n", UsbStatus, Status));
> > +
> > + PrintRndisMsg (RndisMsgResponse);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT
> *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType !=
> SaveResponseType)) {
> > + DEBUG ((DEBUG_INFO, "Retry the response\n"));
> > +
> > + RndisMsgResponse->MessageType = SaveResponseType;
> > + RndisMsgResponse->MessageLength = SaveResponseLength;
> > + continue;
> > + }
> > + }
> > +
> > + return Status;
> > + }
> > +
> > + DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
> > +
> > + return EFI_TIMEOUT;
> > +}
> > +
> > +/**
> > + This function send the RNDIS command through the device's Data
> endpoint
> > +
> > + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
> instance.
> > + @param[in] RndisMsg A pointer to the
> REMOTE_NDIS_MSG_HEADER to send out.
> > + @param[in, out] TransferLength The length of the RndisMsg data to
> transfer.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +RndisTransmitDataMsg (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
> > + IN OUT UINTN *TransferLength
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 UsbStatus;
> > +
> > + if (UsbRndisDevice->BulkInEndpoint == 0) {
> > + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> > + }
> > +
> > + PrintRndisMsg (RndisMsg);
> > +
> > + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> > + UsbRndisDevice->UsbIoCdcData,
> > + UsbRndisDevice->BulkOutEndpoint,
> > + RndisMsg,
> > + TransferLength,
> > + USB_TX_ETHERNET_BULK_TIMEOUT,
> > + &UsbStatus
> > + );
> > +
> > + if (Status == EFI_SUCCESS) {
> > + gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending
> cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This function send the RNDIS command through the device's Data
> endpoint
> > +
> > + @param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE
> instance.
> > + @param[in, out] RndisMsg A pointer to the
> REMOTE_NDIS_MSG_HEADER to send out.
> > + @param[in, out] TransferLength The length of the RndisMsg data to
> transfer.
> > +
> > + @retval EFI_SUCCESS The request executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +RndisReceiveDataMsg (
> > + IN USB_RNDIS_DEVICE *UsbRndisDevice,
> > + IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
> > + IN OUT UINTN *TransferLength
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 UsbStatus;
> > +
> > + UsbStatus = 0;
> > +
> > + if (UsbRndisDevice->BulkInEndpoint == 0) {
> > + GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
> > + }
> > +
> > + // Use gStopBulkInCnt to stop BulkIn command
> > + if (gStopBulkInCnt || LAN_BULKIN_CMD_CONTROL) {
> > + Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
> > + UsbRndisDevice->UsbIoCdcData,
> > + UsbRndisDevice->BulkInEndpoint,
> > + RndisMsg,
> > + TransferLength,
> > + USB_RX_ETHERNET_BULK_TIMEOUT,
> > + &UsbStatus
> > + );
> > +
> > + if (!EFI_ERROR (Status)) {
> > + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> > + } else {
> > + gStopBulkInCnt--;
> > + }
> > + } else {
> > + Status = EFI_TIMEOUT;
> > + *TransferLength = 0;
> > + gBlockBulkInCnt++;
> > + }
> > +
> > + if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
> > + gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
> > + gBlockBulkInCnt = 0;
> > + }
> > +
> > + PrintRndisMsg (RndisMsg);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Prints RNDIS Header and Data
> > +
> > + @param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER
> data.
> > +
> > +**/
> > +VOID
> > +PrintRndisMsg (
> > + IN REMOTE_NDIS_MSG_HEADER *RndisMsg
> > + )
> > +{
> > + UINTN Length;
> > + REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
> > +
> > + Length = 0;
> > +
> > + switch (RndisMsg->MessageType) {
> > + case RNDIS_PACKET_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
> > + break;
> > + case RNDIS_INITIALIZE_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
> > + break;
> > + case RNDIS_INITIALIZE_CMPLT:
> > + DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
> > + Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
> > + break;
> > + case RNDIS_HLT_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_HALT_MSG);
> > + break;
> > + case RNDIS_QUERY_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_QUERY_MSG);
> > + break;
> > + case RNDIS_QUERY_CMPLT:
> > + DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
> > + RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
> > + Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) +
> RndisQueryCmplt->InformationBufferLength;
> > + break;
> > + case RNDIS_SET_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_SET_MSG);
> > + break;
> > + case RNDIS_SET_CMPLT:
> > + DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
> > + Length = sizeof (REMOTE_NDIS_SET_CMPLT);
> > + break;
> > + case RNDIS_RESET_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_RESET_MSG);
> > + break;
> > + case RNDIS_RESET_CMPLT:
> > + DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
> > + Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
> > + break;
> > + case RNDIS_INDICATE_STATUS_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
> > + break;
> > + case RNDIS_KEEPALIVE_MSG:
> > + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
> > + Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
> > + break;
> > + case RNDIS_KEEPALIVE_CMPLT:
> > + DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
> > + Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
> > + }
> > +
> > + if (Length) {
> > + UINTN Index = 0;
> > + for ( ; Length; Length -= 4, Index++) {
> > + DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
> > + if (((Index % 4) == 3) && (Index != 0)) {
> > + DEBUG ((DEBUG_INFO, "\n"));
> > + }
> > +
> > + if ((Length < 8) && (Length > 4)) {
> > + UINT32 Data32;
> > + Index++;
> > + Data32 = *((UINT32 *)RndisMsg + Index);
> > + DEBUG ((DEBUG_INFO, "%8X\t", Data32));
> > + break;
> > + }
> > + }
> > +
> > + if (Index % 4) {
> > + DEBUG ((DEBUG_INFO, "\n"));
> > + }
> > + }
> > +}
> > --
> > 2.35.1.windows.2
> > -The information contained in this message may be confidential and
> proprietary to American Megatrends (AMI). This communication is intended
> to be read only by the individual or entity to whom it is addressed or by their
> designee. If the reader of this message is not the intended recipient, you are
> on notice that any distribution of this message, in any form, is strictly
> prohibited. Please promptly notify the sender by reply e-mail or by
> telephone at 770-246-8600, and then delete or destroy all copies of the
> transmission.
> -The information contained in this message may be confidential and
> proprietary to American Megatrends (AMI). This communication is intended
> to be read only by the individual or entity to whom it is addressed or by their
> designee. If the reader of this message is not the intended recipient, you are
> on notice that any distribution of this message, in any form, is strictly
> prohibited. Please promptly notify the sender by reply e-mail or by
> telephone at 770-246-8600, and then delete or destroy all copies of the
> transmission.
>
>
>
>
next prev parent reply other threads:[~2023-04-11 5:08 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-07 11:27 [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
2023-04-07 11:27 ` [PATCH v7 2/3] UsbNetworkPkg/UsbCdcEcm: Add USB Cdc ECM " RichardHo [何明忠]
2023-04-07 11:27 ` [PATCH v7 3/3] UsbNetworkPkg/UsbCdcNcm: Add USB Cdc NCM " RichardHo [何明忠]
2023-04-10 16:02 ` [PATCH v7 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS " Rebecca Cran
2023-04-11 2:21 ` RichardHo [何明忠]
2023-04-11 5:08 ` Chang, Abner [this message]
2023-04-11 12:31 ` Rebecca Cran
2023-04-11 12:38 ` [edk2-devel] " Pedro Falcato
2023-04-12 2:26 ` RichardHo [何明忠]
2023-04-12 4:25 ` Chang, Abner
2023-04-13 2:33 ` RichardHo [何明忠]
2023-04-18 17:16 ` Leif Lindholm
2023-04-19 16:34 ` Rebecca Cran
2023-04-20 1:55 ` RichardHo [何明忠]
2023-04-11 15:20 ` Rebecca Cran
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=MN2PR12MB39664621AB469F3BBC3848F6EA9A9@MN2PR12MB3966.namprd12.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox