Home | History | Annotate | Download | only in SnpDxe
      1 /** @file
      2   Implementation of receiving a packet from a network interface.
      3 
      4 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed
      6 and made available under the terms and conditions of the BSD License which
      7 accompanies this distribution. The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 
     16 #include "Snp.h"
     17 
     18 /**
     19   Call UNDI to receive a packet and fills in the data in the input pointers.
     20 
     21   @param  Snp          Pointer to snp driver structure
     22   @param  Buffer       Pointer to the memory for the received data
     23   @param  BufferSize   Pointer to the length of the buffer on entry and contains
     24                        the length of the received data on return
     25   @param  HeaderSize   Pointer to the header portion of the data received.
     26   @param  SrcAddr      Pointer to contain the source ethernet address on return
     27   @param  DestAddr     Pointer to contain the destination ethernet address on
     28                        return
     29   @param  Protocol     Pointer to contain the protocol type from the ethernet
     30                        header on return
     31 
     32 
     33   @retval EFI_SUCCESS           The received data was stored in Buffer, and
     34                                 BufferSize has been updated to the number of
     35                                 bytes received.
     36   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
     37   @retval EFI_NOT_READY         No packets have been received on the network
     38                                 interface.
     39   @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small for the received
     40                                 packets. BufferSize has been updated to the
     41                                 required size.
     42 
     43 **/
     44 EFI_STATUS
     45 PxeReceive (
     46   SNP_DRIVER      *Snp,
     47   VOID            *Buffer,
     48   UINTN           *BufferSize,
     49   UINTN           *HeaderSize,
     50   EFI_MAC_ADDRESS *SrcAddr,
     51   EFI_MAC_ADDRESS *DestAddr,
     52   UINT16          *Protocol
     53   )
     54 {
     55   PXE_CPB_RECEIVE *Cpb;
     56   PXE_DB_RECEIVE  *Db;
     57   UINTN           BuffSize;
     58 
     59   Cpb       = Snp->Cpb;
     60   Db        = Snp->Db;
     61   BuffSize  = *BufferSize;
     62 
     63   Cpb->BufferAddr = (UINT64)(UINTN) Buffer;
     64   Cpb->BufferLen  = (UINT32) *BufferSize;
     65 
     66   Cpb->reserved       = 0;
     67 
     68   Snp->Cdb.OpCode     = PXE_OPCODE_RECEIVE;
     69   Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;
     70 
     71   Snp->Cdb.CPBsize    = (UINT16) sizeof (PXE_CPB_RECEIVE);
     72   Snp->Cdb.CPBaddr    = (UINT64)(UINTN) Cpb;
     73 
     74   Snp->Cdb.DBsize     = (UINT16) sizeof (PXE_DB_RECEIVE);
     75   Snp->Cdb.DBaddr     = (UINT64)(UINTN) Db;
     76 
     77   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
     78   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
     79   Snp->Cdb.IFnum      = Snp->IfNum;
     80   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
     81 
     82   //
     83   // Issue UNDI command and check result.
     84   //
     85   DEBUG ((EFI_D_NET, "\nsnp->undi.receive ()  "));
     86 
     87   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
     88 
     89   switch (Snp->Cdb.StatCode) {
     90   case PXE_STATCODE_SUCCESS:
     91     break;
     92 
     93   case PXE_STATCODE_NO_DATA:
     94     DEBUG (
     95       (EFI_D_NET,
     96       "\nsnp->undi.receive ()  %xh:%xh\n",
     97       Snp->Cdb.StatFlags,
     98       Snp->Cdb.StatCode)
     99       );
    100 
    101     return EFI_NOT_READY;
    102 
    103   default:
    104     DEBUG (
    105       (EFI_D_ERROR,
    106       "\nsnp->undi.receive()  %xh:%xh\n",
    107       Snp->Cdb.StatFlags,
    108       Snp->Cdb.StatCode)
    109       );
    110 
    111     return EFI_DEVICE_ERROR;
    112   }
    113 
    114   *BufferSize = Db->FrameLen;
    115 
    116   if (HeaderSize != NULL) {
    117     *HeaderSize = Db->MediaHeaderLen;
    118   }
    119 
    120   if (SrcAddr != NULL) {
    121     CopyMem (SrcAddr, &Db->SrcAddr, Snp->Mode.HwAddressSize);
    122   }
    123 
    124   if (DestAddr != NULL) {
    125     CopyMem (DestAddr, &Db->DestAddr, Snp->Mode.HwAddressSize);
    126   }
    127 
    128   if (Protocol != NULL) {
    129     //
    130     // We need to do the byte swapping
    131     //
    132     *Protocol = (UINT16) PXE_SWAP_UINT16 (Db->Protocol);
    133   }
    134 
    135   //
    136   // We have received a packet from network interface, which implies that the
    137   // network cable should be present. While, some UNDI driver may not report
    138   // correct media status during Snp->Initialize(). So, we need ensure
    139   // MediaPresent in SNP mode data is set to correct value.
    140   //
    141   if (Snp->Mode.MediaPresentSupported && !Snp->Mode.MediaPresent) {
    142     Snp->Mode.MediaPresent = TRUE;
    143   }
    144 
    145   return (*BufferSize <= BuffSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
    146 }
    147 
    148 /**
    149   Receives a packet from a network interface.
    150 
    151   This function retrieves one packet from the receive queue of a network interface.
    152   If there are no packets on the receive queue, then EFI_NOT_READY will be
    153   returned. If there is a packet on the receive queue, and the size of the packet
    154   is smaller than BufferSize, then the contents of the packet will be placed in
    155   Buffer, and BufferSize will be updated with the actual size of the packet.
    156   In addition, if SrcAddr, DestAddr, and Protocol are not NULL, then these values
    157   will be extracted from the media header and returned. EFI_SUCCESS will be
    158   returned if a packet was successfully received.
    159   If BufferSize is smaller than the received packet, then the size of the receive
    160   packet will be placed in BufferSize and EFI_BUFFER_TOO_SMALL will be returned.
    161   If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
    162 
    163   @param This       A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
    164   @param HeaderSize The size, in bytes, of the media header received on the network
    165                     interface. If this parameter is NULL, then the media header size
    166                     will not be returned.
    167   @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
    168                     bytes, of the packet that was received on the network interface.
    169   @param Buffer     A pointer to the data buffer to receive both the media
    170                     header and the data.
    171   @param SrcAddr    The source HW MAC address. If this parameter is NULL, the HW
    172                     MAC source address will not be extracted from the media header.
    173   @param DestAddr   The destination HW MAC address. If this parameter is NULL,
    174                     the HW MAC destination address will not be extracted from
    175                     the media header.
    176   @param Protocol   The media header type. If this parameter is NULL, then the
    177                     protocol will not be extracted from the media header. See
    178                     RFC 1700 section "Ether Types" for examples.
    179 
    180   @retval EFI_SUCCESS           The received data was stored in Buffer, and
    181                                 BufferSize has been updated to the number of
    182                                 bytes received.
    183   @retval EFI_NOT_STARTED       The network interface has not been started.
    184   @retval EFI_NOT_READY         No packets have been received on the network interface.
    185   @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small for the received packets.
    186                                 BufferSize has been updated to the required size.
    187   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    188                                 * The This parameter is NULL
    189                                 * The This parameter does not point to a valid
    190                                   EFI_SIMPLE_NETWORK_PROTOCOL structure.
    191                                 * The BufferSize parameter is NULL
    192                                 * The Buffer parameter is NULL
    193   @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
    194 
    195 **/
    196 EFI_STATUS
    197 EFIAPI
    198 SnpUndi32Receive (
    199   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
    200   OUT UINTN                      *HeaderSize OPTIONAL,
    201   IN OUT UINTN                   *BufferSize,
    202   OUT VOID                       *Buffer,
    203   OUT EFI_MAC_ADDRESS            *SrcAddr OPTIONAL,
    204   OUT EFI_MAC_ADDRESS            *DestAddr OPTIONAL,
    205   OUT UINT16                     *Protocol OPTIONAL
    206   )
    207 {
    208   SNP_DRIVER  *Snp;
    209   EFI_TPL     OldTpl;
    210   EFI_STATUS  Status;
    211 
    212   if (This == NULL) {
    213     return EFI_INVALID_PARAMETER;
    214   }
    215 
    216   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
    217 
    218   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    219 
    220   switch (Snp->Mode.State) {
    221   case EfiSimpleNetworkInitialized:
    222     break;
    223 
    224   case EfiSimpleNetworkStopped:
    225     Status = EFI_NOT_STARTED;
    226     goto ON_EXIT;
    227 
    228   default:
    229     Status = EFI_DEVICE_ERROR;
    230     goto ON_EXIT;
    231   }
    232 
    233   if ((BufferSize == NULL) || (Buffer == NULL)) {
    234     Status = EFI_INVALID_PARAMETER;
    235     goto ON_EXIT;
    236   }
    237 
    238   if (Snp->Mode.ReceiveFilterSetting == 0) {
    239     Status = EFI_DEVICE_ERROR;
    240     goto ON_EXIT;
    241   }
    242 
    243   Status = PxeReceive (
    244              Snp,
    245              Buffer,
    246              BufferSize,
    247              HeaderSize,
    248              SrcAddr,
    249              DestAddr,
    250              Protocol
    251              );
    252 
    253 ON_EXIT:
    254   gBS->RestoreTPL (OldTpl);
    255 
    256   return Status;
    257 }
    258