Files
system76-edk2/MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c
Mike Maslenkin 03d6569f70 MdeModulePkg: UsbRndis: get rid of magic values
Replace magic values used for checking Base Class, SubClass and Protocol
fields of USB Interface Descriptor.
Add definitions for Base Class EFh (Miscellaneous) and RNDIS subclass.
These definitions were taken from https://www.usb.org/defined-class-codes

Cc: Richard Ho <richardho@ami.com>
Cc: Rebecca Cran <rebecca@bsdio.com>
Signed-off-by: Mike Maslenkin <mike.maslenkin@gmail.com>
2023-10-16 22:49:33 +00:00

887 lines
28 KiB
C

/** @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 == USB_CDC_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_CDC_ACM_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_VENDOR_PROTOCOL)) || \
((InterfaceDescriptor.InterfaceClass == USB_MISC_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_RNDIS_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_RNDIS_ETHERNET_PROTOCOL)) || \
((InterfaceDescriptor.InterfaceClass == USB_CDC_DATA_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_CDC_DATA_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
)
{
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 == USB_CDC_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_CDC_ACM_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_VENDOR_PROTOCOL)) || \
((InterfaceDescriptor.InterfaceClass == USB_MISC_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_RNDIS_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_RNDIS_ETHERNET_PROTOCOL))
)
{
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 == USB_CDC_DATA_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_CDC_DATA_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
{
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 == USB_CDC_CLASS) &&
(InterfaceDescriptor.InterfaceSubClass == USB_CDC_ACM_SUBCLASS) &&
(InterfaceDescriptor.InterfaceProtocol == USB_VENDOR_PROTOCOL))
{
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
);
}