/** @file This file contains code for USB Remote Network Driver Interface Spec. Driver Binding Copyright (c) 2023, American Megatrends International LLC. All rights reserved.
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 ); }