aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/NetworkPkg/ArpDxe/ArpMain.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/NetworkPkg/ArpDxe/ArpMain.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/NetworkPkg/ArpDxe/ArpMain.c')
-rw-r--r--roms/edk2/NetworkPkg/ArpDxe/ArpMain.c739
1 files changed, 739 insertions, 0 deletions
diff --git a/roms/edk2/NetworkPkg/ArpDxe/ArpMain.c b/roms/edk2/NetworkPkg/ArpDxe/ArpMain.c
new file mode 100644
index 000000000..6e8690a93
--- /dev/null
+++ b/roms/edk2/NetworkPkg/ArpDxe/ArpMain.c
@@ -0,0 +1,739 @@
+/** @file
+ Implementation of EFI Address Resolution Protocol (ARP) Protocol interface functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ArpImpl.h"
+
+
+/**
+ This function is used to assign a station address to the ARP cache for this instance
+ of the ARP driver.
+
+ Each ARP instance has one station address. The EFI_ARP_PROTOCOL driver will
+ respond to ARP requests that match this registered station address. A call to
+ this function with the ConfigData field set to NULL will reset this ARP instance.
+
+ Once a protocol type and station address have been assigned to this ARP instance,
+ all the following ARP functions will use this information. Attempting to change
+ the protocol type or station address to a configured ARP instance will result in errors.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+ @param ConfigData Pointer to the EFI_ARP_CONFIG_DATA structure.
+
+ @retval EFI_SUCCESS The new station address was successfully
+ registered.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL. SwAddressLength is zero when
+ ConfigData is not NULL. StationAddress is NULL
+ when ConfigData is not NULL.
+ @retval EFI_ACCESS_DENIED The SwAddressType, SwAddressLength, or
+ StationAddress is different from the one that is
+ already registered.
+ @retval EFI_OUT_OF_RESOURCES Storage for the new StationAddress could not be
+ allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+ArpConfigure (
+ IN EFI_ARP_PROTOCOL *This,
+ IN EFI_ARP_CONFIG_DATA *ConfigData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ ARP_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ConfigData != NULL) &&
+ ((ConfigData->SwAddressLength == 0) ||
+ (ConfigData->StationAddress == NULL) ||
+ (ConfigData->SwAddressType <= 1500))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Configure this instance, the ConfigData has already passed the basic checks.
+ //
+ Status = ArpConfigureInstance (Instance, ConfigData);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function is used to insert entries into the ARP cache.
+
+ ARP cache entries are typically inserted and updated by network protocol drivers
+ as network traffic is processed. Most ARP cache entries will time out and be
+ deleted if the network traffic stops. ARP cache entries that were inserted
+ by the Add() function may be static (will not time out) or dynamic (will time out).
+ Default ARP cache timeout values are not covered in most network protocol
+ specifications (although RFC 1122 comes pretty close) and will only be
+ discussed in general in this specification. The timeout values that are
+ used in the EFI Sample Implementation should be used only as a guideline.
+ Final product implementations of the EFI network stack should be tuned for
+ their expected network environments.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+ @param DenyFlag Set to TRUE if this entry is a deny entry. Set to
+ FALSE if this entry is a normal entry.
+ @param TargetSwAddress Pointer to a protocol address to add (or deny).
+ May be set to NULL if DenyFlag is TRUE.
+ @param TargetHwAddress Pointer to a hardware address to add (or deny).
+ May be set to NULL if DenyFlag is TRUE.
+ @param TimeoutValue Time in 100-ns units that this entry will remain
+ in the ARP cache. A value of zero means that the
+ entry is permanent. A nonzero value will override
+ the one given by Configure() if the entry to be
+ added is a dynamic entry.
+ @param Overwrite If TRUE, the matching cache entry will be
+ overwritten with the supplied parameters. If
+ FALSE, EFI_ACCESS_DENIED is returned if the
+ corresponding cache entry already exists.
+
+ @retval EFI_SUCCESS The entry has been added or updated.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL. DenyFlag is FALSE and
+ TargetHwAddress is NULL. DenyFlag is FALSE and
+ TargetSwAddress is NULL. TargetHwAddress is NULL
+ and TargetSwAddress is NULL. Both TargetSwAddress
+ and TargetHwAddress are not NULL when DenyFlag is
+ TRUE.
+ @retval EFI_OUT_OF_RESOURCES The new ARP cache entry could not be allocated.
+ @retval EFI_ACCESS_DENIED The ARP cache entry already exists and Overwrite
+ is not true.
+ @retval EFI_NOT_STARTED The ARP driver instance has not been configured.
+
+**/
+EFI_STATUS
+EFIAPI
+ArpAdd (
+ IN EFI_ARP_PROTOCOL *This,
+ IN BOOLEAN DenyFlag,
+ IN VOID *TargetSwAddress OPTIONAL,
+ IN VOID *TargetHwAddress OPTIONAL,
+ IN UINT32 TimeoutValue,
+ IN BOOLEAN Overwrite
+ )
+{
+ EFI_STATUS Status;
+ ARP_INSTANCE_DATA *Instance;
+ ARP_SERVICE_DATA *ArpService;
+ ARP_CACHE_ENTRY *CacheEntry;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ NET_ARP_ADDRESS MatchAddress[2];
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((!DenyFlag) && ((TargetHwAddress == NULL) || (TargetSwAddress == NULL))) ||
+ (DenyFlag && (TargetHwAddress != NULL) && (TargetSwAddress != NULL)) ||
+ ((TargetHwAddress == NULL) && (TargetSwAddress == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ Status = EFI_SUCCESS;
+ ArpService = Instance->ArpService;
+ SnpMode = &Instance->ArpService->SnpMode;
+
+ //
+ // Fill the hardware address part in the MatchAddress.
+ //
+ MatchAddress[Hardware].Type = SnpMode->IfType;
+ MatchAddress[Hardware].Length = (UINT8) SnpMode->HwAddressSize;
+ MatchAddress[Hardware].AddressPtr = TargetHwAddress;
+
+ //
+ // Fill the software address part in the MatchAddress.
+ //
+ MatchAddress[Protocol].Type = Instance->ConfigData.SwAddressType;
+ MatchAddress[Protocol].Length = Instance->ConfigData.SwAddressLength;
+ MatchAddress[Protocol].AddressPtr = TargetSwAddress;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // See whether the entry to add exists. Check the DeniedCacheTable first.
+ //
+ CacheEntry = ArpFindDeniedCacheEntry (
+ ArpService,
+ &MatchAddress[Protocol],
+ &MatchAddress[Hardware]
+ );
+
+ if (CacheEntry == NULL) {
+ //
+ // Check the ResolvedCacheTable
+ //
+ CacheEntry = ArpFindNextCacheEntryInTable (
+ &ArpService->ResolvedCacheTable,
+ NULL,
+ ByBoth,
+ &MatchAddress[Protocol],
+ &MatchAddress[Hardware]
+ );
+ }
+
+ if ((CacheEntry != NULL) && !Overwrite) {
+ //
+ // The entry to add exists, if not Overwrite, deny this add request.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto UNLOCK_EXIT;
+ }
+
+ if ((CacheEntry == NULL) && (TargetSwAddress != NULL)) {
+ //
+ // Check whether there are pending requests matching the entry to be added.
+ //
+ CacheEntry = ArpFindNextCacheEntryInTable (
+ &ArpService->PendingRequestTable,
+ NULL,
+ ByProtoAddress,
+ &MatchAddress[Protocol],
+ NULL
+ );
+ }
+
+ if (CacheEntry != NULL) {
+ //
+ // Remove it from the Table.
+ //
+ RemoveEntryList (&CacheEntry->List);
+ } else {
+ //
+ // It's a new entry, allocate memory for the entry.
+ //
+ CacheEntry = ArpAllocCacheEntry (Instance);
+
+ if (CacheEntry == NULL) {
+ DEBUG ((EFI_D_ERROR, "ArpAdd: Failed to allocate pool for CacheEntry.\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNLOCK_EXIT;
+ }
+ }
+
+ //
+ // Overwrite these parameters.
+ //
+ CacheEntry->DefaultDecayTime = TimeoutValue;
+ CacheEntry->DecayTime = TimeoutValue;
+
+ //
+ // Fill in the addresses.
+ //
+ ArpFillAddressInCacheEntry (
+ CacheEntry,
+ &MatchAddress[Hardware],
+ &MatchAddress[Protocol]
+ );
+
+ //
+ // Inform the user if there is any.
+ //
+ ArpAddressResolved (CacheEntry, NULL, NULL);
+
+ //
+ // Add this CacheEntry to the corresponding CacheTable.
+ //
+ if (DenyFlag) {
+ InsertHeadList (&ArpService->DeniedCacheTable, &CacheEntry->List);
+ } else {
+ InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);
+ }
+
+UNLOCK_EXIT:
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function searches the ARP cache for matching entries and allocates a buffer into
+ which those entries are copied.
+
+ The first part of the allocated buffer is EFI_ARP_FIND_DATA, following which
+ are protocol address pairs and hardware address pairs.
+ When finding a specific protocol address (BySwAddress is TRUE and AddressBuffer
+ is not NULL), the ARP cache timeout for the found entry is reset if Refresh is
+ set to TRUE. If the found ARP cache entry is a permanent entry, it is not
+ affected by Refresh.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+ @param BySwAddress Set to TRUE to look for matching software protocol
+ addresses. Set to FALSE to look for matching
+ hardware protocol addresses.
+ @param AddressBuffer Pointer to address buffer. Set to NULL to match
+ all addresses.
+ @param EntryLength The size of an entry in the entries buffer.
+ @param EntryCount The number of ARP cache entries that are found by
+ the specified criteria.
+ @param Entries Pointer to the buffer that will receive the ARP
+ cache entries.
+ @param Refresh Set to TRUE to refresh the timeout value of the
+ matching ARP cache entry.
+
+ @retval EFI_SUCCESS The requested ARP cache entries were copied into
+ the buffer.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL. Both EntryCount and EntryLength are
+ NULL, when Refresh is FALSE.
+ @retval EFI_NOT_FOUND No matching entries were found.
+ @retval EFI_NOT_STARTED The ARP driver instance has not been configured.
+
+**/
+EFI_STATUS
+EFIAPI
+ArpFind (
+ IN EFI_ARP_PROTOCOL *This,
+ 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_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) ||
+ (!Refresh && (EntryCount == NULL) && (EntryLength == NULL)) ||
+ ((Entries != NULL) && ((EntryLength == NULL) || (EntryCount == NULL)))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // All the check passed, find the cache entries now.
+ //
+ Status = ArpFindCacheEntry (
+ Instance,
+ BySwAddress,
+ AddressBuffer,
+ EntryLength,
+ EntryCount,
+ Entries,
+ Refresh
+ );
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function removes specified ARP cache entries.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+ @param BySwAddress Set to TRUE to delete matching protocol addresses.
+ Set to FALSE to delete matching hardware
+ addresses.
+ @param AddressBuffer Pointer to the address buffer that is used as a
+ key to look for the cache entry. Set to NULL to
+ delete all entries.
+
+ @retval EFI_SUCCESS The entry was removed from the ARP cache.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_FOUND The specified deletion key was not found.
+ @retval EFI_NOT_STARTED The ARP driver instance has not been configured.
+
+**/
+EFI_STATUS
+EFIAPI
+ArpDelete (
+ IN EFI_ARP_PROTOCOL *This,
+ IN BOOLEAN BySwAddress,
+ IN VOID *AddressBuffer OPTIONAL
+ )
+{
+ ARP_INSTANCE_DATA *Instance;
+ UINTN Count;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Delete the specified cache entries.
+ //
+ Count = ArpDeleteCacheEntry (Instance, BySwAddress, AddressBuffer, TRUE);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+
+/**
+ This function delete all dynamic entries from the ARP cache that match the specified
+ software protocol type.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The cache has been flushed.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_FOUND There are no matching dynamic cache entries.
+ @retval EFI_NOT_STARTED The ARP driver instance has not been configured.
+
+**/
+EFI_STATUS
+EFIAPI
+ArpFlush (
+ IN EFI_ARP_PROTOCOL *This
+ )
+{
+ ARP_INSTANCE_DATA *Instance;
+ UINTN Count;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Delete the dynamic entries from the cache table.
+ //
+ Count = ArpDeleteCacheEntry (Instance, FALSE, NULL, FALSE);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+
+/**
+ This function tries to resolve the TargetSwAddress and optionally returns a
+ TargetHwAddress if it already exists in the ARP cache.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+ @param TargetSwAddress Pointer to the protocol address to resolve.
+ @param ResolvedEvent Pointer to the event that will be signaled when
+ the address is resolved or some error occurs.
+ @param TargetHwAddress Pointer to the buffer for the resolved hardware
+ address in network byte order.
+
+ @retval EFI_SUCCESS The data is copied from the ARP cache into the
+ TargetHwAddress buffer.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL. TargetHwAddress is NULL.
+ @retval EFI_ACCESS_DENIED The requested address is not present in the normal
+ ARP cache but is present in the deny address list.
+ Outgoing traffic to that address is forbidden.
+ @retval EFI_NOT_STARTED The ARP driver instance has not been configured.
+ @retval EFI_NOT_READY The request has been started and is not finished.
+
+**/
+EFI_STATUS
+EFIAPI
+ArpRequest (
+ IN EFI_ARP_PROTOCOL *This,
+ IN VOID *TargetSwAddress OPTIONAL,
+ IN EFI_EVENT ResolvedEvent OPTIONAL,
+ OUT VOID *TargetHwAddress
+ )
+{
+ EFI_STATUS Status;
+ ARP_INSTANCE_DATA *Instance;
+ ARP_SERVICE_DATA *ArpService;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ ARP_CACHE_ENTRY *CacheEntry;
+ NET_ARP_ADDRESS HardwareAddress;
+ NET_ARP_ADDRESS ProtocolAddress;
+ USER_REQUEST_CONTEXT *RequestContext;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (TargetHwAddress == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ Status = EFI_SUCCESS;
+ ArpService = Instance->ArpService;
+ SnpMode = &ArpService->SnpMode;
+
+ if ((TargetSwAddress == NULL) ||
+ ((Instance->ConfigData.SwAddressType == IPV4_ETHER_PROTO_TYPE) &&
+ IP4_IS_LOCAL_BROADCAST (*((UINT32 *)TargetSwAddress)))) {
+ //
+ // Return the hardware broadcast address.
+ //
+ CopyMem (TargetHwAddress, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
+
+ goto SIGNAL_USER;
+ }
+
+ if ((Instance->ConfigData.SwAddressType == IPV4_ETHER_PROTO_TYPE) &&
+ IP4_IS_MULTICAST (NTOHL (*((UINT32 *)TargetSwAddress)))) {
+ //
+ // If the software address is an IPv4 multicast address, invoke Mnp to
+ // resolve the address.
+ //
+ Status = ArpService->Mnp->McastIpToMac (
+ ArpService->Mnp,
+ FALSE,
+ TargetSwAddress,
+ TargetHwAddress
+ );
+ goto SIGNAL_USER;
+ }
+
+ HardwareAddress.Type = SnpMode->IfType;
+ HardwareAddress.Length = (UINT8)SnpMode->HwAddressSize;
+ HardwareAddress.AddressPtr = NULL;
+
+ ProtocolAddress.Type = Instance->ConfigData.SwAddressType;
+ ProtocolAddress.Length = Instance->ConfigData.SwAddressLength;
+ ProtocolAddress.AddressPtr = TargetSwAddress;
+
+ //
+ // Initialize the TargetHwAddress to a zero address.
+ //
+ ZeroMem (TargetHwAddress, SnpMode->HwAddressSize);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Check whether the software address is in the denied table.
+ //
+ CacheEntry = ArpFindDeniedCacheEntry (ArpService, &ProtocolAddress, NULL);
+ if (CacheEntry != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto UNLOCK_EXIT;
+ }
+
+ //
+ // Check whether the software address is already resolved.
+ //
+ CacheEntry = ArpFindNextCacheEntryInTable (
+ &ArpService->ResolvedCacheTable,
+ NULL,
+ ByProtoAddress,
+ &ProtocolAddress,
+ NULL
+ );
+ if (CacheEntry != NULL) {
+ //
+ // Resolved, copy the address into the user buffer.
+ //
+ CopyMem (
+ TargetHwAddress,
+ CacheEntry->Addresses[Hardware].AddressPtr,
+ CacheEntry->Addresses[Hardware].Length
+ );
+
+ goto UNLOCK_EXIT;
+ }
+
+ if (ResolvedEvent == NULL) {
+ Status = EFI_NOT_READY;
+ goto UNLOCK_EXIT;
+ }
+
+ //
+ // Create a request context for this arp request.
+ //
+ RequestContext = AllocatePool (sizeof(USER_REQUEST_CONTEXT));
+ if (RequestContext == NULL) {
+ DEBUG ((EFI_D_ERROR, "ArpRequest: Allocate memory for RequestContext failed.\n"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNLOCK_EXIT;
+ }
+
+ RequestContext->Instance = Instance;
+ RequestContext->UserRequestEvent = ResolvedEvent;
+ RequestContext->UserHwAddrBuffer = TargetHwAddress;
+ InitializeListHead (&RequestContext->List);
+
+ //
+ // Check whether there is a same request.
+ //
+ CacheEntry = ArpFindNextCacheEntryInTable (
+ &ArpService->PendingRequestTable,
+ NULL,
+ ByProtoAddress,
+ &ProtocolAddress,
+ NULL
+ );
+ if (CacheEntry != NULL) {
+
+ CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;
+ CacheEntry->RetryCount = Instance->ConfigData.RetryCount;
+ } else {
+ //
+ // Allocate a cache entry for this request.
+ //
+ CacheEntry = ArpAllocCacheEntry (Instance);
+ if (CacheEntry == NULL) {
+ DEBUG ((EFI_D_ERROR, "ArpRequest: Allocate memory for CacheEntry failed.\n"));
+ FreePool (RequestContext);
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNLOCK_EXIT;
+ }
+
+ //
+ // Fill the software address.
+ //
+ ArpFillAddressInCacheEntry (CacheEntry, &HardwareAddress, &ProtocolAddress);
+
+ //
+ // Add this entry into the PendingRequestTable.
+ //
+ InsertTailList (&ArpService->PendingRequestTable, &CacheEntry->List);
+ }
+
+ //
+ // Link this request context into the cache entry.
+ //
+ InsertHeadList (&CacheEntry->UserRequestList, &RequestContext->List);
+
+ //
+ // Send out the ARP Request frame.
+ //
+ ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REQUEST);
+ Status = EFI_NOT_READY;
+
+UNLOCK_EXIT:
+
+ gBS->RestoreTPL (OldTpl);
+
+SIGNAL_USER:
+
+ if ((ResolvedEvent != NULL) && (Status == EFI_SUCCESS)) {
+ gBS->SignalEvent (ResolvedEvent);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of ResolvedEvent.
+ //
+ DispatchDpc ();
+ }
+
+ return Status;
+}
+
+
+/**
+ This function aborts the previous ARP request (identified by This, TargetSwAddress
+ and ResolvedEvent) that is issued by EFI_ARP_PROTOCOL.Request().
+
+ If the request is in the internal ARP request queue, the request is aborted
+ immediately and its ResolvedEvent is signaled. Only an asynchronous address
+ request needs to be canceled. If TargetSwAddress and ResolvedEvent are both
+ NULL, all the pending asynchronous requests that have been issued by This
+ instance will be cancelled and their corresponding events will be signaled.
+
+ @param This Pointer to the EFI_ARP_PROTOCOL instance.
+ @param TargetSwAddress Pointer to the protocol address in previous
+ request session.
+ @param ResolvedEvent Pointer to the event that is used as the
+ notification event in previous request session.
+
+ @retval EFI_SUCCESS The pending request session(s) is/are aborted and
+ corresponding event(s) is/are signaled.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL. TargetSwAddress is not NULL and
+ ResolvedEvent is NULL. TargetSwAddress is NULL and
+ ResolvedEvent is not NULL.
+ @retval EFI_NOT_STARTED The ARP driver instance has not been configured.
+ @retval EFI_NOT_FOUND The request is not issued by
+ EFI_ARP_PROTOCOL.Request().
+
+**/
+EFI_STATUS
+EFIAPI
+ArpCancel (
+ IN EFI_ARP_PROTOCOL *This,
+ IN VOID *TargetSwAddress OPTIONAL,
+ IN EFI_EVENT ResolvedEvent OPTIONAL
+ )
+{
+ ARP_INSTANCE_DATA *Instance;
+ UINTN Count;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) ||
+ ((TargetSwAddress != NULL) && (ResolvedEvent == NULL)) ||
+ ((TargetSwAddress == NULL) && (ResolvedEvent != NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Cancel the specified request.
+ //
+ Count = ArpCancelRequest (Instance, TargetSwAddress, ResolvedEvent);
+
+ //
+ // Dispatch the DPCs queued by the NotifyFunction of the events signaled
+ // by ArpCancelRequest.
+ //
+ DispatchDpc ();
+
+ gBS->RestoreTPL (OldTpl);
+
+ return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}