mirror of https://github.com/acidanthera/audk.git
1674 lines
46 KiB
C
1674 lines
46 KiB
C
/** @file
|
|
The implementation of the ARP protocol.
|
|
|
|
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at<BR>
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "ArpImpl.h"
|
|
|
|
//
|
|
// Global variable of EFI ARP Protocol Interface.
|
|
//
|
|
EFI_ARP_PROTOCOL mEfiArpProtocolTemplate = {
|
|
ArpConfigure,
|
|
ArpAdd,
|
|
ArpFind,
|
|
ArpDelete,
|
|
ArpFlush,
|
|
ArpRequest,
|
|
ArpCancel
|
|
};
|
|
|
|
|
|
/**
|
|
Initialize the instance context data.
|
|
|
|
@param[in] ArpService Pointer to the arp service context data this
|
|
instance belongs to.
|
|
@param[out] Instance Pointer to the instance context data.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
ArpInitInstance (
|
|
IN ARP_SERVICE_DATA *ArpService,
|
|
OUT ARP_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
|
|
|
|
Instance->Signature = ARP_INSTANCE_DATA_SIGNATURE;
|
|
Instance->ArpService = ArpService;
|
|
|
|
CopyMem (&Instance->ArpProto, &mEfiArpProtocolTemplate, sizeof (Instance->ArpProto));
|
|
|
|
Instance->Configured = FALSE;
|
|
Instance->InDestroy = FALSE;
|
|
|
|
InitializeListHead (&Instance->List);
|
|
}
|
|
|
|
|
|
/**
|
|
Process the Arp packets received from Mnp, the procedure conforms to RFC826.
|
|
|
|
@param[in] Context Pointer to the context data registerd to the
|
|
Event.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArpOnFrameRcvdDpc (
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARP_SERVICE_DATA *ArpService;
|
|
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;
|
|
EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
|
|
ARP_HEAD *Head;
|
|
ARP_ADDRESS ArpAddress;
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
LIST_ENTRY *Entry;
|
|
ARP_INSTANCE_DATA *Instance;
|
|
EFI_ARP_CONFIG_DATA *ConfigData;
|
|
NET_ARP_ADDRESS SenderAddress[2];
|
|
BOOLEAN ProtoMatched;
|
|
BOOLEAN IsTarget;
|
|
BOOLEAN MergeFlag;
|
|
|
|
ArpService = (ARP_SERVICE_DATA *)Context;
|
|
NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
|
|
|
|
RxToken = &ArpService->RxToken;
|
|
|
|
if (RxToken->Status == EFI_ABORTED) {
|
|
//
|
|
// The Token is aborted, possibly by arp itself, just return and the receiving
|
|
// process is stopped.
|
|
//
|
|
return;
|
|
}
|
|
|
|
if (EFI_ERROR (RxToken->Status)) {
|
|
//
|
|
// Restart the receiving if any other error Status occurs.
|
|
//
|
|
goto RESTART_RECEIVE;
|
|
}
|
|
|
|
//
|
|
// Status is EFI_SUCCESS, process the received frame.
|
|
//
|
|
RxData = RxToken->Packet.RxData;
|
|
//
|
|
// Sanity check.
|
|
//
|
|
if (RxData->DataLength < sizeof (ARP_HEAD)) {
|
|
//
|
|
// Restart the receiving if packet size is not correct.
|
|
//
|
|
goto RESTART_RECEIVE;
|
|
}
|
|
|
|
//
|
|
// Convert the byte order of the multi-byte fields.
|
|
//
|
|
Head = (ARP_HEAD *) RxData->PacketData;
|
|
Head->HwType = NTOHS (Head->HwType);
|
|
Head->ProtoType = NTOHS (Head->ProtoType);
|
|
Head->OpCode = NTOHS (Head->OpCode);
|
|
|
|
if (RxData->DataLength < (sizeof (ARP_HEAD) + 2 * Head->HwAddrLen + 2 * Head->ProtoAddrLen)) {
|
|
goto RESTART_RECEIVE;
|
|
}
|
|
|
|
if ((Head->HwType != ArpService->SnpMode.IfType) ||
|
|
(Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||
|
|
(RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {
|
|
//
|
|
// The hardware type or the hardware address length doesn't match.
|
|
// There is a sanity check for the protocol type too.
|
|
//
|
|
goto RECYCLE_RXDATA;
|
|
}
|
|
|
|
//
|
|
// Set the pointers to the addresses contained in the arp packet.
|
|
//
|
|
ArpAddress.SenderHwAddr = (UINT8 *)(Head + 1);
|
|
ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;
|
|
ArpAddress.TargetHwAddr = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;
|
|
ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;
|
|
|
|
SenderAddress[Hardware].Type = Head->HwType;
|
|
SenderAddress[Hardware].Length = Head->HwAddrLen;
|
|
SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;
|
|
|
|
SenderAddress[Protocol].Type = Head->ProtoType;
|
|
SenderAddress[Protocol].Length = Head->ProtoAddrLen;
|
|
SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;
|
|
|
|
//
|
|
// First, check the denied cache table.
|
|
//
|
|
CacheEntry = ArpFindDeniedCacheEntry (
|
|
ArpService,
|
|
&SenderAddress[Protocol],
|
|
&SenderAddress[Hardware]
|
|
);
|
|
if (CacheEntry != NULL) {
|
|
//
|
|
// This address (either hardware or protocol address, or both) is configured to
|
|
// be a deny entry, silently skip the normal process.
|
|
//
|
|
goto RECYCLE_RXDATA;
|
|
}
|
|
|
|
ProtoMatched = FALSE;
|
|
IsTarget = FALSE;
|
|
Instance = NULL;
|
|
NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {
|
|
//
|
|
// Iterate all the children.
|
|
//
|
|
Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);
|
|
NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
|
|
ConfigData = &Instance->ConfigData;
|
|
|
|
if ((Instance->Configured) &&
|
|
(Head->ProtoType == ConfigData->SwAddressType) &&
|
|
(Head->ProtoAddrLen == ConfigData->SwAddressLength)) {
|
|
//
|
|
// The protocol type is matched for the received arp packet.
|
|
//
|
|
ProtoMatched = TRUE;
|
|
if (0 == CompareMem (
|
|
(VOID *)ArpAddress.TargetProtoAddr,
|
|
ConfigData->StationAddress,
|
|
ConfigData->SwAddressLength
|
|
)) {
|
|
//
|
|
// The arp driver has the target address required by the received arp packet.
|
|
//
|
|
IsTarget = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ProtoMatched) {
|
|
//
|
|
// Protocol type unmatchable, skip.
|
|
//
|
|
goto RECYCLE_RXDATA;
|
|
}
|
|
|
|
//
|
|
// Check whether the sender's address information is already in the cache.
|
|
//
|
|
MergeFlag = FALSE;
|
|
CacheEntry = ArpFindNextCacheEntryInTable (
|
|
&ArpService->ResolvedCacheTable,
|
|
NULL,
|
|
ByProtoAddress,
|
|
&SenderAddress[Protocol],
|
|
NULL
|
|
);
|
|
if (CacheEntry != NULL) {
|
|
//
|
|
// Update the entry with the new information.
|
|
//
|
|
ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);
|
|
CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
|
|
MergeFlag = TRUE;
|
|
}
|
|
|
|
if (!IsTarget) {
|
|
//
|
|
// This arp packet isn't targeted to us, skip now.
|
|
//
|
|
goto RECYCLE_RXDATA;
|
|
}
|
|
|
|
if (!MergeFlag) {
|
|
//
|
|
// Add the triplet <protocol type, sender protocol address, sender hardware address>
|
|
// to the translation table.
|
|
//
|
|
CacheEntry = ArpFindNextCacheEntryInTable (
|
|
&ArpService->PendingRequestTable,
|
|
NULL,
|
|
ByProtoAddress,
|
|
&SenderAddress[Protocol],
|
|
NULL
|
|
);
|
|
if (CacheEntry == NULL) {
|
|
//
|
|
// Allocate a new CacheEntry.
|
|
//
|
|
CacheEntry = ArpAllocCacheEntry (NULL);
|
|
if (CacheEntry == NULL) {
|
|
goto RECYCLE_RXDATA;
|
|
}
|
|
}
|
|
|
|
if (!IsListEmpty (&CacheEntry->List)) {
|
|
RemoveEntryList (&CacheEntry->List);
|
|
}
|
|
|
|
//
|
|
// Fill the addresses into the CacheEntry.
|
|
//
|
|
ArpFillAddressInCacheEntry (
|
|
CacheEntry,
|
|
&SenderAddress[Hardware],
|
|
&SenderAddress[Protocol]
|
|
);
|
|
|
|
//
|
|
// Inform the user.
|
|
//
|
|
ArpAddressResolved (CacheEntry, NULL, NULL);
|
|
|
|
//
|
|
// Add this entry into the ResolvedCacheTable
|
|
//
|
|
InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);
|
|
}
|
|
|
|
if (Head->OpCode == ARP_OPCODE_REQUEST) {
|
|
//
|
|
// Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
|
|
// is not NULL.
|
|
//
|
|
ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);
|
|
}
|
|
|
|
RECYCLE_RXDATA:
|
|
|
|
//
|
|
// Signal Mnp to recycle the RxData.
|
|
//
|
|
gBS->SignalEvent (RxData->RecycleEvent);
|
|
|
|
RESTART_RECEIVE:
|
|
|
|
//
|
|
// Continue to receive packets from Mnp.
|
|
//
|
|
Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);
|
|
|
|
DEBUG_CODE (
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "ArpOnFrameRcvd: ArpService->Mnp->Receive "
|
|
"failed, %r\n.", Status));
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
Queue ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the
|
|
Event.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArpOnFrameRcvd (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
//
|
|
// Request ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK
|
|
//
|
|
QueueDpc (TPL_CALLBACK, ArpOnFrameRcvdDpc, Context);
|
|
}
|
|
|
|
/**
|
|
Process the already sent arp packets.
|
|
|
|
@param[in] Context Pointer to the context data registerd to the
|
|
Event.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArpOnFrameSentDpc (
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TxToken;
|
|
EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
|
|
|
|
ASSERT (Context != NULL);
|
|
|
|
TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;
|
|
TxData = TxToken->Packet.TxData;
|
|
|
|
DEBUG_CODE (
|
|
if (EFI_ERROR (TxToken->Status)) {
|
|
DEBUG ((EFI_D_ERROR, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));
|
|
}
|
|
);
|
|
|
|
//
|
|
// Free the allocated memory and close the event.
|
|
//
|
|
FreePool (TxData->FragmentTable[0].FragmentBuffer);
|
|
FreePool (TxData);
|
|
gBS->CloseEvent (TxToken->Event);
|
|
FreePool (TxToken);
|
|
}
|
|
|
|
/**
|
|
Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the
|
|
Event.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArpOnFrameSent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
//
|
|
// Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK
|
|
//
|
|
QueueDpc (TPL_CALLBACK, ArpOnFrameSentDpc, Context);
|
|
}
|
|
|
|
|
|
/**
|
|
Process the arp cache olding and drive the retrying arp requests.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the
|
|
Event.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArpTimerHandler (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
ARP_SERVICE_DATA *ArpService;
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *NextEntry;
|
|
LIST_ENTRY *ContextEntry;
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
USER_REQUEST_CONTEXT *RequestContext;
|
|
|
|
ASSERT (Context != NULL);
|
|
ArpService = (ARP_SERVICE_DATA *)Context;
|
|
|
|
//
|
|
// Iterate all the pending requests to see whether a retry is needed to send out
|
|
// or the request finally fails because the retry time reaches the limitation.
|
|
//
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
|
|
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
|
|
|
|
if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {
|
|
//
|
|
// Timeout, if we can retry more, send out the request again, otherwise abort
|
|
// this request.
|
|
//
|
|
if (CacheEntry->RetryCount == 0) {
|
|
//
|
|
// Abort this request.
|
|
//
|
|
ArpAddressResolved (CacheEntry, NULL, NULL);
|
|
ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
|
|
|
|
RemoveEntryList (&CacheEntry->List);
|
|
FreePool (CacheEntry);
|
|
} else {
|
|
//
|
|
// resend the ARP request.
|
|
//
|
|
ASSERT (!IsListEmpty(&CacheEntry->UserRequestList));
|
|
|
|
ContextEntry = CacheEntry->UserRequestList.ForwardLink;
|
|
RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);
|
|
|
|
ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);
|
|
|
|
CacheEntry->RetryCount--;
|
|
CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;
|
|
}
|
|
} else {
|
|
//
|
|
// Update the NextRetryTime.
|
|
//
|
|
CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check the timeouts for the DeniedCacheTable.
|
|
//
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {
|
|
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
|
|
ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
|
|
|
|
if (CacheEntry->DefaultDecayTime == 0) {
|
|
//
|
|
// It's a static entry, skip it.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
|
|
//
|
|
// Time out, remove it.
|
|
//
|
|
RemoveEntryList (&CacheEntry->List);
|
|
FreePool (CacheEntry);
|
|
} else {
|
|
//
|
|
// Update the DecayTime.
|
|
//
|
|
CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check the timeouts for the ResolvedCacheTable.
|
|
//
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {
|
|
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
|
|
ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
|
|
|
|
if (CacheEntry->DefaultDecayTime == 0) {
|
|
//
|
|
// It's a static entry, skip it.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
|
|
//
|
|
// Time out, remove it.
|
|
//
|
|
RemoveEntryList (&CacheEntry->List);
|
|
FreePool (CacheEntry);
|
|
} else {
|
|
//
|
|
// Update the DecayTime.
|
|
//
|
|
CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Match the two NET_ARP_ADDRESSes.
|
|
|
|
@param[in] AddressOne Pointer to the first address to match.
|
|
@param[in] AddressTwo Pointer to the second address to match.
|
|
|
|
@return The two addresses match or not.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ArpMatchAddress (
|
|
IN NET_ARP_ADDRESS *AddressOne,
|
|
IN NET_ARP_ADDRESS *AddressTwo
|
|
)
|
|
{
|
|
ASSERT (AddressOne != NULL && AddressTwo != NULL);
|
|
|
|
if ((AddressOne->Type != AddressTwo->Type) ||
|
|
(AddressOne->Length != AddressTwo->Length)) {
|
|
//
|
|
// Either Type or Length doesn't match.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if ((AddressOne->AddressPtr != NULL) &&
|
|
(CompareMem (
|
|
AddressOne->AddressPtr,
|
|
AddressTwo->AddressPtr,
|
|
AddressOne->Length
|
|
) != 0)) {
|
|
//
|
|
// The address is not the same.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
Find the CacheEntry which matches the requirements in the specified CacheTable.
|
|
|
|
@param[in] CacheTable Pointer to the arp cache table.
|
|
@param[in] StartEntry Pointer to the start entry this search begins with
|
|
in the cache table.
|
|
@param[in] FindOpType The search type.
|
|
@param[in] ProtocolAddress Pointer to the protocol address to match.
|
|
@param[in] HardwareAddress Pointer to the hardware address to match.
|
|
|
|
@return Pointer to the matched arp cache entry, if NULL, no match is found.
|
|
|
|
**/
|
|
ARP_CACHE_ENTRY *
|
|
ArpFindNextCacheEntryInTable (
|
|
IN LIST_ENTRY *CacheTable,
|
|
IN LIST_ENTRY *StartEntry,
|
|
IN FIND_OPTYPE FindOpType,
|
|
IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,
|
|
IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
|
|
if (StartEntry == NULL) {
|
|
//
|
|
// Start from the beginning of the table if no StartEntry is specified.
|
|
//
|
|
StartEntry = CacheTable;
|
|
}
|
|
|
|
for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {
|
|
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
|
|
|
|
if ((FindOpType & MATCH_SW_ADDRESS) != 0) {
|
|
//
|
|
// Find by the software address.
|
|
//
|
|
if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {
|
|
//
|
|
// The ProtocolAddress doesn't match, continue to the next cache entry.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ((FindOpType & MATCH_HW_ADDRESS) != 0) {
|
|
//
|
|
// Find by the hardware address.
|
|
//
|
|
if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {
|
|
//
|
|
// The HardwareAddress doesn't match, continue to the next cache entry.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The CacheEntry meets the requirements now, return this entry.
|
|
//
|
|
return CacheEntry;
|
|
}
|
|
|
|
//
|
|
// No matching.
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
|
|
in the DeniedCacheTable.
|
|
|
|
@param[in] ArpService Pointer to the arp service context data.
|
|
@param[in] ProtocolAddress Pointer to the protocol address.
|
|
@param[in] HardwareAddress Pointer to the hardware address.
|
|
|
|
@return Pointer to the matched cache entry, if NULL no match is found.
|
|
|
|
**/
|
|
ARP_CACHE_ENTRY *
|
|
ArpFindDeniedCacheEntry (
|
|
IN ARP_SERVICE_DATA *ArpService,
|
|
IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,
|
|
IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL
|
|
)
|
|
{
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
|
|
ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));
|
|
NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
|
|
|
|
CacheEntry = NULL;
|
|
|
|
if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {
|
|
//
|
|
// Find the cache entry in the DeniedCacheTable by the protocol address.
|
|
//
|
|
CacheEntry = ArpFindNextCacheEntryInTable (
|
|
&ArpService->DeniedCacheTable,
|
|
NULL,
|
|
ByProtoAddress,
|
|
ProtocolAddress,
|
|
NULL
|
|
);
|
|
if (CacheEntry != NULL) {
|
|
//
|
|
// There is a match.
|
|
//
|
|
return CacheEntry;
|
|
}
|
|
}
|
|
|
|
if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {
|
|
//
|
|
// Find the cache entry in the DeniedCacheTable by the hardware address.
|
|
//
|
|
CacheEntry = ArpFindNextCacheEntryInTable (
|
|
&ArpService->DeniedCacheTable,
|
|
NULL,
|
|
ByHwAddress,
|
|
NULL,
|
|
HardwareAddress
|
|
);
|
|
}
|
|
|
|
return CacheEntry;
|
|
}
|
|
|
|
|
|
/**
|
|
Allocate a cache entry and initialize it.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
|
|
@return Pointer to the new created cache entry.
|
|
|
|
**/
|
|
ARP_CACHE_ENTRY *
|
|
ArpAllocCacheEntry (
|
|
IN ARP_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
NET_ARP_ADDRESS *Address;
|
|
UINT16 Index;
|
|
|
|
//
|
|
// Allocate memory for the cache entry.
|
|
//
|
|
CacheEntry = AllocatePool (sizeof (ARP_CACHE_ENTRY));
|
|
if (CacheEntry == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Init the lists.
|
|
//
|
|
InitializeListHead (&CacheEntry->List);
|
|
InitializeListHead (&CacheEntry->UserRequestList);
|
|
|
|
for (Index = 0; Index < 2; Index++) {
|
|
//
|
|
// Init the address pointers to point to the concrete buffer.
|
|
//
|
|
Address = &CacheEntry->Addresses[Index];
|
|
Address->AddressPtr = Address->Buffer.ProtoAddress;
|
|
}
|
|
|
|
//
|
|
// Zero the hardware address first.
|
|
//
|
|
ZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);
|
|
|
|
if (Instance != NULL) {
|
|
//
|
|
// Inherit the parameters from the instance configuration.
|
|
//
|
|
CacheEntry->RetryCount = Instance->ConfigData.RetryCount;
|
|
CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;
|
|
CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;
|
|
CacheEntry->DecayTime = Instance->ConfigData.EntryTimeOut;
|
|
} else {
|
|
//
|
|
// Use the default parameters if this cache entry isn't allocate in a
|
|
// instance's scope.
|
|
//
|
|
CacheEntry->RetryCount = ARP_DEFAULT_RETRY_COUNT;
|
|
CacheEntry->NextRetryTime = ARP_DEFAULT_RETRY_INTERVAL;
|
|
CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
|
|
CacheEntry->DecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
|
|
}
|
|
|
|
return CacheEntry;
|
|
}
|
|
|
|
|
|
/**
|
|
Turn the CacheEntry into the resolved status.
|
|
|
|
@param[in] CacheEntry Pointer to the resolved cache entry.
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] UserEvent Pointer to the UserEvent to notify.
|
|
|
|
@return The count of notifications sent to the instance.
|
|
|
|
**/
|
|
UINTN
|
|
ArpAddressResolved (
|
|
IN ARP_CACHE_ENTRY *CacheEntry,
|
|
IN ARP_INSTANCE_DATA *Instance OPTIONAL,
|
|
IN EFI_EVENT UserEvent OPTIONAL
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *NextEntry;
|
|
USER_REQUEST_CONTEXT *Context;
|
|
UINTN Count;
|
|
|
|
Count = 0;
|
|
|
|
//
|
|
// Iterate all the linked user requests to notify them.
|
|
//
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {
|
|
Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);
|
|
|
|
if (((Instance == NULL) || (Context->Instance == Instance)) &&
|
|
((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {
|
|
//
|
|
// Copy the address to the user-provided buffer and notify the user.
|
|
//
|
|
CopyMem (
|
|
Context->UserHwAddrBuffer,
|
|
CacheEntry->Addresses[Hardware].AddressPtr,
|
|
CacheEntry->Addresses[Hardware].Length
|
|
);
|
|
gBS->SignalEvent (Context->UserRequestEvent);
|
|
|
|
//
|
|
// Remove this user request and free the context data.
|
|
//
|
|
RemoveEntryList (&Context->List);
|
|
FreePool (Context);
|
|
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.
|
|
//
|
|
DispatchDpc ();
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
/**
|
|
Fill the addresses in the CacheEntry using the information passed in by
|
|
HwAddr and SwAddr.
|
|
|
|
@param[in] CacheEntry Pointer to the cache entry.
|
|
@param[in] HwAddr Pointer to the software address.
|
|
@param[in] SwAddr Pointer to the hardware address.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
ArpFillAddressInCacheEntry (
|
|
IN ARP_CACHE_ENTRY *CacheEntry,
|
|
IN NET_ARP_ADDRESS *HwAddr OPTIONAL,
|
|
IN NET_ARP_ADDRESS *SwAddr OPTIONAL
|
|
)
|
|
{
|
|
NET_ARP_ADDRESS *Address[2];
|
|
NET_ARP_ADDRESS *CacheAddress;
|
|
UINT32 Index;
|
|
|
|
Address[Hardware] = HwAddr;
|
|
Address[Protocol] = SwAddr;
|
|
|
|
for (Index = 0; Index < 2; Index++) {
|
|
if (Address[Index] != NULL) {
|
|
//
|
|
// Fill the address if the passed in pointer is not NULL.
|
|
//
|
|
CacheAddress = &CacheEntry->Addresses[Index];
|
|
|
|
CacheAddress->Type = Address[Index]->Type;
|
|
CacheAddress->Length = Address[Index]->Length;
|
|
|
|
if (Address[Index]->AddressPtr != NULL) {
|
|
//
|
|
// Copy it if the AddressPtr points to some buffer.
|
|
//
|
|
CopyMem (
|
|
CacheAddress->AddressPtr,
|
|
Address[Index]->AddressPtr,
|
|
CacheAddress->Length
|
|
);
|
|
} else {
|
|
//
|
|
// Zero the corresponding address buffer in the CacheEntry.
|
|
//
|
|
ZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Configure the instance using the ConfigData. ConfigData is already validated.
|
|
|
|
@param[in] Instance Pointer to the instance context data to be
|
|
configured.
|
|
@param[in] ConfigData Pointer to the configuration data used to
|
|
configure the instance.
|
|
|
|
@retval EFI_SUCCESS The instance is configured with the ConfigData.
|
|
@retval EFI_ACCESS_DENIED The instance is already configured and the
|
|
ConfigData tries to reset some unchangeable
|
|
fields.
|
|
@retval EFI_INVALID_PARAMETER The ConfigData provides a non-unicast IPv4 address
|
|
when the SwAddressType is IPv4.
|
|
@retval EFI_OUT_OF_RESOURCES The instance fails to configure due to memory
|
|
limitation.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ArpConfigureInstance (
|
|
IN ARP_INSTANCE_DATA *Instance,
|
|
IN EFI_ARP_CONFIG_DATA *ConfigData OPTIONAL
|
|
)
|
|
{
|
|
EFI_ARP_CONFIG_DATA *OldConfigData;
|
|
IP4_ADDR Ip;
|
|
|
|
OldConfigData = &Instance->ConfigData;
|
|
|
|
if (ConfigData != NULL) {
|
|
|
|
if (Instance->Configured) {
|
|
//
|
|
// The instance is configured, check the unchangeable fields.
|
|
//
|
|
if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||
|
|
(OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||
|
|
(CompareMem (
|
|
OldConfigData->StationAddress,
|
|
ConfigData->StationAddress,
|
|
OldConfigData->SwAddressLength
|
|
) != 0)) {
|
|
//
|
|
// Deny the unallowed changes.
|
|
//
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
} else {
|
|
//
|
|
// The instance is not configured.
|
|
//
|
|
|
|
if (ConfigData->SwAddressType == IPV4_ETHER_PROTO_TYPE) {
|
|
CopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));
|
|
|
|
if (IP4_IS_UNSPECIFIED (Ip) || IP4_IS_LOCAL_BROADCAST (Ip)) {
|
|
//
|
|
// The station address should not be zero or broadcast address.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the configuration.
|
|
//
|
|
CopyMem (OldConfigData, ConfigData, sizeof (*OldConfigData));
|
|
|
|
OldConfigData->StationAddress = AllocatePool (OldConfigData->SwAddressLength);
|
|
if (OldConfigData->StationAddress == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "ArpConfigInstance: AllocatePool for the StationAddress "
|
|
"failed.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Save the StationAddress.
|
|
//
|
|
CopyMem (
|
|
OldConfigData->StationAddress,
|
|
ConfigData->StationAddress,
|
|
OldConfigData->SwAddressLength
|
|
);
|
|
|
|
//
|
|
// Set the state to configured.
|
|
//
|
|
Instance->Configured = TRUE;
|
|
}
|
|
|
|
//
|
|
// Use the implementation specific values if the following field is zero.
|
|
//
|
|
OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?
|
|
ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;
|
|
|
|
OldConfigData->RetryCount = (ConfigData->RetryCount == 0) ?
|
|
ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;
|
|
|
|
OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?
|
|
ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;
|
|
} else {
|
|
//
|
|
// Reset the configuration.
|
|
//
|
|
|
|
if (Instance->Configured) {
|
|
//
|
|
// Cancel the arp requests issued by this instance.
|
|
//
|
|
Instance->ArpProto.Cancel (&Instance->ArpProto, NULL, NULL);
|
|
|
|
//
|
|
// Free the buffer previously allocated to hold the station address.
|
|
//
|
|
FreePool (OldConfigData->StationAddress);
|
|
}
|
|
|
|
Instance->Configured = FALSE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Send out an arp frame using the CachEntry and the ArpOpCode.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] CacheEntry Pointer to the configuration data used to
|
|
configure the instance.
|
|
@param[in] ArpOpCode The opcode used to send out this Arp frame, either
|
|
request or reply.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
ArpSendFrame (
|
|
IN ARP_INSTANCE_DATA *Instance,
|
|
IN ARP_CACHE_ENTRY *CacheEntry,
|
|
IN UINT16 ArpOpCode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TxToken;
|
|
EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
|
|
UINT32 TotalLength;
|
|
UINT8 *Packet;
|
|
ARP_SERVICE_DATA *ArpService;
|
|
EFI_SIMPLE_NETWORK_MODE *SnpMode;
|
|
EFI_ARP_CONFIG_DATA *ConfigData;
|
|
UINT8 *TmpPtr;
|
|
ARP_HEAD *ArpHead;
|
|
|
|
ASSERT ((Instance != NULL) && (CacheEntry != NULL));
|
|
|
|
//
|
|
// Allocate memory for the TxToken.
|
|
//
|
|
TxToken = AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));
|
|
if (TxToken == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxToken failed.\n"));
|
|
return;
|
|
}
|
|
|
|
TxToken->Event = NULL;
|
|
TxData = NULL;
|
|
Packet = NULL;
|
|
|
|
//
|
|
// Create the event for this TxToken.
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
ArpOnFrameSent,
|
|
(VOID *)TxToken,
|
|
&TxToken->Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
|
|
goto CLEAN_EXIT;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the TxData used in the TxToken.
|
|
//
|
|
TxData = AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));
|
|
if (TxData == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxData failed.\n"));
|
|
goto CLEAN_EXIT;
|
|
}
|
|
|
|
ArpService = Instance->ArpService;
|
|
SnpMode = &ArpService->SnpMode;
|
|
ConfigData = &Instance->ConfigData;
|
|
|
|
//
|
|
// Calculate the buffer length for this arp frame.
|
|
//
|
|
TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +
|
|
2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);
|
|
|
|
//
|
|
// Allocate buffer for the arp frame.
|
|
//
|
|
Packet = AllocatePool (TotalLength);
|
|
if (Packet == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for Packet failed.\n"));
|
|
ASSERT (Packet != NULL);
|
|
}
|
|
|
|
TmpPtr = Packet;
|
|
|
|
//
|
|
// The destination MAC address.
|
|
//
|
|
if (ArpOpCode == ARP_OPCODE_REQUEST) {
|
|
CopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
|
|
} else {
|
|
CopyMem (
|
|
TmpPtr,
|
|
CacheEntry->Addresses[Hardware].AddressPtr,
|
|
SnpMode->HwAddressSize
|
|
);
|
|
}
|
|
TmpPtr += SnpMode->HwAddressSize;
|
|
|
|
//
|
|
// The source MAC address.
|
|
//
|
|
CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
|
|
TmpPtr += SnpMode->HwAddressSize;
|
|
|
|
//
|
|
// The ethernet protocol type.
|
|
//
|
|
*(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);
|
|
TmpPtr += 2;
|
|
|
|
//
|
|
// The ARP Head.
|
|
//
|
|
ArpHead = (ARP_HEAD *) TmpPtr;
|
|
ArpHead->HwType = HTONS ((UINT16)SnpMode->IfType);
|
|
ArpHead->ProtoType = HTONS (ConfigData->SwAddressType);
|
|
ArpHead->HwAddrLen = (UINT8)SnpMode->HwAddressSize;
|
|
ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;
|
|
ArpHead->OpCode = HTONS (ArpOpCode);
|
|
TmpPtr += sizeof (ARP_HEAD);
|
|
|
|
//
|
|
// The sender hardware address.
|
|
//
|
|
CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
|
|
TmpPtr += SnpMode->HwAddressSize;
|
|
|
|
//
|
|
// The sender protocol address.
|
|
//
|
|
CopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);
|
|
TmpPtr += ConfigData->SwAddressLength;
|
|
|
|
//
|
|
// The target hardware address.
|
|
//
|
|
CopyMem (
|
|
TmpPtr,
|
|
CacheEntry->Addresses[Hardware].AddressPtr,
|
|
SnpMode->HwAddressSize
|
|
);
|
|
TmpPtr += SnpMode->HwAddressSize;
|
|
|
|
//
|
|
// The target protocol address.
|
|
//
|
|
CopyMem (
|
|
TmpPtr,
|
|
CacheEntry->Addresses[Protocol].AddressPtr,
|
|
ConfigData->SwAddressLength
|
|
);
|
|
|
|
//
|
|
// Set all the fields of the TxData.
|
|
//
|
|
TxData->DestinationAddress = NULL;
|
|
TxData->SourceAddress = NULL;
|
|
TxData->ProtocolType = 0;
|
|
TxData->DataLength = TotalLength - SnpMode->MediaHeaderSize;
|
|
TxData->HeaderLength = (UINT16) SnpMode->MediaHeaderSize;
|
|
TxData->FragmentCount = 1;
|
|
|
|
TxData->FragmentTable[0].FragmentBuffer = Packet;
|
|
TxData->FragmentTable[0].FragmentLength = TotalLength;
|
|
|
|
//
|
|
// Associate the TxData with the TxToken.
|
|
//
|
|
TxToken->Packet.TxData = TxData;
|
|
TxToken->Status = EFI_NOT_READY;
|
|
|
|
//
|
|
// Send out this arp packet by Mnp.
|
|
//
|
|
Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Mnp->Transmit failed, %r.\n", Status));
|
|
goto CLEAN_EXIT;
|
|
}
|
|
|
|
return;
|
|
|
|
CLEAN_EXIT:
|
|
|
|
if (Packet != NULL) {
|
|
FreePool (Packet);
|
|
}
|
|
|
|
if (TxData != NULL) {
|
|
FreePool (TxData);
|
|
}
|
|
|
|
if (TxToken->Event != NULL) {
|
|
gBS->CloseEvent (TxToken->Event);
|
|
}
|
|
|
|
FreePool (TxToken);
|
|
}
|
|
|
|
|
|
/**
|
|
Delete the cache entries in the specified CacheTable, using the BySwAddress,
|
|
SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,
|
|
the cache is deleted event it's a static entry.
|
|
|
|
@param[in] CacheTable Pointer to the cache table to do the deletion.
|
|
@param[in] BySwAddress Delete the cache entry by software address or by
|
|
hardware address.
|
|
@param[in] SwAddressType The software address used to do the deletion.
|
|
@param[in] AddressBuffer Pointer to the buffer containing the address to
|
|
match for the deletion.
|
|
@param[in] Force This deletion is forced or not.
|
|
|
|
@return The count of the deleted cache entries.
|
|
|
|
**/
|
|
UINTN
|
|
ArpDeleteCacheEntryInTable (
|
|
IN LIST_ENTRY *CacheTable,
|
|
IN BOOLEAN BySwAddress,
|
|
IN UINT16 SwAddressType,
|
|
IN UINT8 *AddressBuffer OPTIONAL,
|
|
IN BOOLEAN Force
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *NextEntry;
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
UINTN Count;
|
|
|
|
Count = 0;
|
|
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {
|
|
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
|
|
|
|
if ((CacheEntry->DefaultDecayTime == 0) && !Force) {
|
|
//
|
|
// It's a static entry and we are not forced to delete it, skip.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (BySwAddress) {
|
|
if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {
|
|
//
|
|
// Protocol address type matched. Check the address.
|
|
//
|
|
if ((AddressBuffer == NULL) ||
|
|
(CompareMem (
|
|
AddressBuffer,
|
|
CacheEntry->Addresses[Protocol].AddressPtr,
|
|
CacheEntry->Addresses[Protocol].Length
|
|
) == 0)) {
|
|
//
|
|
// Address matched.
|
|
//
|
|
goto MATCHED;
|
|
}
|
|
}
|
|
} else {
|
|
if ((AddressBuffer == NULL) ||
|
|
(CompareMem (
|
|
AddressBuffer,
|
|
CacheEntry->Addresses[Hardware].AddressPtr,
|
|
CacheEntry->Addresses[Hardware].Length
|
|
) == 0)) {
|
|
//
|
|
// Address matched.
|
|
//
|
|
goto MATCHED;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
|
|
MATCHED:
|
|
|
|
//
|
|
// Delete this entry.
|
|
//
|
|
RemoveEntryList (&CacheEntry->List);
|
|
ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
|
|
FreePool (CacheEntry);
|
|
|
|
Count++;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
/**
|
|
Delete cache entries in all the cache tables.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] BySwAddress Delete the cache entry by software address or by
|
|
hardware address.
|
|
@param[in] AddressBuffer Pointer to the buffer containing the address to
|
|
match for the deletion.
|
|
@param[in] Force This deletion is forced or not.
|
|
|
|
@return The count of the deleted cache entries.
|
|
|
|
**/
|
|
UINTN
|
|
ArpDeleteCacheEntry (
|
|
IN ARP_INSTANCE_DATA *Instance,
|
|
IN BOOLEAN BySwAddress,
|
|
IN UINT8 *AddressBuffer OPTIONAL,
|
|
IN BOOLEAN Force
|
|
)
|
|
{
|
|
ARP_SERVICE_DATA *ArpService;
|
|
UINTN Count;
|
|
|
|
NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
|
|
|
|
ArpService = Instance->ArpService;
|
|
|
|
//
|
|
// Delete the cache entries in the DeniedCacheTable.
|
|
//
|
|
Count = ArpDeleteCacheEntryInTable (
|
|
&ArpService->DeniedCacheTable,
|
|
BySwAddress,
|
|
Instance->ConfigData.SwAddressType,
|
|
AddressBuffer,
|
|
Force
|
|
);
|
|
|
|
//
|
|
// Delete the cache entries inthe ResolvedCacheTable.
|
|
//
|
|
Count += ArpDeleteCacheEntryInTable (
|
|
&ArpService->ResolvedCacheTable,
|
|
BySwAddress,
|
|
Instance->ConfigData.SwAddressType,
|
|
AddressBuffer,
|
|
Force
|
|
);
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
/**
|
|
Cancel the arp request.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] TargetSwAddress Pointer to the buffer containing the target
|
|
software address to match the arp request.
|
|
@param[in] UserEvent The user event used to notify this request
|
|
cancellation.
|
|
|
|
@return The count of the cancelled requests.
|
|
|
|
**/
|
|
UINTN
|
|
ArpCancelRequest (
|
|
IN ARP_INSTANCE_DATA *Instance,
|
|
IN VOID *TargetSwAddress OPTIONAL,
|
|
IN EFI_EVENT UserEvent OPTIONAL
|
|
)
|
|
{
|
|
ARP_SERVICE_DATA *ArpService;
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *NextEntry;
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
UINTN Count;
|
|
|
|
NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
|
|
|
|
ArpService = Instance->ArpService;
|
|
|
|
Count = 0;
|
|
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
|
|
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
|
|
|
|
if ((TargetSwAddress == NULL) ||
|
|
(CompareMem (
|
|
TargetSwAddress,
|
|
CacheEntry->Addresses[Protocol].AddressPtr,
|
|
CacheEntry->Addresses[Protocol].Length
|
|
) == 0)) {
|
|
//
|
|
// This request entry matches the TargetSwAddress or all requests are to be
|
|
// cancelled as TargetSwAddress is NULL.
|
|
//
|
|
Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);
|
|
|
|
if (IsListEmpty (&CacheEntry->UserRequestList)) {
|
|
//
|
|
// No user requests any more, remove this request cache entry.
|
|
//
|
|
RemoveEntryList (&CacheEntry->List);
|
|
FreePool (CacheEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
/**
|
|
Find the cache entry in the cache table.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] BySwAddress Set to TRUE to look for matching software protocol
|
|
addresses. Set to FALSE to look for matching
|
|
hardware protocol addresses.
|
|
@param[in] AddressBuffer Pointer to address buffer. Set to NULL to match
|
|
all addresses.
|
|
@param[out] EntryLength The size of an entry in the entries buffer.
|
|
@param[out] EntryCount The number of ARP cache entries that are found by
|
|
the specified criteria.
|
|
@param[out] Entries Pointer to the buffer that will receive the ARP
|
|
cache entries.
|
|
@param[in] Refresh Set to TRUE to refresh the timeout value of the
|
|
matching ARP cache entry.
|
|
|
|
@retval EFI_SUCCESS The requested ARP cache entries are copied into
|
|
the buffer.
|
|
@retval EFI_NOT_FOUND No matching entries found.
|
|
@retval EFI_OUT_OF_RESOURCE There is a memory allocation failure.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ArpFindCacheEntry (
|
|
IN ARP_INSTANCE_DATA *Instance,
|
|
IN BOOLEAN BySwAddress,
|
|
IN VOID *AddressBuffer OPTIONAL,
|
|
OUT UINT32 *EntryLength OPTIONAL,
|
|
OUT UINT32 *EntryCount OPTIONAL,
|
|
OUT EFI_ARP_FIND_DATA **Entries OPTIONAL,
|
|
IN BOOLEAN Refresh
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARP_SERVICE_DATA *ArpService;
|
|
NET_ARP_ADDRESS MatchAddress;
|
|
FIND_OPTYPE FindOpType;
|
|
LIST_ENTRY *StartEntry;
|
|
ARP_CACHE_ENTRY *CacheEntry;
|
|
NET_MAP FoundEntries;
|
|
UINT32 FoundCount;
|
|
EFI_ARP_FIND_DATA *FindData;
|
|
LIST_ENTRY *CacheTable;
|
|
UINT32 FoundEntryLength;
|
|
|
|
ArpService = Instance->ArpService;
|
|
|
|
//
|
|
// Init the FounEntries used to hold the found cache entries.
|
|
//
|
|
NetMapInit (&FoundEntries);
|
|
|
|
//
|
|
// Set the MatchAddress.
|
|
//
|
|
if (BySwAddress) {
|
|
MatchAddress.Type = Instance->ConfigData.SwAddressType;
|
|
MatchAddress.Length = Instance->ConfigData.SwAddressLength;
|
|
FindOpType = ByProtoAddress;
|
|
} else {
|
|
MatchAddress.Type = ArpService->SnpMode.IfType;
|
|
MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;
|
|
FindOpType = ByHwAddress;
|
|
}
|
|
|
|
MatchAddress.AddressPtr = AddressBuffer;
|
|
|
|
//
|
|
// Search the DeniedCacheTable
|
|
//
|
|
StartEntry = NULL;
|
|
while (TRUE) {
|
|
//
|
|
// Try to find the matched entries in the DeniedCacheTable.
|
|
//
|
|
CacheEntry = ArpFindNextCacheEntryInTable (
|
|
&ArpService->DeniedCacheTable,
|
|
StartEntry,
|
|
FindOpType,
|
|
&MatchAddress,
|
|
&MatchAddress
|
|
);
|
|
if (CacheEntry == NULL) {
|
|
//
|
|
// Once the CacheEntry is NULL, there are no more matches.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Insert the found entry into the map.
|
|
//
|
|
NetMapInsertTail (
|
|
&FoundEntries,
|
|
(VOID *)CacheEntry,
|
|
(VOID *)&ArpService->DeniedCacheTable
|
|
);
|
|
|
|
//
|
|
// Let the next search start from this cache entry.
|
|
//
|
|
StartEntry = &CacheEntry->List;
|
|
|
|
if (Refresh) {
|
|
//
|
|
// Refresh the DecayTime if needed.
|
|
//
|
|
CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Search the ResolvedCacheTable
|
|
//
|
|
StartEntry = NULL;
|
|
while (TRUE) {
|
|
CacheEntry = ArpFindNextCacheEntryInTable (
|
|
&ArpService->ResolvedCacheTable,
|
|
StartEntry,
|
|
FindOpType,
|
|
&MatchAddress,
|
|
&MatchAddress
|
|
);
|
|
if (CacheEntry == NULL) {
|
|
//
|
|
// Once the CacheEntry is NULL, there are no more matches.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Insert the found entry into the map.
|
|
//
|
|
NetMapInsertTail (
|
|
&FoundEntries,
|
|
(VOID *)CacheEntry,
|
|
(VOID *)&ArpService->ResolvedCacheTable
|
|
);
|
|
|
|
//
|
|
// Let the next search start from this cache entry.
|
|
//
|
|
StartEntry = &CacheEntry->List;
|
|
|
|
if (Refresh) {
|
|
//
|
|
// Refresh the DecayTime if needed.
|
|
//
|
|
CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
|
|
}
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
FoundCount = (UINT32) NetMapGetCount (&FoundEntries);
|
|
if (FoundCount == 0) {
|
|
Status = EFI_NOT_FOUND;
|
|
goto CLEAN_EXIT;
|
|
}
|
|
|
|
//
|
|
// Found the entry length, make sure its 8 bytes alignment.
|
|
//
|
|
FoundEntryLength = (((sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +
|
|
ArpService->SnpMode.HwAddressSize) + 3) & ~(0x3));
|
|
|
|
if (EntryLength != NULL) {
|
|
*EntryLength = FoundEntryLength;
|
|
}
|
|
|
|
if (EntryCount != NULL) {
|
|
//
|
|
// Return the found entry count.
|
|
//
|
|
*EntryCount = FoundCount;
|
|
}
|
|
|
|
if (Entries == NULL) {
|
|
goto CLEAN_EXIT;
|
|
}
|
|
|
|
//
|
|
// Allocate buffer to copy the found entries.
|
|
//
|
|
FindData = AllocatePool (FoundCount * FoundEntryLength);
|
|
if (FindData == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "ArpFindCacheEntry: Failed to allocate memory.\n"));
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto CLEAN_EXIT;
|
|
}
|
|
|
|
//
|
|
// Return the address to the user.
|
|
//
|
|
*Entries = FindData;
|
|
|
|
//
|
|
// Dump the entries.
|
|
//
|
|
while (!NetMapIsEmpty (&FoundEntries)) {
|
|
//
|
|
// Get a cache entry from the map.
|
|
//
|
|
CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);
|
|
|
|
//
|
|
// Set the fields in FindData.
|
|
//
|
|
FindData->Size = FoundEntryLength;
|
|
FindData->DenyFlag = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);
|
|
FindData->StaticFlag = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);
|
|
FindData->HwAddressType = ArpService->SnpMode.IfType;
|
|
FindData->SwAddressType = Instance->ConfigData.SwAddressType;
|
|
FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;
|
|
FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;
|
|
|
|
//
|
|
// Copy the software address.
|
|
//
|
|
CopyMem (
|
|
FindData + 1,
|
|
CacheEntry->Addresses[Protocol].AddressPtr,
|
|
FindData->SwAddressLength
|
|
);
|
|
|
|
//
|
|
// Copy the hardware address.
|
|
//
|
|
CopyMem (
|
|
(UINT8 *)(FindData + 1) + FindData->SwAddressLength,
|
|
CacheEntry->Addresses[Hardware].AddressPtr,
|
|
FindData->HwAddressLength
|
|
);
|
|
|
|
//
|
|
// Slip to the next FindData.
|
|
//
|
|
FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + FoundEntryLength);
|
|
}
|
|
|
|
CLEAN_EXIT:
|
|
|
|
NetMapClean (&FoundEntries);
|
|
|
|
return Status;
|
|
}
|
|
|