mirror of https://github.com/acidanthera/audk.git
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;
|
|
}
|