/** @file
|
Implementation of managing the multicast receive filters of a network
|
interface.
|
|
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include "Snp.h"
|
|
/**
|
Call undi to enable the receive filters.
|
|
@param Snp Pointer to snp driver structure.
|
@param EnableFlags Bit mask for enabling the receive filters.
|
@param MCastAddressCount Multicast address count for a new multicast address
|
list.
|
@param MCastAddressList List of new multicast addresses.
|
|
@retval EFI_SUCCESS The multicast receive filter list was updated.
|
@retval EFI_INVALID_PARAMETER Invalid UNDI command.
|
@retval EFI_UNSUPPORTED Command is not supported by UNDI.
|
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
|
|
**/
|
EFI_STATUS
|
PxeRecvFilterEnable (
|
SNP_DRIVER *Snp,
|
UINT32 EnableFlags,
|
UINTN MCastAddressCount,
|
EFI_MAC_ADDRESS *MCastAddressList
|
)
|
{
|
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
|
Snp->Cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
|
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
|
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
|
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
|
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
|
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
|
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
|
Snp->Cdb.IFnum = Snp->IfNum;
|
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
|
|
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
|
}
|
|
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
|
}
|
|
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
|
}
|
|
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
|
}
|
|
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
|
}
|
|
if (MCastAddressCount != 0) {
|
Snp->Cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
|
Snp->Cdb.CPBaddr = (UINT64)(UINTN)Snp->Cpb;
|
CopyMem (Snp->Cpb, MCastAddressList, Snp->Cdb.CPBsize);
|
}
|
//
|
// Issue UNDI command and check result.
|
//
|
DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
|
|
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
|
|
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
|
//
|
// UNDI command failed. Return UNDI status to caller.
|
//
|
DEBUG (
|
(EFI_D_ERROR,
|
"\nsnp->undi.receive_filters() %xh:%xh\n",
|
Snp->Cdb.StatFlags,
|
Snp->Cdb.StatCode)
|
);
|
|
switch (Snp->Cdb.StatCode) {
|
case PXE_STATCODE_INVALID_CDB:
|
case PXE_STATCODE_INVALID_CPB:
|
case PXE_STATCODE_INVALID_PARAMETER:
|
return EFI_INVALID_PARAMETER;
|
|
case PXE_STATCODE_UNSUPPORTED:
|
return EFI_UNSUPPORTED;
|
}
|
|
return EFI_DEVICE_ERROR;
|
}
|
|
return EFI_SUCCESS;
|
}
|
|
/**
|
Call undi to disable the receive filters.
|
|
@param Snp Pointer to snp driver structure
|
@param DisableFlags Bit mask for disabling the receive filters
|
@param ResetMCastList Boolean flag to reset/delete the multicast filter
|
list.
|
|
@retval EFI_SUCCESS The multicast receive filter list was updated.
|
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
|
|
**/
|
EFI_STATUS
|
PxeRecvFilterDisable (
|
SNP_DRIVER *Snp,
|
UINT32 DisableFlags,
|
BOOLEAN ResetMCastList
|
)
|
{
|
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
|
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
|
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
|
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
|
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
|
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
|
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
|
Snp->Cdb.IFnum = Snp->IfNum;
|
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
|
|
Snp->Cdb.OpFlags = (UINT16) ((DisableFlags != 0) ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
|
|
if (ResetMCastList) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
|
}
|
|
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
|
}
|
|
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
|
}
|
|
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
|
}
|
|
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
|
}
|
|
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
|
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
|
}
|
//
|
// Issue UNDI command and check result.
|
//
|
DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
|
|
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
|
|
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
|
//
|
// UNDI command failed. Return UNDI status to caller.
|
//
|
DEBUG (
|
(EFI_D_ERROR,
|
"\nsnp->undi.receive_filters() %xh:%xh\n",
|
Snp->Cdb.StatFlags,
|
Snp->Cdb.StatCode)
|
);
|
|
return EFI_DEVICE_ERROR;
|
}
|
|
return EFI_SUCCESS;
|
}
|
|
/**
|
Call undi to read the receive filters.
|
|
@param Snp Pointer to snp driver structure.
|
|
@retval EFI_SUCCESS The receive filter was read.
|
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
|
|
**/
|
EFI_STATUS
|
PxeRecvFilterRead (
|
SNP_DRIVER *Snp
|
)
|
{
|
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
|
Snp->Cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ;
|
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
|
Snp->Cdb.DBsize = (UINT16) (Snp->Mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
|
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
|
if (Snp->Cdb.DBsize == 0) {
|
Snp->Cdb.DBaddr = (UINT64)(UINTN) NULL;
|
} else {
|
Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
|
ZeroMem (Snp->Db, Snp->Cdb.DBsize);
|
}
|
|
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
|
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
|
Snp->Cdb.IFnum = Snp->IfNum;
|
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
|
|
DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
|
|
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
|
|
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
|
//
|
// UNDI command failed. Return UNDI status to caller.
|
//
|
DEBUG (
|
(EFI_D_ERROR,
|
"\nsnp->undi.receive_filters() %xh:%xh\n",
|
Snp->Cdb.StatFlags,
|
Snp->Cdb.StatCode)
|
);
|
|
return EFI_DEVICE_ERROR;
|
}
|
//
|
// Convert UNDI32 StatFlags to EFI SNP filter flags.
|
//
|
Snp->Mode.ReceiveFilterSetting = 0;
|
|
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
|
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
|
}
|
|
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
|
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
|
}
|
|
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
|
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
|
}
|
|
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
|
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
|
}
|
|
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
|
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
|
}
|
|
CopyMem (Snp->Mode.MCastFilter, Snp->Db, Snp->Cdb.DBsize);
|
|
//
|
// Count number of active entries in multicast filter list.
|
//
|
{
|
EFI_MAC_ADDRESS ZeroMacAddr;
|
|
SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
|
|
for (Snp->Mode.MCastFilterCount = 0;
|
Snp->Mode.MCastFilterCount < Snp->Mode.MaxMCastFilterCount;
|
Snp->Mode.MCastFilterCount++
|
) {
|
if (CompareMem (
|
&Snp->Mode.MCastFilter[Snp->Mode.MCastFilterCount],
|
&ZeroMacAddr,
|
sizeof ZeroMacAddr
|
) == 0) {
|
break;
|
}
|
}
|
}
|
|
return EFI_SUCCESS;
|
}
|
|
|
/**
|
Manages the multicast receive filters of a network interface.
|
|
This function is used enable and disable the hardware and software receive
|
filters for the underlying network device.
|
The receive filter change is broken down into three steps:
|
* The filter mask bits that are set (ON) in the Enable parameter are added to
|
the current receive filter settings.
|
* The filter mask bits that are set (ON) in the Disable parameter are subtracted
|
from the updated receive filter settings.
|
* If the resulting receive filter setting is not supported by the hardware a
|
more liberal setting is selected.
|
If the same bits are set in the Enable and Disable parameters, then the bits
|
in the Disable parameter takes precedence.
|
If the ResetMCastFilter parameter is TRUE, then the multicast address list
|
filter is disabled (irregardless of what other multicast bits are set in the
|
Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set
|
to zero. The Snp->Mode->MCastFilter contents are undefined.
|
After enabling or disabling receive filter settings, software should verify
|
the new settings by checking the Snp->Mode->ReceiveFilterSettings,
|
Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields.
|
Note: Some network drivers and/or devices will automatically promote receive
|
filter settings if the requested setting can not be honored. For example, if
|
a request for four multicast addresses is made and the underlying hardware
|
only supports two multicast addresses the driver might set the promiscuous
|
or promiscuous multicast receive filters instead. The receiving software is
|
responsible for discarding any extra packets that get through the hardware
|
receive filters.
|
Note: Note: To disable all receive filter hardware, the network driver must
|
be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to
|
Snp->Mode->ReceiveFilterSettings will make it so no more packets are
|
returned by the Receive() function, but the receive hardware may still be
|
moving packets into system memory before inspecting and discarding them.
|
Unexpected system errors, reboots and hangs can occur if an OS is loaded
|
and the network devices are not Shutdown() and Stopped().
|
If ResetMCastFilter is TRUE, then the multicast receive filter list on the
|
network interface will be reset to the default multicast receive filter list.
|
If ResetMCastFilter is FALSE, and this network interface allows the multicast
|
receive filter list to be modified, then the MCastFilterCnt and MCastFilter
|
are used to update the current multicast receive filter list. The modified
|
receive filter list settings can be found in the MCastFilter field of
|
EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast
|
receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned.
|
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
|
If the receive filter mask and multicast receive filter list have been
|
successfully updated on the network interface, EFI_SUCCESS will be returned.
|
|
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
|
@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. For backward compatibility with EFI 1.1
|
platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit
|
must be set when the ResetMCastFilter parameter is TRUE.
|
@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 EFI_SIMPLE_NETWORK_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 following conditions is TRUE:
|
* This is NULL
|
* There are bits set in Enable that are not set
|
in Snp->Mode->ReceiveFilterMask
|
* There are bits set in Disable that are not set
|
in Snp->Mode->ReceiveFilterMask
|
* Multicast is being enabled (the
|
EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is
|
set in Enable, it is not set in Disable, and
|
ResetMCastFilter is FALSE) and MCastFilterCount
|
is zero
|
* Multicast is being enabled and MCastFilterCount
|
is greater than Snp->Mode->MaxMCastFilterCount
|
* Multicast is being enabled and MCastFilter is NULL
|
* Multicast is being enabled and one or more of
|
the addresses in the MCastFilter list are not
|
valid multicast MAC addresses
|
@retval EFI_DEVICE_ERROR One or more of the following conditions is TRUE:
|
* The network interface has been started but has
|
not been initialized
|
* An unexpected error was returned by the
|
underlying network driver or device
|
@retval EFI_UNSUPPORTED This function is not supported by the network
|
interface.
|
|
**/
|
EFI_STATUS
|
EFIAPI
|
SnpUndi32ReceiveFilters (
|
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
|
IN UINT32 Enable,
|
IN UINT32 Disable,
|
IN BOOLEAN ResetMCastFilter,
|
IN UINTN MCastFilterCnt, OPTIONAL
|
IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
|
)
|
{
|
SNP_DRIVER *Snp;
|
EFI_STATUS Status;
|
EFI_TPL OldTpl;
|
|
if (This == NULL) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
switch (Snp->Mode.State) {
|
case EfiSimpleNetworkInitialized:
|
break;
|
|
case EfiSimpleNetworkStopped:
|
Status = EFI_NOT_STARTED;
|
goto ON_EXIT;
|
|
default:
|
Status = EFI_DEVICE_ERROR;
|
goto ON_EXIT;
|
}
|
//
|
// check if we are asked to enable or disable something that the UNDI
|
// does not even support!
|
//
|
if (((Enable &~Snp->Mode.ReceiveFilterMask) != 0) ||
|
((Disable &~Snp->Mode.ReceiveFilterMask) != 0)) {
|
Status = EFI_INVALID_PARAMETER;
|
goto ON_EXIT;
|
}
|
|
if (ResetMCastFilter) {
|
|
Disable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & Snp->Mode.ReceiveFilterMask;
|
MCastFilterCnt = 0;
|
MCastFilter = NULL;
|
} else {
|
if (MCastFilterCnt != 0) {
|
if ((MCastFilterCnt > Snp->Mode.MaxMCastFilterCount) ||
|
(MCastFilter == NULL)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
goto ON_EXIT;
|
}
|
}
|
}
|
|
if (Enable == 0 && Disable == 0 && !ResetMCastFilter && MCastFilterCnt == 0) {
|
Status = EFI_SUCCESS;
|
goto ON_EXIT;
|
}
|
|
if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {
|
Status = EFI_INVALID_PARAMETER;
|
goto ON_EXIT;
|
}
|
|
if ((Enable != 0) || (MCastFilterCnt != 0)) {
|
Status = PxeRecvFilterEnable (
|
Snp,
|
Enable,
|
MCastFilterCnt,
|
MCastFilter
|
);
|
|
if (EFI_ERROR (Status)) {
|
goto ON_EXIT;
|
}
|
}
|
|
if ((Disable != 0) || ResetMCastFilter) {
|
Status = PxeRecvFilterDisable (Snp, Disable, ResetMCastFilter);
|
|
if (EFI_ERROR (Status)) {
|
goto ON_EXIT;
|
}
|
}
|
|
Status = PxeRecvFilterRead (Snp);
|
|
ON_EXIT:
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
}
|