audk/MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndis.c

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
);
}