This patch fixes wrong condition because of UINT16 value to integer promotion. NumberMcFilters is UINT16 value, so when bitwise shift operator applied to small integer type, the operation is preceded by integral promotion. This is described in MISRA-C:2004 guideline as Rule 10.5: "If the bitwise operators ~ and << are applied to an operand of underlying type unsigned char or unsigned short, the result shall be immediately cast to the underlying type of the operand." A simple fix for this issue would be the following: if ((UINT16)(UsbEthFunDescriptor.NumberMcFilters << 1) == 0) But this patch proposes to use bitwise AND operation with a proper bit mask rather than shifting to prevent similar mistakes in future. Cc: Richard Ho <richardho@ami.com> Cc: Rebecca Cran <rebecca@bsdio.com> Signed-off-by: Mike Maslenkin <mike.maslenkin@gmail.com>
		
			
				
	
	
		
			1806 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1806 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This file contains code for UNDI command based on UEFI specification.
 | 
						|
 | 
						|
  Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
 | 
						|
#include "DriverBinding.h"
 | 
						|
 | 
						|
// API table, defined in UEFI specification
 | 
						|
API_FUNC  gUndiApiTable[] = {
 | 
						|
  UndiGetState,
 | 
						|
  UndiStart,
 | 
						|
  UndiStop,
 | 
						|
  UndiGetInitInfo,
 | 
						|
  UndiGetConfigInfo,
 | 
						|
  UndiInitialize,
 | 
						|
  UndiReset,
 | 
						|
  UndiShutdown,
 | 
						|
  UndiInterruptEnable,
 | 
						|
  UndiReceiveFilter,
 | 
						|
  UndiStationAddress,
 | 
						|
  UndiStatistics,
 | 
						|
  UndiMcastIp2Mac,
 | 
						|
  UndiNvData,
 | 
						|
  UndiGetStatus,
 | 
						|
  UndiFillHeader,
 | 
						|
  UndiTransmit,
 | 
						|
  UndiReceive
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
   Callback function for enable Rate Limiter.
 | 
						|
 | 
						|
   @param[in] Event           Event whose notification function is being invoked
 | 
						|
   @param[in] Context         Pointer to the notification function's context
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
UndiRateLimiterCallback (
 | 
						|
  IN  EFI_EVENT  Event,
 | 
						|
  IN  VOID       *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  NIC_DATA  *Nic;
 | 
						|
 | 
						|
  Nic = Context;
 | 
						|
 | 
						|
  if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) {
 | 
						|
    Nic->RateLimitingCreditCount++;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to determine the operational state of the UNDI.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiGetState (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Cdb->StatFlags = Cdb->StatFlags | Nic->State;
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to change the UNDI operational state from stopped to started.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiStart (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_CPB_START_31  *Cpb;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  BOOLEAN           EventError;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_START) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != sizeof (PXE_CPB_START_31)) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_ALREADY_STARTED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr;
 | 
						|
 | 
						|
  Nic->PxeStart.Delay     = Cpb->Delay;
 | 
						|
  Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys;
 | 
						|
  Nic->PxeStart.Block     = Cpb->Block;
 | 
						|
  Nic->PxeStart.Map_Mem   = 0;
 | 
						|
  Nic->PxeStart.UnMap_Mem = 0;
 | 
						|
  Nic->PxeStart.Sync_Mem  = Cpb->Sync_Mem;
 | 
						|
  Nic->PxeStart.Unique_ID = Cpb->Unique_ID;
 | 
						|
  EventError              = FALSE;
 | 
						|
  Status                  = EFI_SUCCESS;
 | 
						|
  if (Nic->RateLimitingEnable == TRUE) {
 | 
						|
    Status = gBS->CreateEvent (
 | 
						|
                    EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | 
						|
                    TPL_NOTIFY,
 | 
						|
                    UndiRateLimiterCallback,
 | 
						|
                    Nic,
 | 
						|
                    &Nic->RateLimiter
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = gBS->SetTimer (
 | 
						|
                      Nic->RateLimiter,
 | 
						|
                      TimerPeriodic,
 | 
						|
                      Nic->RateLimitingPollTimer * 10000
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        EventError = TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    // Initial the state for UNDI start.
 | 
						|
    Nic->State     = PXE_STATFLAGS_GET_STATE_STARTED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  } else {
 | 
						|
    if (Nic->RateLimitingEnable == TRUE) {
 | 
						|
      if (!EventError) {
 | 
						|
        gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
 | 
						|
      }
 | 
						|
 | 
						|
      if (Nic->RateLimiter) {
 | 
						|
        gBS->CloseEvent (&Nic->RateLimiter);
 | 
						|
        Nic->RateLimiter = 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Initial the state when UNDI start is fail
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_DEVICE_FAILURE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to change the UNDI operational state from started to stopped.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiStop (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_STOP) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_STARTED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_SHUTDOWN;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Nic->PxeStart.Delay     = 0;
 | 
						|
  Nic->PxeStart.Virt2Phys = 0;
 | 
						|
  Nic->PxeStart.Block     = 0;
 | 
						|
  Nic->PxeStart.Map_Mem   = 0;
 | 
						|
  Nic->PxeStart.UnMap_Mem = 0;
 | 
						|
  Nic->PxeStart.Sync_Mem  = 0;
 | 
						|
  Nic->State              = PXE_STATFLAGS_GET_STATE_STOPPED;
 | 
						|
 | 
						|
  if (Nic->RateLimitingEnable == TRUE) {
 | 
						|
    gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0);
 | 
						|
    gBS->CloseEvent (&Nic->RateLimiter);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to retrieve initialization information that is
 | 
						|
  needed by drivers and applications to initialized UNDI.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiGetInitInfo (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_DB_GET_INIT_INFO  *Db;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
 | 
						|
      (Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_STARTED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
 | 
						|
 | 
						|
  Db->MemoryRequired         = MEMORY_REQUIRE;
 | 
						|
  Db->FrameDataLen           = PXE_MAX_TXRX_UNIT_ETHER;
 | 
						|
  Db->LinkSpeeds[0]          = 10;
 | 
						|
  Db->LinkSpeeds[1]          = 100;
 | 
						|
  Db->LinkSpeeds[2]          = 1000;
 | 
						|
  Db->LinkSpeeds[3]          = 0;
 | 
						|
  Db->MediaHeaderLen         = PXE_MAC_HEADER_LEN_ETHER;
 | 
						|
  Db->HWaddrLen              = PXE_HWADDR_LEN_ETHER;
 | 
						|
  Db->MCastFilterCnt         = MAX_MCAST_ADDRESS_CNT;
 | 
						|
  Db->TxBufCnt               = Nic->PxeInit.TxBufCnt;
 | 
						|
  Db->TxBufSize              = Nic->PxeInit.TxBufSize;
 | 
						|
  Db->RxBufCnt               = Nic->PxeInit.RxBufCnt;
 | 
						|
  Db->RxBufSize              = Nic->PxeInit.RxBufSize;
 | 
						|
  Db->IFtype                 = PXE_IFTYPE_ETHERNET;
 | 
						|
  Db->SupportedDuplexModes   = PXE_DUPLEX_DEFAULT;
 | 
						|
  Db->SupportedLoopBackModes = LOOPBACK_NORMAL;
 | 
						|
 | 
						|
  Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
 | 
						|
                     PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to retrieve configuration information about
 | 
						|
  the NIC being controlled by the UNDI.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiGetConfigInfo (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_DB_GET_CONFIG_INFO  *Db;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
 | 
						|
      (Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_STARTED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr;
 | 
						|
 | 
						|
  Db->pci.BusType = PXE_BUSTYPE_USB;
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command resets the network adapter and initializes UNDI using
 | 
						|
  the parameters supplied in the CPB.
 | 
						|
 | 
						|
  @param[in]      Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in, out] Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiInitialize (
 | 
						|
  IN      PXE_CDB   *Cdb,
 | 
						|
  IN OUT  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_CPB_INITIALIZE  *Cpb;
 | 
						|
  PXE_DB_INITIALIZE   *Db;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE)))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_STARTED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_ALREADY_INITIALIZED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr;
 | 
						|
  Db  = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr;
 | 
						|
 | 
						|
  Nic->PxeInit.LinkSpeed    = Cpb->LinkSpeed;
 | 
						|
  Nic->PxeInit.DuplexMode   = Cpb->DuplexMode;
 | 
						|
  Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode;
 | 
						|
  Nic->PxeInit.MemoryAddr   = Cpb->MemoryAddr;
 | 
						|
  Nic->PxeInit.MemoryLength = Cpb->MemoryLength;
 | 
						|
  Nic->PxeInit.TxBufCnt     = TX_BUFFER_COUNT;
 | 
						|
  Nic->PxeInit.TxBufSize    = Nic->MaxSegmentSize;
 | 
						|
  Nic->PxeInit.RxBufCnt     = RX_BUFFER_COUNT;
 | 
						|
  Nic->PxeInit.RxBufSize    = Nic->MaxSegmentSize;
 | 
						|
 | 
						|
  Cdb->StatCode = Initialize (Cdb, Nic);
 | 
						|
 | 
						|
  Db->MemoryUsed = MEMORY_REQUIRE;
 | 
						|
  Db->TxBufCnt   = Nic->PxeInit.TxBufCnt;
 | 
						|
  Db->TxBufSize  = Nic->PxeInit.TxBufSize;
 | 
						|
  Db->RxBufCnt   = Nic->PxeInit.RxBufCnt;
 | 
						|
  Db->RxBufSize  = Nic->PxeInit.RxBufSize;
 | 
						|
 | 
						|
  Nic->RxFilter    = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
 | 
						|
  Nic->CanTransmit = FALSE;
 | 
						|
 | 
						|
  if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
 | 
						|
    if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
 | 
						|
      Nic->CableDetect = 0;
 | 
						|
    } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
 | 
						|
      Nic->CableDetect = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Nic->CableDetect == 0) {
 | 
						|
      Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
  } else {
 | 
						|
    Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize Network interface controller data.
 | 
						|
 | 
						|
  @param[in]      Cdb     A pointer to the command descriptor block.
 | 
						|
  @param[in, out] Nic     A pointer to the Network interface controller data.
 | 
						|
 | 
						|
  @retval Status  A value of Pxe statcode.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
Initialize (
 | 
						|
  IN      PXE_CDB   *Cdb,
 | 
						|
  IN OUT  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN       Status;
 | 
						|
  UINT32      Index;
 | 
						|
  EFI_STATUS  EfiStatus;
 | 
						|
 | 
						|
  Status = MapIt (
 | 
						|
             Nic,
 | 
						|
             Nic->PxeInit.MemoryAddr,
 | 
						|
             Nic->PxeInit.MemoryLength,
 | 
						|
             TO_AND_FROM_DEVICE,
 | 
						|
             (UINT64)(UINTN)&Nic->MappedAddr
 | 
						|
             );
 | 
						|
 | 
						|
  if (Status != 0) {
 | 
						|
    return (UINT16)Status;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
    Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index];
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
    Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
    Nic->BroadcastNodeAddress[Index] = 0xFF;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {
 | 
						|
    Nic->CurrentNodeAddress[Index]   = 0;
 | 
						|
    Nic->PermNodeAddress[Index]      = 0;
 | 
						|
    Nic->BroadcastNodeAddress[Index] = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthInitialize != NULL) {
 | 
						|
    EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (EfiStatus)) {
 | 
						|
      return PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return (UINT16)Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command resets the network adapter and reinitializes the UNDI
 | 
						|
  with the same parameters provided in the Initialize command.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiReset (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_RESET) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) &&
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) &&
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
 | 
						|
    Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
 | 
						|
    Nic->InterrupOpFlag = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The Shutdown command resets the network adapter and leaves it in a
 | 
						|
  safe state for another driver to initialize.
 | 
						|
 | 
						|
  @param[in]      Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in, out] Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiShutdown (
 | 
						|
  IN      PXE_CDB   *Cdb,
 | 
						|
  IN OUT  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Nic->CanTransmit = FALSE;
 | 
						|
 | 
						|
  Nic->State = PXE_STATFLAGS_GET_STATE_STARTED;
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The Interrupt Enables command can be used to read and/or change
 | 
						|
  the current external interrupt enable settings.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiInterruptEnable (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    } else {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
      Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to read and change receive filters and,
 | 
						|
  if supported, read and change the multicast MAC address filter list.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiReceiveFilter (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16                  NewFilter;
 | 
						|
  PXE_DB_RECEIVE_FILTERS  *Db;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  NewFilter = (UINT16)(Cdb->OpFlags & 0x1F);
 | 
						|
 | 
						|
  switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
 | 
						|
    case PXE_OPFLAGS_RECEIVE_FILTER_READ:
 | 
						|
      if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
 | 
						|
        Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
        Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
      }
 | 
						|
 | 
						|
      if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
 | 
						|
        if ((Cdb->DBsize != 0)) {
 | 
						|
          Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr;
 | 
						|
          CopyMem (Db, &Nic->McastList, Nic->McastCount);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
 | 
						|
      if (NewFilter == 0) {
 | 
						|
        Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
      }
 | 
						|
 | 
						|
      if (Cdb->CPBsize != 0) {
 | 
						|
        if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
 | 
						|
            ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
 | 
						|
            ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
 | 
						|
            ((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0))
 | 
						|
        {
 | 
						|
          Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
 | 
						|
        if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
 | 
						|
            ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0))
 | 
						|
        {
 | 
						|
          Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
        }
 | 
						|
 | 
						|
        if ((Cdb->CPBsize == 0)) {
 | 
						|
          Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
 | 
						|
      if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) {
 | 
						|
        Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
        Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
      Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
  }
 | 
						|
 | 
						|
  Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter);
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set PXE receive filter.
 | 
						|
 | 
						|
  @param[in]  Nic         A pointer to the Network interface controller data.
 | 
						|
  @param[in]  SetFilter   PXE receive filter
 | 
						|
  @param[in]  CpbAddr     Command Parameter Block Address
 | 
						|
  @param[in]  CpbSize     Command Parameter Block Size
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
SetFilter (
 | 
						|
  IN  NIC_DATA  *Nic,
 | 
						|
  IN  UINT16    SetFilter,
 | 
						|
  IN  UINT64    CpbAddr,
 | 
						|
  IN  UINT32    CpbSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  UINT8                        *McastList;
 | 
						|
  UINT8                        Count;
 | 
						|
  UINT8                        Index1;
 | 
						|
  UINT8                        Index2;
 | 
						|
  PXE_CPB_RECEIVE_FILTERS      *Cpb;
 | 
						|
  USB_ETHERNET_FUN_DESCRIPTOR  UsbEthFunDescriptor;
 | 
						|
 | 
						|
  Count = 0;
 | 
						|
  Cpb   = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
 | 
						|
 | 
						|
  // The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
 | 
						|
  Nic->RxFilter = (UINT8)SetFilter;
 | 
						|
 | 
						|
  if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
 | 
						|
    if (Cpb != NULL) {
 | 
						|
      Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
 | 
						|
      CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
 | 
						|
    }
 | 
						|
 | 
						|
    Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
 | 
						|
    if ((UsbEthFunDescriptor.NumberMcFilters & MAC_FILTERS_MASK) == 0) {
 | 
						|
      Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
 | 
						|
      Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
 | 
						|
    } else {
 | 
						|
      Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return PXE_STATCODE_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      if (Cpb != NULL) {
 | 
						|
        for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
 | 
						|
          for (Index2 = 0; Index2 < 6; Index2++) {
 | 
						|
            McastList[Count++] = Cpb->MCastList[Index1][Index2];
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
 | 
						|
      if (Cpb != NULL) {
 | 
						|
        Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
 | 
						|
      }
 | 
						|
 | 
						|
      Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
 | 
						|
      FreePool (McastList);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return PXE_STATCODE_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to get current station and broadcast MAC addresses
 | 
						|
  and, if supported, to change the current station MAC address.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiStationAddress (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_CPB_STATION_ADDRESS  *Cpb;
 | 
						|
  PXE_DB_STATION_ADDRESS   *Db;
 | 
						|
  UINT16                   Index;
 | 
						|
  EFI_STATUS               Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS)))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
 | 
						|
    if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) {
 | 
						|
      for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
 | 
						|
        Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index];
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cdb->CPBaddr != 0) {
 | 
						|
    Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr;
 | 
						|
    for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
 | 
						|
      Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cdb->DBaddr != 0) {
 | 
						|
    Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr;
 | 
						|
    for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
 | 
						|
      Db->StationAddr[Index]   = Nic->CurrentNodeAddress[Index];
 | 
						|
      Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index];
 | 
						|
      Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to read and clear the NIC traffic statistics.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiStatistics (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) &&
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize);
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return data for DB data.
 | 
						|
 | 
						|
  @param[in]  Nic      A pointer to the Network interface controller data.
 | 
						|
  @param[in]  DbAddr   Data Block Address.
 | 
						|
  @param[in]  DbSize   Data Block Size.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
Statistics (
 | 
						|
  IN NIC_DATA  *Nic,
 | 
						|
  IN UINT64    DbAddr,
 | 
						|
  IN UINT16    DbSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_DB_STATISTICS  *DbStatistic;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr;
 | 
						|
 | 
						|
  if (DbSize == 0) {
 | 
						|
    return PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  DbStatistic->Supported  = 0x802;
 | 
						|
  DbStatistic->Data[0x01] = Nic->RxFrame;
 | 
						|
  DbStatistic->Data[0x0B] = Nic->TxFrame;
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthStatistics != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return PXE_STATCODE_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Translate a multicast IPv4 or IPv6 address to a multicast MAC address.
 | 
						|
 | 
						|
  @param[in, out] Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]      Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiMcastIp2Mac (
 | 
						|
  IN OUT  PXE_CDB   *Cdb,
 | 
						|
  IN      NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_CPB_MCAST_IP_TO_MAC  *Cpb;
 | 
						|
  PXE_DB_MCAST_IP_TO_MAC   *Db;
 | 
						|
  UINT8                    *Tmp;
 | 
						|
  EFI_STATUS               Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) ||
 | 
						|
      (Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC)))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr;
 | 
						|
  Db  = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr;
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_UNSUPPORTED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Tmp = (UINT8 *)(&Cpb->IP.IPv4);
 | 
						|
 | 
						|
  if ((Tmp[0] & 0xF0) != 0xE0) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CPB;
 | 
						|
  }
 | 
						|
 | 
						|
  Db->MAC[0] = 0x01;
 | 
						|
  Db->MAC[1] = 0x00;
 | 
						|
  Db->MAC[2] = 0x5E;
 | 
						|
  Db->MAC[3] = Tmp[1] & 0x7F;
 | 
						|
  Db->MAC[4] = Tmp[2];
 | 
						|
  Db->MAC[5] = Tmp[3];
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to read and write (if supported by NIC H/W)
 | 
						|
  nonvolatile storage on the NIC.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiNvData (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Cdb->StatCode = PXE_STATCODE_UNSUPPORTED;
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    } else {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
      Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command returns the current interrupt status and/or the
 | 
						|
  transmitted buffer addresses and the current media status.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiGetStatus (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_DB_GET_STATUS  *Db;
 | 
						|
  PXE_DB_GET_STATUS  TmpGetStatus;
 | 
						|
  UINT16             NumEntries;
 | 
						|
  UINTN              Index;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->CPBaddr != PXE_CPBADDR_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  TmpGetStatus.RxFrameLen = 0;
 | 
						|
  TmpGetStatus.reserved   = 0;
 | 
						|
  Db                      = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr;
 | 
						|
 | 
						|
  if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) {
 | 
						|
    CopyMem (Db, &TmpGetStatus, Cdb->DBsize);
 | 
						|
  } else {
 | 
						|
    CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2);
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
 | 
						|
    if (Cdb->DBsize == 0) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
      Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    NumEntries  = Cdb->DBsize - sizeof (UINT64);
 | 
						|
    Cdb->DBsize = sizeof (UINT32) * 2;
 | 
						|
 | 
						|
    for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
 | 
						|
      if (Nic->TxBufferCount > 0) {
 | 
						|
        Nic->TxBufferCount--;
 | 
						|
        Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount];
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
 | 
						|
    if (Nic->ReceiveStatus != 0) {
 | 
						|
      Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) {
 | 
						|
    Nic->CableDetect = 0;
 | 
						|
  } else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) {
 | 
						|
    Nic->CableDetect = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
 | 
						|
    if (Nic->CableDetect == 0) {
 | 
						|
      Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This command is used to fill the media header(s) in transmit packet(s).
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiFillHeader (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_CPB_FILL_HEADER             *CpbFillHeader;
 | 
						|
  PXE_CPB_FILL_HEADER_FRAGMENTED  *CpbFill;
 | 
						|
  ETHERNET_HEADER                 *MacHeader;
 | 
						|
  UINTN                           Index;
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
 | 
						|
    CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr;
 | 
						|
 | 
						|
    if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
      Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    MacHeader           = (ETHERNET_HEADER *)(UINTN)CpbFill->FragDesc[0].FragAddr;
 | 
						|
    MacHeader->Protocol = CpbFill->Protocol;
 | 
						|
 | 
						|
    for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
      MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index];
 | 
						|
      MacHeader->SrcAddr[Index]  = CpbFill->SrcAddr[Index];
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr;
 | 
						|
 | 
						|
    MacHeader           = (ETHERNET_HEADER *)(UINTN)CpbFillHeader->MediaHeader;
 | 
						|
    MacHeader->Protocol = CpbFillHeader->Protocol;
 | 
						|
 | 
						|
    for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
      MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index];
 | 
						|
      MacHeader->SrcAddr[Index]  = CpbFillHeader->SrcAddr[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The Transmit command is used to place a packet into the transmit queue.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiTransmit (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) ||
 | 
						|
      (Cdb->DBsize != PXE_DBSIZE_NOT_USED) ||
 | 
						|
      (Cdb->DBaddr != PXE_DBADDR_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags);
 | 
						|
 | 
						|
  if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Use USB Ethernet Protocol Bulk out command to transmit data.
 | 
						|
 | 
						|
  @param[in]      Cdb      A pointer to the command descriptor block.
 | 
						|
  @param[in, out] Nic      A pointer to the Network interface controller data.
 | 
						|
  @param[in]      CpbAddr  Command Parameter Block Address.
 | 
						|
  @param[in]      OpFlags  Operation Flags.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
Transmit (
 | 
						|
  IN      PXE_CDB   *Cdb,
 | 
						|
  IN OUT  NIC_DATA  *Nic,
 | 
						|
  IN      UINT64    CpbAddr,
 | 
						|
  IN      UINT16    OpFlags
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  PXE_CPB_TRANSMIT  *Cpb;
 | 
						|
  UINT64            BulkOutData;
 | 
						|
  UINTN             DataLength;
 | 
						|
  UINTN             TransmitLength;
 | 
						|
  UINTN             Map;
 | 
						|
  UINT32            Counter;
 | 
						|
  UINT16            StatCode;
 | 
						|
 | 
						|
  BulkOutData = 0;
 | 
						|
  Counter     = 0;
 | 
						|
  Cpb         = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr;
 | 
						|
 | 
						|
  if (Nic->CanTransmit) {
 | 
						|
    return PXE_STATCODE_BUSY;
 | 
						|
  }
 | 
						|
 | 
						|
  Nic->CanTransmit = TRUE;
 | 
						|
 | 
						|
  if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
 | 
						|
    return PXE_STATCODE_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Map = MapIt (
 | 
						|
          Nic,
 | 
						|
          Cpb->FrameAddr,
 | 
						|
          Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
 | 
						|
          TO_DEVICE,
 | 
						|
          (UINT64)(UINTN)&BulkOutData
 | 
						|
          );
 | 
						|
 | 
						|
  if (Map != 0) {
 | 
						|
    Nic->CanTransmit = FALSE;
 | 
						|
    return PXE_STATCODE_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) {
 | 
						|
    Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr;
 | 
						|
    Nic->TxBufferCount++;
 | 
						|
  }
 | 
						|
 | 
						|
  DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen);
 | 
						|
 | 
						|
  while (1) {
 | 
						|
    if (Counter >= 3) {
 | 
						|
      StatCode = PXE_STATCODE_BUSY;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    TransmitLength = DataLength;
 | 
						|
 | 
						|
    Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      StatCode =  PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Status == EFI_INVALID_PARAMETER) {
 | 
						|
      StatCode = PXE_STATCODE_INVALID_PARAMETER;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Status == EFI_DEVICE_ERROR) {
 | 
						|
      StatCode = PXE_STATCODE_DEVICE_FAILURE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Nic->TxFrame++;
 | 
						|
      StatCode = PXE_STATCODE_SUCCESS;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Counter++;
 | 
						|
  }
 | 
						|
 | 
						|
  UnMapIt (
 | 
						|
    Nic,
 | 
						|
    Cpb->FrameAddr,
 | 
						|
    Cpb->DataLen + (UINT32)Cpb->MediaheaderLen,
 | 
						|
    TO_DEVICE,
 | 
						|
    BulkOutData
 | 
						|
    );
 | 
						|
 | 
						|
  Nic->CanTransmit = FALSE;
 | 
						|
 | 
						|
  return StatCode;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  When the network adapter has received a frame, this command is used
 | 
						|
  to copy the frame into driver/application storage.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
  @param[in]  Nic  A pointer to the Network interface controller data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UndiReceive (
 | 
						|
  IN  PXE_CDB   *Cdb,
 | 
						|
  IN  NIC_DATA  *Nic
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) ||
 | 
						|
      (Cdb->StatCode != PXE_STATCODE_INITIALIZE) ||
 | 
						|
      (Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
 | 
						|
      (Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) ||
 | 
						|
      (Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) ||
 | 
						|
      (Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) ||
 | 
						|
      (Cdb->OpFlags != PXE_OPFLAGS_NOT_USED))
 | 
						|
  {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_INVALID_CDB;
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    Cdb->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) {
 | 
						|
    Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr);
 | 
						|
 | 
						|
  if (Cdb->StatCode != PXE_STATCODE_SUCCESS) {
 | 
						|
    Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Use USB Ethernet Protocol Bulk in command to receive data.
 | 
						|
 | 
						|
  @param[in]      Cdb      A pointer to the command descriptor block.
 | 
						|
  @param[in, out] Nic      A pointer to the Network interface controller data.
 | 
						|
  @param[in]      CpbAddr  Command Parameter Block Address.
 | 
						|
  @param[in, out] DbAddr   Data Block Address.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
Receive (
 | 
						|
  IN PXE_CDB       *Cdb,
 | 
						|
  IN OUT NIC_DATA  *Nic,
 | 
						|
  IN UINT64        CpbAddr,
 | 
						|
  IN OUT UINT64    DbAddr
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS       Status;
 | 
						|
  UINTN            Index;
 | 
						|
  PXE_FRAME_TYPE   FrameType;
 | 
						|
  PXE_CPB_RECEIVE  *Cpb;
 | 
						|
  PXE_DB_RECEIVE   *Db;
 | 
						|
  NIC_DEVICE       *NicDevice;
 | 
						|
  UINT8            *BulkInData;
 | 
						|
  UINTN            DataLength;
 | 
						|
  ETHERNET_HEADER  *Header;
 | 
						|
  EFI_TPL          OriginalTpl;
 | 
						|
 | 
						|
  FrameType  = PXE_FRAME_TYPE_NONE;
 | 
						|
  NicDevice  = UNDI_DEV_FROM_NIC (Nic);
 | 
						|
  BulkInData = NicDevice->ReceiveBuffer;
 | 
						|
  DataLength = (UINTN)Nic->MaxSegmentSize;
 | 
						|
  Cpb        = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr;
 | 
						|
  Db         = (PXE_DB_RECEIVE *)(UINTN)DbAddr;
 | 
						|
 | 
						|
  if (!BulkInData) {
 | 
						|
    return PXE_STATCODE_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) {
 | 
						|
    return PXE_STATCODE_NO_DATA;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Nic->ReceiveStatus = 0;
 | 
						|
    if (Nic->RateLimitingEnable == TRUE) {
 | 
						|
      OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
      if (Nic->RateLimitingCreditCount != 0) {
 | 
						|
        Nic->RateLimitingCreditCount--;
 | 
						|
      }
 | 
						|
 | 
						|
      gBS->RestoreTPL (OriginalTpl);
 | 
						|
    }
 | 
						|
 | 
						|
    return PXE_STATCODE_NO_DATA;
 | 
						|
  }
 | 
						|
 | 
						|
  Nic->RxFrame++;
 | 
						|
 | 
						|
  if (DataLength != 0) {
 | 
						|
    if (DataLength > Cpb->BufferLen) {
 | 
						|
      DataLength = (UINTN)Cpb->BufferLen;
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength);
 | 
						|
 | 
						|
    Header = (ETHERNET_HEADER *)BulkInData;
 | 
						|
 | 
						|
    Db->FrameLen       = (UINT32)DataLength;
 | 
						|
    Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
 | 
						|
 | 
						|
    for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
      if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (Index >= PXE_HWADDR_LEN_ETHER) {
 | 
						|
      FrameType = PXE_FRAME_TYPE_UNICAST;
 | 
						|
    } else {
 | 
						|
      for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
        if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (Index >= PXE_HWADDR_LEN_ETHER) {
 | 
						|
        FrameType = PXE_FRAME_TYPE_BROADCAST;
 | 
						|
      } else {
 | 
						|
        if ((Header->DestAddr[0] & 1) == 1) {
 | 
						|
          FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST;
 | 
						|
        } else {
 | 
						|
          FrameType = PXE_FRAME_TYPE_PROMISCUOUS;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Db->Type     = FrameType;
 | 
						|
    Db->Protocol = Header->Protocol;
 | 
						|
 | 
						|
    for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
 | 
						|
      Db->SrcAddr[Index]  = Header->SrcAddr[Index];
 | 
						|
      Db->DestAddr[Index] = Header->DestAddr[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (FrameType == PXE_FRAME_TYPE_NONE) {
 | 
						|
    Nic->ReceiveStatus = 0;
 | 
						|
  } else {
 | 
						|
    Nic->ReceiveStatus = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return PXE_STATCODE_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fill out PXE SW UNDI structure.
 | 
						|
 | 
						|
  @param[out]  PxeSw      A pointer to the PXE SW UNDI structure.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PxeStructInit (
 | 
						|
  OUT PXE_SW_UNDI  *PxeSw
 | 
						|
  )
 | 
						|
{
 | 
						|
  PxeSw->Signature = PXE_ROMID_SIGNATURE;
 | 
						|
  PxeSw->Len       = (UINT8)sizeof (PXE_SW_UNDI);
 | 
						|
  PxeSw->Fudge     = 0;
 | 
						|
  PxeSw->IFcnt     = 0;
 | 
						|
  PxeSw->IFcntExt  = 0;
 | 
						|
  PxeSw->Rev       = PXE_ROMID_REV;
 | 
						|
  PxeSw->MajorVer  = PXE_ROMID_MAJORVER;
 | 
						|
  PxeSw->MinorVer  = PXE_ROMID_MINORVER;
 | 
						|
  PxeSw->reserved1 = 0;
 | 
						|
 | 
						|
  PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
 | 
						|
                          PXE_ROMID_IMP_FRAG_SUPPORTED |
 | 
						|
                          PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
 | 
						|
                          PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
 | 
						|
                          PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
 | 
						|
                          PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
 | 
						|
                          PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
 | 
						|
                          PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED;
 | 
						|
 | 
						|
  PxeSw->EntryPoint   = (UINT64)(UINTN)UndiApiEntry;
 | 
						|
  PxeSw->reserved2[0] = 0;
 | 
						|
  PxeSw->reserved2[1] = 0;
 | 
						|
  PxeSw->reserved2[2] = 0;
 | 
						|
  PxeSw->BusCnt       = 1;
 | 
						|
  PxeSw->BusType[0]   = PXE_BUSTYPE_USB;
 | 
						|
  PxeSw->Fudge        = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update NIC number.
 | 
						|
 | 
						|
  @param[in]      Nic       A pointer to the Network interface controller data.
 | 
						|
  @param[in, out] PxeSw     A pointer to the PXE SW UNDI structure.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UpdateNicNum (
 | 
						|
  IN      NIC_DATA     *Nic,
 | 
						|
  IN OUT  PXE_SW_UNDI  *PxeSw
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  NicNum;
 | 
						|
 | 
						|
  NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8);
 | 
						|
 | 
						|
  if (Nic == NULL) {
 | 
						|
    if (NicNum > 0) {
 | 
						|
      NicNum--;
 | 
						|
    }
 | 
						|
 | 
						|
    PxeSw->IFcnt    = (UINT8)(NicNum & 0xFF);          // Get lower byte
 | 
						|
    PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
 | 
						|
    PxeSw->Fudge    = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  NicNum++;
 | 
						|
 | 
						|
  PxeSw->IFcnt    = (UINT8)(NicNum & 0xFF);          // Get lower byte
 | 
						|
  PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte
 | 
						|
  PxeSw->Fudge    = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  UNDI API table entry.
 | 
						|
 | 
						|
  @param[in]  Cdb  A pointer to the command descriptor block.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UndiApiEntry (
 | 
						|
  IN  UINT64  Cdb
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_CDB   *CdbPtr;
 | 
						|
  NIC_DATA  *Nic;
 | 
						|
 | 
						|
  if (Cdb == 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  CdbPtr = (PXE_CDB *)(UINTN)Cdb;
 | 
						|
  Nic    = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo);
 | 
						|
  gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Map virtual memory address for DMA. This field can be set to
 | 
						|
  zero if there is no mapping service.
 | 
						|
 | 
						|
  @param[in]  Nic           A pointer to the Network interface controller data.
 | 
						|
  @param[in]  MemAddr       Virtual address to be mapped.
 | 
						|
  @param[in]  Size          Size of memory to be mapped.
 | 
						|
  @param[in]  Direction     Direction of data flow for this memory's usage:
 | 
						|
                            cpu->device, device->cpu or both ways.
 | 
						|
  @param[out] MappedAddr    Pointer to return the mapped device address.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
MapIt (
 | 
						|
  IN NIC_DATA  *Nic,
 | 
						|
  IN UINT64    MemAddr,
 | 
						|
  IN UINT32    Size,
 | 
						|
  IN UINT32    Direction,
 | 
						|
  OUT UINT64   MappedAddr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64  *PhyAddr;
 | 
						|
 | 
						|
  PhyAddr = (UINT64 *)(UINTN)MappedAddr;
 | 
						|
 | 
						|
  if (Nic->PxeStart.Map_Mem == 0) {
 | 
						|
    *PhyAddr = MemAddr;
 | 
						|
  } else {
 | 
						|
    ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)(
 | 
						|
  Nic->PxeStart.Unique_ID,
 | 
						|
  MemAddr,
 | 
						|
  Size,
 | 
						|
  Direction,
 | 
						|
  MappedAddr
 | 
						|
  );
 | 
						|
  }
 | 
						|
 | 
						|
  return PXE_STATCODE_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Un-map previously mapped virtual memory address. This field can be set
 | 
						|
  to zero only if the Map_Mem() service is also set to zero.
 | 
						|
 | 
						|
  @param[in]  Nic           A pointer to the Network interface controller data.
 | 
						|
  @param[in]  MemAddr       Virtual address to be mapped.
 | 
						|
  @param[in]  Size          Size of memory to be mapped.
 | 
						|
  @param[in]  Direction     Direction of data flow for this memory's usage:
 | 
						|
                            cpu->device, device->cpu or both ways.
 | 
						|
  @param[in]  MappedAddr    Pointer to return the mapped device address.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UnMapIt (
 | 
						|
  IN NIC_DATA  *Nic,
 | 
						|
  IN UINT64    MemAddr,
 | 
						|
  IN UINT32    Size,
 | 
						|
  IN UINT32    Direction,
 | 
						|
  IN UINT64    MappedAddr
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (Nic->PxeStart.UnMap_Mem != 0) {
 | 
						|
    ((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)(
 | 
						|
  Nic->PxeStart.Unique_ID,
 | 
						|
  MemAddr,
 | 
						|
  Size,
 | 
						|
  Direction,
 | 
						|
  MappedAddr
 | 
						|
  );
 | 
						|
  }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 |