]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/SnpDxe/Transmit.c
NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
[mirror_edk2.git] / NetworkPkg / SnpDxe / Transmit.c
diff --git a/NetworkPkg/SnpDxe/Transmit.c b/NetworkPkg/SnpDxe/Transmit.c
new file mode 100644 (file)
index 0000000..44fdd71
--- /dev/null
@@ -0,0 +1,353 @@
+/** @file\r
+    Implementation of transmitting a packet.\r
+\r
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+  Call UNDI to create the meadia header for the given data buffer.\r
+\r
+  @param  Snp              Pointer to SNP driver structure.\r
+  @param  MacHeaderPtr     Address where the media header will be filled in.\r
+  @param  HeaderSize       Size of the memory at MacHeaderPtr.\r
+  @param  Buffer           Data buffer pointer.\r
+  @param  BufferSize       Size of data in the Buffer\r
+  @param  DestAddr         Address of the destination mac address buffer.\r
+  @param  SrcAddr          Address of the source mac address buffer.\r
+  @param  ProtocolPtr      Address of the protocol type.\r
+\r
+  @retval EFI_SUCCESS      Successfully completed the undi call.\r
+  @retval Other            Error return from undi call.\r
+\r
+**/\r
+EFI_STATUS\r
+PxeFillHeader (\r
+  SNP_DRIVER      *Snp,\r
+  VOID            *MacHeaderPtr,\r
+  UINTN           HeaderSize,\r
+  VOID            *Buffer,\r
+  UINTN           BufferSize,\r
+  EFI_MAC_ADDRESS *DestAddr,\r
+  EFI_MAC_ADDRESS *SrcAddr,\r
+  UINT16          *ProtocolPtr\r
+  )\r
+{\r
+  PXE_CPB_FILL_HEADER_FRAGMENTED  *Cpb;\r
+\r
+  Cpb = Snp->Cpb;\r
+  if (SrcAddr != NULL) {\r
+    CopyMem (\r
+      (VOID *) Cpb->SrcAddr,\r
+      (VOID *) SrcAddr,\r
+      Snp->Mode.HwAddressSize\r
+      );\r
+  } else {\r
+    CopyMem (\r
+      (VOID *) Cpb->SrcAddr,\r
+      (VOID *) &(Snp->Mode.CurrentAddress),\r
+      Snp->Mode.HwAddressSize\r
+      );\r
+  }\r
+\r
+  CopyMem (\r
+    (VOID *) Cpb->DestAddr,\r
+    (VOID *) DestAddr,\r
+    Snp->Mode.HwAddressSize\r
+    );\r
+\r
+  //\r
+  // we need to do the byte swapping\r
+  //\r
+  Cpb->Protocol             = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);\r
+\r
+  Cpb->PacketLen            = (UINT32) (BufferSize);\r
+  Cpb->MediaHeaderLen       = (UINT16) HeaderSize;\r
+\r
+  Cpb->FragCnt              = 2;\r
+  Cpb->reserved             = 0;\r
+\r
+  Cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;\r
+  Cpb->FragDesc[0].FragLen  = (UINT32) HeaderSize;\r
+  Cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) Buffer;\r
+  Cpb->FragDesc[1].FragLen  = (UINT32) BufferSize;\r
+\r
+  Cpb->FragDesc[0].reserved = Cpb->FragDesc[1].reserved = 0;\r
+\r
+  Snp->Cdb.OpCode     = PXE_OPCODE_FILL_HEADER;\r
+  Snp->Cdb.OpFlags    = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;\r
+\r
+  Snp->Cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  Snp->Cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+\r
+  Snp->Cdb.CPBsize    = (UINT16) sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);\r
+  Snp->Cdb.CPBaddr    = (UINT64)(UINTN) Cpb;\r
+\r
+  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  Snp->Cdb.IFnum      = Snp->IfNum;\r
+  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nSnp->undi.fill_header()  "));\r
+\r
+  (*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);\r
+\r
+  switch (Snp->Cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    return EFI_SUCCESS;\r
+\r
+  case PXE_STATCODE_INVALID_PARAMETER:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nSnp->undi.fill_header()  %xh:%xh\n",\r
+      Snp->Cdb.StatFlags,\r
+      Snp->Cdb.StatCode)\r
+      );\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+\r
+  default:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nSnp->undi.fill_header()  %xh:%xh\n",\r
+      Snp->Cdb.StatFlags,\r
+      Snp->Cdb.StatCode)\r
+      );\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This routine calls undi to transmit the given data buffer\r
+\r
+  @param  Snp                 pointer to SNP driver structure\r
+  @param  Buffer           data buffer pointer\r
+  @param  BufferSize        Size of data in the Buffer\r
+\r
+  @retval EFI_SUCCESS         if successfully completed the undi call\r
+  @retval Other               error return from undi call.\r
+\r
+**/\r
+EFI_STATUS\r
+PxeTransmit (\r
+  SNP_DRIVER *Snp,\r
+  VOID       *Buffer,\r
+  UINTN      BufferSize\r
+  )\r
+{\r
+  PXE_CPB_TRANSMIT  *Cpb;\r
+  EFI_STATUS        Status;\r
+\r
+  Cpb             = Snp->Cpb;\r
+  Cpb->FrameAddr  = (UINT64) (UINTN) Buffer;\r
+  Cpb->DataLen    = (UINT32) BufferSize;\r
+\r
+  Cpb->MediaheaderLen = 0;\r
+  Cpb->reserved       = 0;\r
+\r
+  Snp->Cdb.OpFlags    = PXE_OPFLAGS_TRANSMIT_WHOLE;\r
+\r
+  Snp->Cdb.CPBsize    = (UINT16) sizeof (PXE_CPB_TRANSMIT);\r
+  Snp->Cdb.CPBaddr    = (UINT64)(UINTN) Cpb;\r
+\r
+  Snp->Cdb.OpCode     = PXE_OPCODE_TRANSMIT;\r
+  Snp->Cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
+  Snp->Cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
+\r
+  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
+  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
+  Snp->Cdb.IFnum      = Snp->IfNum;\r
+  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+  //\r
+  // Issue UNDI command and check result.\r
+  //\r
+  DEBUG ((EFI_D_NET, "\nSnp->undi.transmit()  "));\r
+  DEBUG ((EFI_D_NET, "\nSnp->Cdb.OpCode  == %x", Snp->Cdb.OpCode));\r
+  DEBUG ((EFI_D_NET, "\nSnp->Cdb.CPBaddr == %LX", Snp->Cdb.CPBaddr));\r
+  DEBUG ((EFI_D_NET, "\nSnp->Cdb.DBaddr  == %LX", Snp->Cdb.DBaddr));\r
+  DEBUG ((EFI_D_NET, "\nCpb->FrameAddr   == %LX\n", Cpb->FrameAddr));\r
+\r
+  (*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);\r
+\r
+  DEBUG ((EFI_D_NET, "\nexit Snp->undi.transmit()  "));\r
+\r
+  //\r
+  // we will unmap the buffers in get_status call, not here\r
+  //\r
+  switch (Snp->Cdb.StatCode) {\r
+  case PXE_STATCODE_SUCCESS:\r
+    return EFI_SUCCESS;\r
+\r
+  case PXE_STATCODE_BUFFER_FULL:\r
+  case PXE_STATCODE_QUEUE_FULL:\r
+  case PXE_STATCODE_BUSY:\r
+    Status = EFI_NOT_READY;\r
+    DEBUG (\r
+      (EFI_D_NET,\r
+      "\nSnp->undi.transmit()  %xh:%xh\n",\r
+      Snp->Cdb.StatFlags,\r
+      Snp->Cdb.StatCode)\r
+      );\r
+    break;\r
+\r
+  default:\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "\nSnp->undi.transmit()  %xh:%xh\n",\r
+      Snp->Cdb.StatFlags,\r
+      Snp->Cdb.StatCode)\r
+      );\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Places a packet in the transmit queue of a network interface.\r
+\r
+  This function places the packet specified by Header and Buffer on the transmit\r
+  queue. If HeaderSize is nonzero and HeaderSize is not equal to\r
+  This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If\r
+  BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL\r
+  will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be\r
+  returned. If HeaderSize is nonzero and DestAddr or Protocol is NULL, then\r
+  EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network\r
+  interface is busy, then EFI_NOT_READY will be returned. If this packet can be\r
+  accepted by the transmit engine of the network interface, the packet contents\r
+  specified by Buffer will be placed on the transmit queue of the network\r
+  interface, and EFI_SUCCESS will be returned. GetStatus() can be used to\r
+  determine when the packet has actually been transmitted. The contents of the\r
+  Buffer must not be modified until the packet has actually been transmitted.\r
+  The Transmit() function performs nonblocking I/O. A caller who wants to perform\r
+  blocking I/O, should call Transmit(), and then GetStatus() until the\r
+  transmitted buffer shows up in the recycled transmit buffer.\r
+  If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.\r
+\r
+  @param This       A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.\r
+  @param HeaderSize The size, in bytes, of the media header to be filled in by the\r
+                    Transmit() function. If HeaderSize is nonzero, then it must\r
+                    be equal to This->Mode->MediaHeaderSize and the DestAddr and\r
+                    Protocol parameters must not be NULL.\r
+  @param BufferSize The size, in bytes, of the entire packet (media header and\r
+                    data) to be transmitted through the network interface.\r
+  @param Buffer     A pointer to the packet (media header followed by data) to be\r
+                    transmitted. This parameter cannot be NULL. If HeaderSize is\r
+                    zero, then the media header in Buffer must already be filled\r
+                    in by the caller. If HeaderSize is nonzero, then the media\r
+                    header will be filled in by the Transmit() function.\r
+  @param SrcAddr    The source HW MAC address. If HeaderSize is zero, then this\r
+                    parameter is ignored. If HeaderSize is nonzero and SrcAddr\r
+                    is NULL, then This->Mode->CurrentAddress is used for the\r
+                    source HW MAC address.\r
+  @param DestAddr   The destination HW MAC address. If HeaderSize is zero, then\r
+                    this parameter is ignored.\r
+  @param Protocol   The type of header to build. If HeaderSize is zero, then this\r
+                    parameter is ignored. See RFC 1700, section "Ether Types,"\r
+                    for examples.\r
+\r
+  @retval EFI_SUCCESS           The packet was placed on the transmit queue.\r
+  @retval EFI_NOT_STARTED       The network interface has not been started.\r
+  @retval EFI_NOT_READY         The network interface is too busy to accept this\r
+                                transmit request.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.\r
+  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported\r
+                                value.\r
+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.\r
+  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SnpUndi32Transmit (\r
+  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r
+  IN UINTN                       HeaderSize,\r
+  IN UINTN                       BufferSize,\r
+  IN VOID                        *Buffer,\r
+  IN EFI_MAC_ADDRESS             *SrcAddr,  OPTIONAL\r
+  IN EFI_MAC_ADDRESS             *DestAddr, OPTIONAL\r
+  IN UINT16                      *Protocol  OPTIONAL\r
+  )\r
+{\r
+  SNP_DRIVER  *Snp;\r
+  EFI_STATUS  Status;\r
+  EFI_TPL     OldTpl;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (Snp == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  switch (Snp->Mode.State) {\r
+  case EfiSimpleNetworkInitialized:\r
+    break;\r
+\r
+  case EfiSimpleNetworkStopped:\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_EXIT;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (BufferSize < Snp->Mode.MediaHeaderSize) {\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // if the HeaderSize is non-zero, we need to fill up the header and for that\r
+  // we need the destination address and the protocol\r
+  //\r
+  if (HeaderSize != 0) {\r
+    if (HeaderSize != Snp->Mode.MediaHeaderSize || DestAddr == 0 || Protocol == 0) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = PxeFillHeader (\r
+              Snp,\r
+              Buffer,\r
+              HeaderSize,\r
+              (UINT8 *) Buffer + HeaderSize,\r
+              BufferSize - HeaderSize,\r
+              DestAddr,\r
+              SrcAddr,\r
+              Protocol\r
+              );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  Status = PxeTransmit (Snp, Buffer, BufferSize);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r