/**@file | |
Windows Packet Filter implementation of the EMU_SNP_PROTOCOL that allows the | |
emulator to get on real networks. | |
Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> | |
Portions copyright (c) 2011, Apple Inc. All rights reserved. | |
(C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "WinHost.h" | |
#define NETWORK_LIBRARY_NAME_U L"SnpNt32Io.dll" | |
#define NETWORK_LIBRARY_INITIALIZE "SnpInitialize" | |
#define NETWORK_LIBRARY_FINALIZE "SnpFinalize" | |
#define NETWORK_LIBRARY_SET_RCV_FILTER "SnpSetReceiveFilter" | |
#define NETWORK_LIBRARY_RECEIVE "SnpReceive" | |
#define NETWORK_LIBRARY_TRANSMIT "SnpTransmit" | |
#pragma pack(1) | |
typedef struct _NT_NET_INTERFACE_INFO { | |
UINT32 InterfaceIndex; | |
EFI_MAC_ADDRESS MacAddr; | |
} NT_NET_INTERFACE_INFO; | |
#pragma pack() | |
#define NET_ETHER_HEADER_SIZE 14 | |
#define MAX_INTERFACE_INFO_NUMBER 16 | |
#define SNP_MAX_TX_BUFFER_NUM 65536 | |
#define SNP_TX_BUFFER_INCREASEMENT 32 | |
#define DEFAULT_SELECTED_NIC_INDEX 0 | |
// | |
// Functions in Net Library | |
// | |
typedef | |
INT32 | |
(*NT_NET_INITIALIZE) ( | |
IN OUT UINT32 *InterfaceCount, | |
IN OUT NT_NET_INTERFACE_INFO *InterfaceInfoBuffer | |
); | |
typedef | |
INT32 | |
(*NT_NET_FINALIZE) ( | |
VOID | |
); | |
typedef | |
INT32 | |
(*NT_NET_SET_RECEIVE_FILTER) ( | |
IN UINT32 Index, | |
IN UINT32 EnableFilter, | |
IN UINT32 MCastFilterCnt, | |
IN EFI_MAC_ADDRESS *MCastFilter | |
); | |
typedef | |
INT32 | |
(*NT_NET_RECEIVE) ( | |
IN UINT32 Index, | |
IN OUT UINT32 *BufferSize, | |
OUT VOID *Buffer | |
); | |
typedef | |
INT32 | |
(*NT_NET_TRANSMIT) ( | |
IN UINT32 Index, | |
IN UINT32 HeaderSize, | |
IN UINT32 BufferSize, | |
IN VOID *Buffer, | |
IN EFI_MAC_ADDRESS *SrcAddr, | |
IN EFI_MAC_ADDRESS *DestAddr, | |
IN UINT16 *Protocol | |
); | |
typedef struct _NT_NET_UTILITY_TABLE { | |
NT_NET_INITIALIZE Initialize; | |
NT_NET_FINALIZE Finalize; | |
NT_NET_SET_RECEIVE_FILTER SetReceiveFilter; | |
NT_NET_RECEIVE Receive; | |
NT_NET_TRANSMIT Transmit; | |
} NT_NET_UTILITY_TABLE; | |
// | |
// Instance data for each fake SNP instance | |
// | |
#define WIN_NT_INSTANCE_SIGNATURE SIGNATURE_32 ('N', 'T', 'I', 'S') | |
typedef struct { | |
UINT32 Signature; | |
// | |
// Array of the recycled transmit buffer address. | |
// | |
UINT64 *RecycledTxBuf; | |
// | |
// Current number of recycled buffer pointers in RecycledTxBuf. | |
// | |
UINT32 RecycledTxBufCount; | |
// | |
// The maximum number of recycled buffer pointers in RecycledTxBuf. | |
// | |
UINT32 MaxRecycledTxBuf; | |
EFI_SIMPLE_NETWORK_MODE Mode; | |
NT_NET_INTERFACE_INFO InterfaceInfo; | |
} WIN_NT_INSTANCE_DATA; | |
// | |
// Instance data for each SNP private instance | |
// | |
#define WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 's', 'n') | |
typedef struct { | |
UINTN Signature; | |
EMU_IO_THUNK_PROTOCOL *Thunk; | |
EMU_SNP_PROTOCOL EmuSnp; | |
EFI_SIMPLE_NETWORK_MODE *Mode; | |
HMODULE NetworkLibraryHandle; | |
NT_NET_UTILITY_TABLE NtNetUtilityTable; | |
WIN_NT_INSTANCE_DATA Instance; | |
} WIN_NT_SNP_PRIVATE; | |
#define WIN_NT_SNP_PRIVATE_DATA_FROM_THIS(a) \ | |
CR(a, WIN_NT_SNP_PRIVATE, EmuSnp, WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE) | |
/** | |
Register storage for SNP Mode. | |
@param This Protocol instance pointer. | |
@param Mode SimpleNetworkProtocol Mode structure passed into driver. | |
@retval EFI_SUCCESS The network interface was started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
**/ | |
EFI_STATUS | |
WinNtSnpCreateMapping ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN EFI_SIMPLE_NETWORK_MODE *Mode | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
Private->Mode = Mode; | |
// | |
// Set the broadcast address. | |
// | |
CopyMem (&Mode->BroadcastAddress, &Private->Instance.Mode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS)); | |
// | |
// Set the MAC address. | |
// | |
CopyMem (&Mode->CurrentAddress, &Private->Instance.Mode.CurrentAddress, sizeof (EFI_MAC_ADDRESS)); | |
CopyMem (&Mode->PermanentAddress, &Private->Instance.Mode.PermanentAddress, sizeof (EFI_MAC_ADDRESS)); | |
return EFI_SUCCESS; | |
} | |
/** | |
Changes the state of a network interface from "stopped" to "started". | |
@param This Protocol instance pointer. | |
@retval EFI_SUCCESS The network interface was started. | |
@retval EFI_ALREADY_STARTED The network interface is already in the started state. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpStart ( | |
IN EMU_SNP_PROTOCOL *This | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
switch (Private->Mode->State) { | |
case EfiSimpleNetworkStopped: | |
break; | |
case EfiSimpleNetworkStarted: | |
case EfiSimpleNetworkInitialized: | |
return EFI_ALREADY_STARTED; | |
break; | |
default: | |
return EFI_DEVICE_ERROR; | |
break; | |
} | |
Private->Mode->State = EfiSimpleNetworkStarted; | |
return EFI_SUCCESS; | |
} | |
/** | |
Changes the state of a network interface from "started" to "stopped". | |
@param This Protocol instance pointer. | |
@retval EFI_SUCCESS The network interface was stopped. | |
@retval EFI_ALREADY_STARTED The network interface is already in the stopped state. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpStop ( | |
IN EMU_SNP_PROTOCOL *This | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
switch ( Private->Mode->State ) { | |
case EfiSimpleNetworkStarted: | |
break; | |
case EfiSimpleNetworkStopped: | |
return EFI_NOT_STARTED; | |
break; | |
default: | |
return EFI_DEVICE_ERROR; | |
break; | |
} | |
Private->Mode->State = EfiSimpleNetworkStopped; | |
return EFI_SUCCESS; | |
} | |
/** | |
Resets a network adapter and allocates the transmit and receive buffers | |
required by the network interface; optionally, also requests allocation | |
of additional transmit and receive buffers. | |
@param This The protocol instance pointer. | |
@param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space | |
that the driver should allocate for the network interface. | |
Some network interfaces will not be able to use the extra | |
buffer, and the caller will not know if it is actually | |
being used. | |
@param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space | |
that the driver should allocate for the network interface. | |
Some network interfaces will not be able to use the extra | |
buffer, and the caller will not know if it is actually | |
being used. | |
@retval EFI_SUCCESS The network interface was initialized. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and | |
receive buffers. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpInitialize ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN UINTN ExtraRxBufferSize OPTIONAL, | |
IN UINTN ExtraTxBufferSize OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
switch ( Private->Mode->State ) { | |
case EfiSimpleNetworkStarted: | |
break; | |
case EfiSimpleNetworkStopped: | |
return EFI_NOT_STARTED; | |
break; | |
default: | |
return EFI_DEVICE_ERROR; | |
break; | |
} | |
Private->Mode->MCastFilterCount = 0; | |
Private->Mode->ReceiveFilterSetting = 0; | |
ZeroMem (Private->Mode->MCastFilter, sizeof (Private->Mode->MCastFilter)); | |
Private->Mode->State = EfiSimpleNetworkInitialized; | |
return EFI_SUCCESS; | |
} | |
/** | |
Resets a network adapter and re-initializes it with the parameters that were | |
provided in the previous call to Initialize(). | |
@param This The protocol instance pointer. | |
@param ExtendedVerification Indicates that the driver may perform a more | |
exhaustive verification operation of the device | |
during reset. | |
@retval EFI_SUCCESS The network interface was reset. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpReset ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN BOOLEAN ExtendedVerification | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
switch ( Private->Mode->State ) { | |
case EfiSimpleNetworkInitialized: | |
break; | |
case EfiSimpleNetworkStopped: | |
return EFI_NOT_STARTED; | |
break; | |
default: | |
return EFI_DEVICE_ERROR; | |
break; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Resets a network adapter and leaves it in a state that is safe for | |
another driver to initialize. | |
@param This Protocol instance pointer. | |
@retval EFI_SUCCESS The network interface was shutdown. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpShutdown ( | |
IN EMU_SNP_PROTOCOL *This | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
switch ( Private->Mode->State ) { | |
case EfiSimpleNetworkInitialized: | |
break; | |
case EfiSimpleNetworkStopped: | |
return EFI_NOT_STARTED; | |
break; | |
default: | |
return EFI_DEVICE_ERROR; | |
break; | |
} | |
Private->Mode->State = EfiSimpleNetworkStarted; | |
Private->Mode->ReceiveFilterSetting = 0; | |
Private->Mode->MCastFilterCount = 0; | |
ZeroMem (Private->Mode->MCastFilter, sizeof (Private->Mode->MCastFilter)); | |
return EFI_SUCCESS; | |
} | |
/** | |
Manages the multicast receive filters of a network interface. | |
@param This The protocol instance pointer. | |
@param Enable A bit mask of receive filters to enable on the network interface. | |
@param Disable A bit mask of receive filters to disable on the network interface. | |
@param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive | |
filters on the network interface to their default values. | |
@param McastFilterCnt Number of multicast HW MAC addresses in the new | |
MCastFilter list. This value must be less than or equal to | |
the MCastFilterCnt field of EMU_SNP_MODE. This | |
field is optional if ResetMCastFilter is TRUE. | |
@param MCastFilter A pointer to a list of new multicast receive filter HW MAC | |
addresses. This list will replace any existing multicast | |
HW MAC address list. This field is optional if | |
ResetMCastFilter is TRUE. | |
@retval EFI_SUCCESS The multicast receive filter list was updated. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpReceiveFilters ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN UINT32 Enable, | |
IN UINT32 Disable, | |
IN BOOLEAN ResetMCastFilter, | |
IN UINTN MCastFilterCnt OPTIONAL, | |
IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
INT32 ReturnValue; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
ReturnValue = Private->NtNetUtilityTable.SetReceiveFilter ( | |
Private->Instance.InterfaceInfo.InterfaceIndex, | |
Enable, | |
(UINT32)MCastFilterCnt, | |
MCastFilter | |
); | |
if (ReturnValue <= 0) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Modifies or resets the current station address, if supported. | |
@param This The protocol instance pointer. | |
@param Reset Flag used to reset the station address to the network interfaces | |
permanent address. | |
@param New The new station address to be used for the network interface. | |
@retval EFI_SUCCESS The network interfaces station address was updated. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpStationAddress ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN BOOLEAN Reset, | |
IN EFI_MAC_ADDRESS *New OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Resets or collects the statistics on a network interface. | |
@param This Protocol instance pointer. | |
@param Reset Set to TRUE to reset the statistics for the network interface. | |
@param StatisticsSize On input the size, in bytes, of StatisticsTable. On | |
output the size, in bytes, of the resulting table of | |
statistics. | |
@param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that | |
contains the statistics. | |
@retval EFI_SUCCESS The statistics were collected from the network interface. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer | |
size needed to hold the statistics is returned in | |
StatisticsSize. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpStatistics ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN BOOLEAN Reset, | |
IN OUT UINTN *StatisticsSize OPTIONAL, | |
OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Converts a multicast IP address to a multicast HW MAC address. | |
@param This The protocol instance pointer. | |
@param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set | |
to FALSE if the multicast IP address is IPv4 [RFC 791]. | |
@param IP The multicast IP address that is to be converted to a multicast | |
HW MAC address. | |
@param MAC The multicast HW MAC address that is to be generated from IP. | |
@retval EFI_SUCCESS The multicast IP address was mapped to the multicast | |
HW MAC address. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer | |
size needed to hold the statistics is returned in | |
StatisticsSize. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpMCastIpToMac ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN BOOLEAN IPv6, | |
IN EFI_IP_ADDRESS *IP, | |
OUT EFI_MAC_ADDRESS *MAC | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Performs read and write operations on the NVRAM device attached to a | |
network interface. | |
@param This The protocol instance pointer. | |
@param ReadWrite TRUE for read operations, FALSE for write operations. | |
@param Offset Byte offset in the NVRAM device at which to start the read or | |
write operation. This must be a multiple of NvRamAccessSize and | |
less than NvRamSize. | |
@param BufferSize The number of bytes to read or write from the NVRAM device. | |
This must also be a multiple of NvramAccessSize. | |
@param Buffer A pointer to the data buffer. | |
@retval EFI_SUCCESS The NVRAM access was performed. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpNvData ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN BOOLEAN ReadWrite, | |
IN UINTN Offset, | |
IN UINTN BufferSize, | |
IN OUT VOID *Buffer | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
Reads the current interrupt status and recycled transmit buffer status from | |
a network interface. | |
@param This The protocol instance pointer. | |
@param InterruptStatus A pointer to the bit mask of the currently active interrupts | |
If this is NULL, the interrupt status will not be read from | |
the device. If this is not NULL, the interrupt status will | |
be read from the device. When the interrupt status is read, | |
it will also be cleared. Clearing the transmit interrupt | |
does not empty the recycled transmit buffer array. | |
@param TxBuf Recycled transmit buffer address. The network interface will | |
not transmit if its internal recycled transmit buffer array | |
is full. Reading the transmit buffer does not clear the | |
transmit interrupt. If this is NULL, then the transmit buffer | |
status will not be read. If there are no transmit buffers to | |
recycle and TxBuf is not NULL, * TxBuf will be set to NULL. | |
@retval EFI_SUCCESS The status of the network interface was retrieved. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpGetStatus ( | |
IN EMU_SNP_PROTOCOL *This, | |
OUT UINT32 *InterruptStatus OPTIONAL, | |
OUT VOID **TxBuf OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
if (TxBuf != NULL) { | |
if (Private->Instance.RecycledTxBufCount != 0) { | |
Private->Instance.RecycledTxBufCount--; | |
*((UINT8 **)TxBuf) = (UINT8 *)(UINTN)Private->Instance.RecycledTxBuf[Private->Instance.RecycledTxBufCount]; | |
} else { | |
*((UINT8 **)TxBuf) = NULL; | |
} | |
} | |
if (InterruptStatus != NULL) { | |
*InterruptStatus = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Places a packet in the transmit queue of a network interface. | |
@param This The protocol instance pointer. | |
@param HeaderSize The size, in bytes, of the media header to be filled in by | |
the Transmit() function. If HeaderSize is non-zero, then it | |
must be equal to This->Mode->MediaHeaderSize and the DestAddr | |
and Protocol parameters must not be NULL. | |
@param BufferSize The size, in bytes, of the entire packet (media header and | |
data) to be transmitted through the network interface. | |
@param Buffer A pointer to the packet (media header followed by data) to be | |
transmitted. This parameter cannot be NULL. If HeaderSize is zero, | |
then the media header in Buffer must already be filled in by the | |
caller. If HeaderSize is non-zero, then the media header will be | |
filled in by the Transmit() function. | |
@param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter | |
is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then | |
This->Mode->CurrentAddress is used for the source HW MAC address. | |
@param DestAddr The destination HW MAC address. If HeaderSize is zero, then this | |
parameter is ignored. | |
@param Protocol The type of header to build. If HeaderSize is zero, then this | |
parameter is ignored. See RFC 1700, section "Ether Types", for | |
examples. | |
@retval EFI_SUCCESS The packet was placed on the transmit queue. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_NOT_READY The network interface is too busy to accept this transmit request. | |
@retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpTransmit ( | |
IN EMU_SNP_PROTOCOL *This, | |
IN UINTN HeaderSize, | |
IN UINTN BufferSize, | |
IN VOID *Buffer, | |
IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, | |
IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, | |
IN UINT16 *Protocol OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
INT32 ReturnValue; | |
UINT64 *Tmp; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
if ((HeaderSize != 0) && (SrcAddr == NULL)) { | |
SrcAddr = &Private->Instance.Mode.CurrentAddress; | |
} | |
ReturnValue = Private->NtNetUtilityTable.Transmit ( | |
Private->Instance.InterfaceInfo.InterfaceIndex, | |
(UINT32)HeaderSize, | |
(UINT32)BufferSize, | |
Buffer, | |
SrcAddr, | |
DestAddr, | |
Protocol | |
); | |
if (ReturnValue < 0) { | |
return EFI_DEVICE_ERROR; | |
} else { | |
if ((Private->Instance.MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) { | |
return EFI_NOT_READY; | |
} | |
if (Private->Instance.RecycledTxBufCount < Private->Instance.MaxRecycledTxBuf) { | |
Private->Instance.RecycledTxBuf[Private->Instance.RecycledTxBufCount] = (UINT64)Buffer; | |
Private->Instance.RecycledTxBufCount++; | |
} else { | |
Tmp = malloc (sizeof (UINT64) * (Private->Instance.MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT)); | |
if (Tmp == NULL) { | |
return EFI_DEVICE_ERROR; | |
} | |
CopyMem (Tmp, Private->Instance.RecycledTxBuf, sizeof (UINT64) * Private->Instance.RecycledTxBufCount); | |
free (Private->Instance.RecycledTxBuf); | |
Private->Instance.RecycledTxBuf = Tmp; | |
Private->Instance.MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT; | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Receives a packet from a network interface. | |
@param This The protocol instance pointer. | |
@param HeaderSize The size, in bytes, of the media header received on the network | |
interface. If this parameter is NULL, then the media header size | |
will not be returned. | |
@param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in | |
bytes, of the packet that was received on the network interface. | |
@param Buffer A pointer to the data buffer to receive both the media header and | |
the data. | |
@param SrcAddr The source HW MAC address. If this parameter is NULL, the | |
HW MAC source address will not be extracted from the media | |
header. | |
@param DestAddr The destination HW MAC address. If this parameter is NULL, | |
the HW MAC destination address will not be extracted from the | |
media header. | |
@param Protocol The media header type. If this parameter is NULL, then the | |
protocol will not be extracted from the media header. See | |
RFC 1700 section "Ether Types" for examples. | |
@retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has | |
been updated to the number of bytes received. | |
@retval EFI_NOT_STARTED The network interface has not been started. | |
@retval EFI_NOT_READY The network interface is too busy to accept this transmit | |
request. | |
@retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. | |
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface. | |
@retval EFI_UNSUPPORTED This function is not supported by the network interface. | |
**/ | |
EFI_STATUS | |
WinNtSnpReceive ( | |
IN EMU_SNP_PROTOCOL *This, | |
OUT UINTN *HeaderSize OPTIONAL, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer, | |
OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, | |
OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, | |
OUT UINT16 *Protocol OPTIONAL | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
INT32 ReturnValue; | |
UINTN BufSize; | |
Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This); | |
BufSize = *BufferSize; | |
ASSERT (Private->NtNetUtilityTable.Receive != NULL); | |
ReturnValue = Private->NtNetUtilityTable.Receive ( | |
Private->Instance.InterfaceInfo.InterfaceIndex, | |
BufferSize, | |
Buffer | |
); | |
if (ReturnValue < 0) { | |
if (ReturnValue == -100) { | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
return EFI_DEVICE_ERROR; | |
} else if (ReturnValue == 0) { | |
return EFI_NOT_READY; | |
} | |
if (HeaderSize != NULL) { | |
*HeaderSize = 14; | |
} | |
if (SrcAddr != NULL) { | |
ZeroMem (SrcAddr, sizeof (EFI_MAC_ADDRESS)); | |
CopyMem (SrcAddr, ((UINT8 *)Buffer) + 6, 6); | |
} | |
if (DestAddr != NULL) { | |
ZeroMem (DestAddr, sizeof (EFI_MAC_ADDRESS)); | |
CopyMem (DestAddr, ((UINT8 *)Buffer), 6); | |
} | |
if (Protocol != NULL) { | |
*Protocol = NTOHS (*((UINT16 *)(((UINT8 *)Buffer) + 12))); | |
} | |
return (*BufferSize <= BufSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; | |
} | |
/** | |
Initialize the snpnt32 driver instance. | |
@param Instance Pointer to the instance context data. | |
@param NetInfo Pointer to the interface info. | |
@retval EFI_SUCCESS The driver instance is initialized. | |
@retval other Initialization errors. | |
**/ | |
EFI_STATUS | |
WinNtInitializeInstanceData ( | |
IN OUT WIN_NT_INSTANCE_DATA *Instance, | |
IN NT_NET_INTERFACE_INFO *NetInfo | |
) | |
{ | |
if ((Instance == NULL) || (NetInfo == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
ZeroMem (Instance, sizeof (WIN_NT_INSTANCE_DATA)); | |
Instance->Signature = WIN_NT_INSTANCE_SIGNATURE; | |
Instance->RecycledTxBufCount = 0; | |
Instance->MaxRecycledTxBuf = 32; | |
Instance->Mode.State = EfiSimpleNetworkInitialized; | |
Instance->Mode.HwAddressSize = NET_ETHER_ADDR_LEN; | |
Instance->Mode.MediaHeaderSize = NET_ETHER_HEADER_SIZE; | |
Instance->Mode.MaxPacketSize = 1500; | |
Instance->Mode.MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; | |
Instance->Mode.IfType = NET_IFTYPE_ETHERNET; | |
Instance->Mode.MediaPresentSupported = TRUE; | |
Instance->Mode.MediaPresent = TRUE; | |
// | |
// Allocate the RecycledTxBuf. | |
// | |
Instance->RecycledTxBuf = malloc (sizeof (UINT64) * Instance->MaxRecycledTxBuf); | |
if (Instance->RecycledTxBuf == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Set the interface information. | |
// | |
CopyMem (&Instance->InterfaceInfo, NetInfo, sizeof (Instance->InterfaceInfo)); | |
// | |
// Set broadcast address | |
// | |
SetMem (&Instance->Mode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); | |
// | |
// Copy Current/PermanentAddress MAC address | |
// | |
CopyMem (&Instance->Mode.CurrentAddress, &Instance->InterfaceInfo.MacAddr, sizeof (Instance->Mode.CurrentAddress)); | |
CopyMem (&Instance->Mode.PermanentAddress, &Instance->InterfaceInfo.MacAddr, sizeof (Instance->Mode.PermanentAddress)); | |
// | |
// Since the fake SNP is based on a real NIC, to avoid conflict with the host | |
// NIC network stack, we use a different MAC address. | |
// So just change the last byte of the MAC address for the real NIC. | |
// | |
Instance->Mode.CurrentAddress.Addr[NET_ETHER_ADDR_LEN - 1]++; | |
return EFI_SUCCESS; | |
} | |
/** | |
Initialize the net utility data. | |
@param This Pointer to the private data. | |
@param ActiveInstance The active network interface. | |
@retval EFI_SUCCESS The global data is initialized. | |
@retval EFI_NOT_FOUND The required DLL is not found. | |
@retval EFI_DEVICE_ERROR Error initialize network utility library. | |
@retval other Other errors. | |
**/ | |
EFI_STATUS | |
WintNtInitializeNetUtilityData ( | |
IN OUT WIN_NT_SNP_PRIVATE *Private, | |
IN UINT8 ActiveInstance | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 *DllFileNameU; | |
INT32 ReturnValue; | |
BOOLEAN NetUtilityLibInitDone; | |
NT_NET_INTERFACE_INFO NetInterfaceInfoBuffer[MAX_INTERFACE_INFO_NUMBER]; | |
UINT32 InterfaceCount; | |
UINT8 ActiveInterfaceIndex; | |
if (Private == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
NetUtilityLibInitDone = FALSE; | |
InterfaceCount = MAX_INTERFACE_INFO_NUMBER; | |
DllFileNameU = NETWORK_LIBRARY_NAME_U; | |
// | |
// Load network utility library | |
// | |
Private->NetworkLibraryHandle = LoadLibraryEx (DllFileNameU, NULL, 0); | |
if (NULL == Private->NetworkLibraryHandle) { | |
return EFI_NOT_FOUND; | |
} | |
Private->NtNetUtilityTable.Initialize = (NT_NET_INITIALIZE)GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_INITIALIZE); | |
if (NULL == Private->NtNetUtilityTable.Initialize) { | |
Status = EFI_NOT_FOUND; | |
goto ErrorReturn; | |
} | |
Private->NtNetUtilityTable.Finalize = (NT_NET_FINALIZE)GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_FINALIZE); | |
if (NULL == Private->NtNetUtilityTable.Finalize) { | |
Status = EFI_NOT_FOUND; | |
goto ErrorReturn; | |
} | |
Private->NtNetUtilityTable.SetReceiveFilter = (NT_NET_SET_RECEIVE_FILTER)GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_SET_RCV_FILTER); | |
if (NULL == Private->NtNetUtilityTable.SetReceiveFilter) { | |
Status = EFI_NOT_FOUND; | |
goto ErrorReturn; | |
} | |
Private->NtNetUtilityTable.Receive = (NT_NET_RECEIVE)GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_RECEIVE); | |
if (NULL == Private->NtNetUtilityTable.Receive) { | |
Status = EFI_NOT_FOUND; | |
goto ErrorReturn; | |
} | |
Private->NtNetUtilityTable.Transmit = (NT_NET_TRANSMIT)GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_TRANSMIT); | |
if (NULL == Private->NtNetUtilityTable.Transmit) { | |
Status = EFI_NOT_FOUND; | |
goto ErrorReturn; | |
} | |
// | |
// Initialize the network utility library | |
// And enumerate the interfaces in emulator host | |
// | |
ReturnValue = Private->NtNetUtilityTable.Initialize (&InterfaceCount, &NetInterfaceInfoBuffer[0]); | |
if (ReturnValue <= 0) { | |
Status = EFI_DEVICE_ERROR; | |
goto ErrorReturn; | |
} | |
NetUtilityLibInitDone = TRUE; | |
if (InterfaceCount == 0) { | |
Status = EFI_NOT_FOUND; | |
goto ErrorReturn; | |
} | |
DEBUG ((DEBUG_INFO, "%a, total %d interface(s) found\n", __func__, InterfaceCount)); | |
// | |
// Active interface index is set to first interface if given instance does | |
// not exist. | |
// | |
ActiveInterfaceIndex = (ActiveInstance >= InterfaceCount ? DEFAULT_SELECTED_NIC_INDEX : ActiveInstance); | |
// | |
// Initialize instance | |
// | |
Status = WinNtInitializeInstanceData (&Private->Instance, &NetInterfaceInfoBuffer[ActiveInterfaceIndex]); | |
if (EFI_ERROR (Status)) { | |
goto ErrorReturn; | |
} | |
return EFI_SUCCESS; | |
ErrorReturn: | |
if (Private->Instance.RecycledTxBuf != NULL) { | |
free (Private->Instance.RecycledTxBuf); | |
} | |
if (NetUtilityLibInitDone) { | |
if (Private->NtNetUtilityTable.Finalize != NULL) { | |
Private->NtNetUtilityTable.Finalize (); | |
Private->NtNetUtilityTable.Finalize = NULL; | |
} | |
} | |
return Status; | |
} | |
/** | |
Release the net utility data. | |
@param This Pointer to the private data. | |
@retval EFI_SUCCESS The global data is released. | |
@retval other Other errors. | |
**/ | |
EFI_STATUS | |
WintNtReleaseNetUtilityData ( | |
IN OUT WIN_NT_SNP_PRIVATE *Private | |
) | |
{ | |
if (Private == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (Private->Instance.RecycledTxBuf != NULL) { | |
free (Private->Instance.RecycledTxBuf); | |
} | |
if (Private->NtNetUtilityTable.Finalize != NULL) { | |
Private->NtNetUtilityTable.Finalize (); | |
} | |
FreeLibrary (Private->NetworkLibraryHandle); | |
return EFI_SUCCESS; | |
} | |
EMU_SNP_PROTOCOL mWinNtSnpProtocol = { | |
WinNtSnpCreateMapping, | |
WinNtSnpStart, | |
WinNtSnpStop, | |
WinNtSnpInitialize, | |
WinNtSnpReset, | |
WinNtSnpShutdown, | |
WinNtSnpReceiveFilters, | |
WinNtSnpStationAddress, | |
WinNtSnpStatistics, | |
WinNtSnpMCastIpToMac, | |
WinNtSnpNvData, | |
WinNtSnpGetStatus, | |
WinNtSnpTransmit, | |
WinNtSnpReceive | |
}; | |
/** | |
Open SNP thunk protocol. | |
@param This Pointer to the thunk protocol instance. | |
@retval EFI_SUCCESS SNP thunk protocol is opened successfully. | |
@retval EFI_UNSUPPORTED This is not SNP thunk protocol. | |
@retval EFI_OUT_OF_RESOURCES Not enough memory. | |
@retval other Other errors. | |
**/ | |
EFI_STATUS | |
WinNtSnpThunkOpen ( | |
IN EMU_IO_THUNK_PROTOCOL *This | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
UINT8 HostInterfaceIndex; | |
HostInterfaceIndex = 0; | |
if (This->Private != NULL) { | |
return EFI_ALREADY_STARTED; | |
} | |
if (!CompareGuid (This->Protocol, &gEmuSnpProtocolGuid)) { | |
return EFI_UNSUPPORTED; | |
} | |
Private = malloc (sizeof (WIN_NT_SNP_PRIVATE)); | |
if (Private == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Private->Signature = WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE; | |
Private->Thunk = This; | |
CopyMem (&Private->EmuSnp, &mWinNtSnpProtocol, sizeof (mWinNtSnpProtocol)); | |
This->Interface = &Private->EmuSnp; | |
This->Private = Private; | |
if ((This->ConfigString != NULL) && (This->ConfigString[0] != '\0')) { | |
HostInterfaceIndex = (UINT8)StrDecimalToUintn (This->ConfigString); | |
} | |
return WintNtInitializeNetUtilityData (Private, HostInterfaceIndex); | |
} | |
/** | |
Close SNP thunk protocol. | |
@param This Pointer to the thunk protocol instance. | |
@retval EFI_SUCCESS SNP thunk protocol is closed successfully. | |
@retval EFI_UNSUPPORTED This is not SNP thunk protocol. | |
@retval other Other errors. | |
**/ | |
EFI_STATUS | |
WinNtSnpThunkClose ( | |
IN EMU_IO_THUNK_PROTOCOL *This | |
) | |
{ | |
WIN_NT_SNP_PRIVATE *Private; | |
if (!CompareGuid (This->Protocol, &gEmuSnpProtocolGuid)) { | |
return EFI_UNSUPPORTED; | |
} | |
Private = This->Private; | |
WintNtReleaseNetUtilityData (Private); | |
free (Private); | |
return EFI_SUCCESS; | |
} | |
EMU_IO_THUNK_PROTOCOL mWinNtSnpThunkIo = { | |
&gEmuSnpProtocolGuid, | |
NULL, | |
NULL, | |
0, | |
WinNtSnpThunkOpen, | |
WinNtSnpThunkClose, | |
NULL | |
}; |