https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			186 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
|   Implementation of the SNP.Receive() function and its private helpers if any.
 | |
| 
 | |
|   Copyright (C) 2013, Red Hat, Inc.
 | |
|   Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| 
 | |
| #include "VirtioNet.h"
 | |
| 
 | |
| /**
 | |
|   Receives a packet from a network interface.
 | |
| 
 | |
|   @param  This       The protocol instance pointer.
 | |
|   @param  HeaderSize The size, in bytes, of the media header received on the
 | |
|                      network interface. If this parameter is NULL, then the
 | |
|                      media header size will not be returned.
 | |
|   @param  BufferSize On entry, the size, in bytes, of Buffer. On exit, the
 | |
|                      size, in bytes, of the packet that was received on the
 | |
|                      network interface.
 | |
|   @param  Buffer     A pointer to the data buffer to receive both the media
 | |
|                      header and the data.
 | |
|   @param  SrcAddr    The source HW MAC address. If this parameter is NULL, the
 | |
|                      HW MAC source address will not be extracted from the media
 | |
|                      header.
 | |
|   @param  DestAddr   The destination HW MAC address. If this parameter is NULL,
 | |
|                      the HW MAC destination address will not be extracted from
 | |
|                      the media header.
 | |
|   @param  Protocol   The media header type. If this parameter is NULL, then the
 | |
|                      protocol will not be extracted from the media header. See
 | |
|                      RFC 1700 section "Ether Types" for examples.
 | |
| 
 | |
|   @retval  EFI_SUCCESS           The received data was stored in Buffer, and
 | |
|                                  BufferSize has been updated to the number of
 | |
|                                  bytes received.
 | |
|   @retval  EFI_NOT_STARTED       The network interface has not been started.
 | |
|   @retval  EFI_NOT_READY         The network interface is too busy to accept
 | |
|                                  this transmit request.
 | |
|   @retval  EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.
 | |
|   @retval  EFI_INVALID_PARAMETER One or more of the parameters has an
 | |
|                                  unsupported value.
 | |
|   @retval  EFI_DEVICE_ERROR      The command could not be sent to the network
 | |
|                                  interface.
 | |
|   @retval  EFI_UNSUPPORTED       This function is not supported by the network
 | |
|                                  interface.
 | |
| 
 | |
| **/
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| VirtioNetReceive (
 | |
|   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
 | |
|   OUT UINTN                      *HeaderSize OPTIONAL,
 | |
|   IN OUT UINTN                   *BufferSize,
 | |
|   OUT VOID                       *Buffer,
 | |
|   OUT EFI_MAC_ADDRESS            *SrcAddr    OPTIONAL,
 | |
|   OUT EFI_MAC_ADDRESS            *DestAddr   OPTIONAL,
 | |
|   OUT UINT16                     *Protocol   OPTIONAL
 | |
|   )
 | |
| {
 | |
|   VNET_DEV   *Dev;
 | |
|   EFI_TPL    OldTpl;
 | |
|   EFI_STATUS Status;
 | |
|   UINT16     RxCurUsed;
 | |
|   UINT16     UsedElemIdx;
 | |
|   UINT32     DescIdx;
 | |
|   UINT32     RxLen;
 | |
|   UINTN      OrigBufferSize;
 | |
|   UINT8      *RxPtr;
 | |
|   UINT16     AvailIdx;
 | |
|   EFI_STATUS NotifyStatus;
 | |
|   UINTN      RxBufOffset;
 | |
| 
 | |
|   if (This == NULL || BufferSize == NULL || Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Dev = VIRTIO_NET_FROM_SNP (This);
 | |
|   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | |
|   switch (Dev->Snm.State) {
 | |
|   case EfiSimpleNetworkStopped:
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   case EfiSimpleNetworkStarted:
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto Exit;
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
 | |
|   //
 | |
|   MemoryFence ();
 | |
|   RxCurUsed = *Dev->RxRing.Used.Idx;
 | |
|   MemoryFence ();
 | |
| 
 | |
|   if (Dev->RxLastUsed == RxCurUsed) {
 | |
|     Status = EFI_NOT_READY;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   UsedElemIdx = Dev->RxLastUsed % Dev->RxRing.QueueSize;
 | |
|   DescIdx = Dev->RxRing.Used.UsedElem[UsedElemIdx].Id;
 | |
|   RxLen   = Dev->RxRing.Used.UsedElem[UsedElemIdx].Len;
 | |
| 
 | |
|   //
 | |
|   // the virtio-net request header must be complete; we skip it
 | |
|   //
 | |
|   ASSERT (RxLen >= Dev->RxRing.Desc[DescIdx].Len);
 | |
|   RxLen -= Dev->RxRing.Desc[DescIdx].Len;
 | |
|   //
 | |
|   // the host must not have filled in more data than requested
 | |
|   //
 | |
|   ASSERT (RxLen <= Dev->RxRing.Desc[DescIdx + 1].Len);
 | |
| 
 | |
|   OrigBufferSize = *BufferSize;
 | |
|   *BufferSize = RxLen;
 | |
| 
 | |
|   if (OrigBufferSize < RxLen) {
 | |
|     Status = EFI_BUFFER_TOO_SMALL;
 | |
|     goto Exit; // keep the packet
 | |
|   }
 | |
| 
 | |
|   if (RxLen < Dev->Snm.MediaHeaderSize) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto RecycleDesc; // drop useless short packet
 | |
|   }
 | |
| 
 | |
|   if (HeaderSize != NULL) {
 | |
|     *HeaderSize = Dev->Snm.MediaHeaderSize;
 | |
|   }
 | |
| 
 | |
|   RxBufOffset = (UINTN)(Dev->RxRing.Desc[DescIdx + 1].Addr -
 | |
|                         Dev->RxBufDeviceBase);
 | |
|   RxPtr = Dev->RxBuf + RxBufOffset;
 | |
|   CopyMem (Buffer, RxPtr, RxLen);
 | |
| 
 | |
|   if (DestAddr != NULL) {
 | |
|     CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (Mac));
 | |
|   }
 | |
|   RxPtr += SIZE_OF_VNET (Mac);
 | |
| 
 | |
|   if (SrcAddr != NULL) {
 | |
|     CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (Mac));
 | |
|   }
 | |
|   RxPtr += SIZE_OF_VNET (Mac);
 | |
| 
 | |
|   if (Protocol != NULL) {
 | |
|     *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
 | |
|   }
 | |
|   RxPtr += sizeof (UINT16);
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
| RecycleDesc:
 | |
|   ++Dev->RxLastUsed;
 | |
| 
 | |
|   //
 | |
|   // virtio-0.9.5, 2.4.1 Supplying Buffers to The Device
 | |
|   //
 | |
|   AvailIdx = *Dev->RxRing.Avail.Idx;
 | |
|   Dev->RxRing.Avail.Ring[AvailIdx++ % Dev->RxRing.QueueSize] =
 | |
|     (UINT16) DescIdx;
 | |
| 
 | |
|   MemoryFence ();
 | |
|   *Dev->RxRing.Avail.Idx = AvailIdx;
 | |
| 
 | |
|   MemoryFence ();
 | |
|   NotifyStatus = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);
 | |
|   if (!EFI_ERROR (Status)) { // earlier error takes precedence
 | |
|     Status = NotifyStatus;
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 |