Contributed-under: TianoCore Contribution Agreement 1.0

Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 OvmfPkg/VirtioNetDxe/SnpReceive.c |  190 +++++++++++++++++++++++++++++++++++++
 1 files changed, 190 insertions(+), 0 deletions(-)
 create mode 100644 OvmfPkg/VirtioNetDxe/SnpReceive.c

diff --git a/OvmfPkg/VirtioNetDxe/SnpReceive.c 
b/OvmfPkg/VirtioNetDxe/SnpReceive.c
new file mode 100644
index 0000000..c7d733b
--- /dev/null
+++ b/OvmfPkg/VirtioNetDxe/SnpReceive.c
@@ -0,0 +1,190 @@
+/** @file
+
+  Implementation of the SNP.Receive() function and its private helpers if any.
+
+  Copyright (C) 2013, Red Hat, Inc.
+
+  UEFI API documentation:
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution. The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+
+  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;
+
+  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;
+  }
+
+  RxPtr = (UINT8 *)Dev->RxRing.Desc[DescIdx + 1].Addr;
+  CopyMem (Buffer, RxPtr, RxLen);
+
+  if (DestAddr != NULL) {
+    CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (VhdrMac));
+  }
+  RxPtr += SIZE_OF_VNET (VhdrMac);
+
+  if (SrcAddr != NULL) {
+    CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (VhdrMac));
+  }
+  RxPtr += SIZE_OF_VNET (VhdrMac);
+
+  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] = DescIdx;
+
+  MemoryFence ();
+  *Dev->RxRing.Avail.Idx = AvailIdx;
+
+  MemoryFence ();
+  NotifyStatus = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify,
+                   VIRTIO_NET_Q_RX);
+
+  if (!EFI_ERROR (Status)) { // earlier error takes precedence
+    Status = NotifyStatus;
+  }
+
+Exit:
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
-- 
1.7.1



------------------------------------------------------------------------------
AlienVault Unified Security Management (USM) platform delivers complete
security visibility with the essential security capabilities. Easily and
efficiently configure, manage, and operate all of your security controls
from a single console and one unified framework. Download a free trial.
http://p.sf.net/sfu/alienvault_d2d
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to