From 4542f8b8135f1f1ee5654e25139be9769e139ddd Mon Sep 17 00:00:00 2001 From: Liming Gao Date: Wed, 15 May 2019 20:02:18 +0800 Subject: NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg Signed-off-by: Liming Gao Cc: Siyuan Fu Cc: Jiaxin Wu Reviewed-by: Jiaxin Wu Reviewed-by: Siyuan Fu --- NetworkPkg/ArpDxe/ArpImpl.c | 1667 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1667 insertions(+) create mode 100644 NetworkPkg/ArpDxe/ArpImpl.c (limited to 'NetworkPkg/ArpDxe/ArpImpl.c') diff --git a/NetworkPkg/ArpDxe/ArpImpl.c b/NetworkPkg/ArpDxe/ArpImpl.c new file mode 100644 index 0000000..0e9ef10 --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpImpl.c @@ -0,0 +1,1667 @@ +/** @file + The implementation of the ARP protocol. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 + // 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; +} + -- cgit v1.1