summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c')
-rw-r--r--MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c886
1 files changed, 886 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c
new file mode 100644
index 0000000000..056b0ff0fd
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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] UsbCdcDataPath 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", __func__, 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", __func__, 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", __func__, 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
+ );
+}