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