summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c
diff options
context:
space:
mode:
Diffstat (limited to 'EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c')
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c
new file mode 100644
index 0000000000..5a41b8a1ee
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c
@@ -0,0 +1,255 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. 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.
+
+Module name:
+ receive.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_receive (
+ SNP_DRIVER *snp,
+ VOID *BufferPtr,
+ UINTN *BuffSizePtr,
+ UINTN *HeaderSizePtr,
+ EFI_MAC_ADDRESS *SourceAddrPtr,
+ EFI_MAC_ADDRESS *DestinationAddrPtr,
+ UINT16 *ProtocolPtr
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to receive a packet and fills in the data in the
+ input pointers!
+
+Arguments:
+ snp - pointer to snp driver structure
+ BufferPtr - pointer to the memory for the received data
+ BuffSizePtr - is a pointer to the length of the buffer on entry and contains
+ the length of the received data on return
+ HeaderSizePtr - pointer to the header portion of the data received.
+ SourceAddrPtr - optional parameter, is a pointer to contain the source
+ ethernet address on return
+ DestinationAddrPtr - optional parameter, is a pointer to contain the destination
+ ethernet address on return
+ ProtocolPtr - optional parameter, is a pointer to contain the protocol type
+ from the ethernet header on return
+
+
+Returns:
+
+--*/
+{
+ PXE_CPB_RECEIVE *cpb;
+ PXE_DB_RECEIVE *db;
+ UINTN buf_size;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ buf_size = *BuffSizePtr;
+ //
+ // IMPORTANT NOTE:
+ // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB,
+ // DO NOT call the map function on the given buffer, instead use
+ // a global buffer. The reason is that UNDI3.0 has some unnecessary check of
+ // making sure that all the addresses (whether or not they will be given
+ // to the NIC ) supplied to it are below 4GB. It may or may not use
+ // the mapped address after all (like in case of CPB and DB)!
+ // Instead of using the global buffer whose address is allocated within the
+ // 2GB limit if I start mapping the given buffer we lose the data, here is
+ // why!!!
+ // if our address is > 4GB, the map call creates another buffer below 2GB and
+ // copies data to/from the original buffer to the mapped buffer either at
+ // map time or unmap time depending on the map direction.
+ // UNDI will not complain since we already mapped the buffer to be
+ // within the 2GB limit but will not use (I know undi) the mapped address
+ // since it does not give the user buffers to the NIC's receive unit,
+ // It just copies the received packet into the user buffer using the virtual
+ // (CPU) address rather than the mapped (device or physical) address.
+ // When the UNDI call returns, if we then unmap the buffer, we will lose
+ // the contents because unmap copies the contents of the mapped buffer into
+ // the original buffer (since the direction is FROM_DEVICE) !!!
+ //
+ // this is not a problem in Undi 3.1 because this undi uses it's map callback
+ // routine to map a cpu address to device address and it does it only if
+ // it is giving the address to the device and unmaps it before using the cpu
+ // address!
+ //
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ cpb->BufferAddr = (UINT64) (UINTN) snp->receive_buf;
+ cpb->BufferLen = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ } else {
+ cpb->BufferAddr = (UINT64) (UINTN) BufferPtr;
+ cpb->BufferLen = (UINT32) *BuffSizePtr;
+ }
+
+ cpb->reserved = 0;
+
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_RECEIVE);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_RECEIVE);
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_INFO, "\nsnp->undi.receive () "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_NO_DATA:
+ DEBUG (
+ (EFI_D_INFO,
+ "\nsnp->undi.receive () %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_NOT_READY;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ *BuffSizePtr = db->FrameLen;
+
+ if (HeaderSizePtr != NULL) {
+ *HeaderSizePtr = db->MediaHeaderLen;
+ }
+
+ if (SourceAddrPtr != NULL) {
+ CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize);
+ }
+
+ if (DestinationAddrPtr != NULL) {
+ CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize);
+ }
+
+ if (ProtocolPtr != NULL) {
+ *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /* we need to do the byte swapping */
+ }
+
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ }
+
+ return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINTN *HeaderSizePtr OPTIONAL,
+ IN OUT UINTN *BuffSizePtr,
+ OUT VOID *BufferPtr,
+ OUT EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
+ OUT EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
+ OUT UINT16 *ProtocolPtr OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for receiving network data.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_receive routine to actually do the receive!
+
+Arguments:
+ this - context pointer
+ HeaderSizePtr - optional parameter and is a pointer to the header portion of
+ the data received.
+ BuffSizePtr - is a pointer to the length of the buffer on entry and contains
+ the length of the received data on return
+ BufferPtr - pointer to the memory for the received data
+ SourceAddrPtr - optional parameter, is a pointer to contain the source
+ ethernet address on return
+ DestinationAddrPtr - optional parameter, is a pointer to contain the destination
+ ethernet address on return
+ ProtocolPtr - optional parameter, is a pointer to contain the protocol type
+ from the ethernet header on return
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!snp->mode.ReceiveFilterSetting) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return pxe_receive (
+ snp,
+ BufferPtr,
+ BuffSizePtr,
+ HeaderSizePtr,
+ SourceAddrPtr,
+ DestinationAddrPtr,
+ ProtocolPtr
+ );
+}