This patch fixes wrong condition because of UINT16 value to integer promotion. NumberMcFilters is UINT16 value, so when bitwise shift operator applied to small integer type, the operation is preceded by integral promotion. This is described in MISRA-C:2004 guideline as Rule 10.5: "If the bitwise operators ~ and << are applied to an operand of underlying type unsigned char or unsigned short, the result shall be immediately cast to the underlying type of the operand." A simple fix for this issue would be the following: if ((UINT16)(UsbEthFunDescriptor.NumberMcFilters << 1) == 0) But this patch proposes to use bitwise AND operation with a proper bit mask rather than shifting to prevent similar mistakes in future. Cc: Richard Ho <richardho@ami.com> Cc: Rebecca Cran <rebecca@bsdio.com> Signed-off-by: Mike Maslenkin <mike.maslenkin@gmail.com>
		
			
				
	
	
		
			1722 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1722 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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", __func__, Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiBootServicesData,
 | |
|                   Tmp.TotalLength,
 | |
|                   (VOID **)ConfigDesc
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __func__, 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", __func__, Status));
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (Interface.NumEndpoints == 0 ) {
 | |
|     Status = UsbSetInterface (UsbIo, 1, 0, &Result);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __func__, Status));
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __func__, 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", __func__, 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]  Requst            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) {
 | |
|     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]  UsbRndisDevice    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", __func__, 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", __func__, 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 & MAC_FILTERS_MASK) == 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
 | |
|                                   );
 | |
| }
 | |
| 
 | |
| BIT_MAP  gTable[] = {
 | |
|   { 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 },
 | |
| };
 | |
| 
 | |
| /**
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   Count = sizeof (gTable)/sizeof (gTable[0]);
 | |
| 
 | |
|   for (Index = 0; (gTable[Index].Src != 0) && (Index < Count); Index++) {
 | |
|     if (gTable[Index].Src & Value) {
 | |
|       *CdcFilter |= gTable[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 & MAC_FILTERS_MASK) == 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;
 | |
|   EFI_USB_DEVICE_REQUEST        DevReq;
 | |
|   UINT32                        UsbStatus;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINT32                        SaveResponseType;
 | |
|   UINT32                        SaveResponseLength;
 | |
|   UINT32                        Index;
 | |
|   REMOTE_NDIS_INITIALIZE_CMPLT  *RndisInitCmplt;
 | |
| 
 | |
|   UsbIo              = UsbRndisDevice->UsbIo;
 | |
|   SaveResponseType   = 0;
 | |
|   SaveResponseLength = 0;
 | |
|   RndisInitCmplt     = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
 | |
| 
 | |
|   if (RndisMsgResponse != NULL) {
 | |
|     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 != 0) || 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;
 | |
|     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) != 0) {
 | |
|       DEBUG ((DEBUG_INFO, "\n"));
 | |
|     }
 | |
|   }
 | |
| }
 |