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/ArpDriver.c | 811 ++++++++++++++++++ NetworkPkg/ArpDxe/ArpDriver.h | 334 ++++++++ NetworkPkg/ArpDxe/ArpDxe.inf | 62 ++ NetworkPkg/ArpDxe/ArpDxe.uni | 18 + NetworkPkg/ArpDxe/ArpDxeExtra.uni | 14 + NetworkPkg/ArpDxe/ArpImpl.c | 1667 +++++++++++++++++++++++++++++++++++++ NetworkPkg/ArpDxe/ArpImpl.h | 770 +++++++++++++++++ NetworkPkg/ArpDxe/ArpMain.c | 739 ++++++++++++++++ NetworkPkg/ArpDxe/ComponentName.c | 219 +++++ 9 files changed, 4634 insertions(+) create mode 100644 NetworkPkg/ArpDxe/ArpDriver.c create mode 100644 NetworkPkg/ArpDxe/ArpDriver.h create mode 100644 NetworkPkg/ArpDxe/ArpDxe.inf create mode 100644 NetworkPkg/ArpDxe/ArpDxe.uni create mode 100644 NetworkPkg/ArpDxe/ArpDxeExtra.uni create mode 100644 NetworkPkg/ArpDxe/ArpImpl.c create mode 100644 NetworkPkg/ArpDxe/ArpImpl.h create mode 100644 NetworkPkg/ArpDxe/ArpMain.c create mode 100644 NetworkPkg/ArpDxe/ComponentName.c (limited to 'NetworkPkg/ArpDxe') diff --git a/NetworkPkg/ArpDxe/ArpDriver.c b/NetworkPkg/ArpDxe/ArpDriver.c new file mode 100644 index 0000000000..632d691d75 --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpDriver.c @@ -0,0 +1,811 @@ +/** @file + ARP driver functions. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "ArpDriver.h" +#include "ArpImpl.h" + +EFI_DRIVER_BINDING_PROTOCOL gArpDriverBinding = { + ArpDriverBindingSupported, + ArpDriverBindingStart, + ArpDriverBindingStop, + 0xa, + NULL, + NULL +}; + + +/** + Create and initialize the arp service context data. + + @param[in] ImageHandle The image handle representing the loaded driver + image. + @param[in] ControllerHandle The controller handle the driver binds to. + @param[in, out] ArpService Pointer to the buffer containing the arp service + context data. + + @retval EFI_SUCCESS The arp service context is initialized. + + @retval EFI_UNSUPPORTED The underlayer Snp mode type is not ethernet. + Failed to initialize the service context. + @retval other Failed to initialize the arp service context. + +**/ +EFI_STATUS +ArpCreateService ( + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle, + IN OUT ARP_SERVICE_DATA *ArpService + ) +{ + EFI_STATUS Status; + + ASSERT (ArpService != NULL); + + ArpService->Signature = ARP_SERVICE_DATA_SIGNATURE; + + // + // Init the lists. + // + InitializeListHead (&ArpService->ChildrenList); + InitializeListHead (&ArpService->PendingRequestTable); + InitializeListHead (&ArpService->DeniedCacheTable); + InitializeListHead (&ArpService->ResolvedCacheTable); + + // + // Init the servicebinding protocol members. + // + ArpService->ServiceBinding.CreateChild = ArpServiceBindingCreateChild; + ArpService->ServiceBinding.DestroyChild = ArpServiceBindingDestroyChild; + + // + // Save the handles. + // + ArpService->ImageHandle = ImageHandle; + ArpService->ControllerHandle = ControllerHandle; + + // + // Create a MNP child instance. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + ImageHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &ArpService->MnpChildHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the MNP protocol. + // + Status = gBS->OpenProtocol ( + ArpService->MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + (VOID **)&ArpService->Mnp, + ImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + // + // Get the underlayer Snp mode data. + // + Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode); + if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) { + // + // Only support the ethernet. + // + Status = EFI_UNSUPPORTED; + goto ERROR_EXIT; + } + + // + // Set the Mnp config parameters. + // + ArpService->MnpConfigData.ReceivedQueueTimeoutValue = 0; + ArpService->MnpConfigData.TransmitQueueTimeoutValue = 0; + ArpService->MnpConfigData.ProtocolTypeFilter = ARP_ETHER_PROTO_TYPE; + ArpService->MnpConfigData.EnableUnicastReceive = TRUE; + ArpService->MnpConfigData.EnableMulticastReceive = FALSE; + ArpService->MnpConfigData.EnableBroadcastReceive = TRUE; + ArpService->MnpConfigData.EnablePromiscuousReceive = FALSE; + ArpService->MnpConfigData.FlushQueuesOnReset = TRUE; + ArpService->MnpConfigData.EnableReceiveTimestamps = FALSE; + ArpService->MnpConfigData.DisableBackgroundPolling = FALSE; + + // + // Configure the Mnp child. + // + Status = ArpService->Mnp->Configure (ArpService->Mnp, &ArpService->MnpConfigData); + if (EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + // + // Create the event used in the RxToken. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ArpOnFrameRcvd, + ArpService, + &ArpService->RxToken.Event + ); + if (EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + // + // Create the Arp heartbeat timer. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL | EVT_TIMER, + TPL_CALLBACK, + ArpTimerHandler, + ArpService, + &ArpService->PeriodicTimer + ); + if (EFI_ERROR (Status)) { + goto ERROR_EXIT; + } + + // + // Start the heartbeat timer. + // + Status = gBS->SetTimer ( + ArpService->PeriodicTimer, + TimerPeriodic, + ARP_PERIODIC_TIMER_INTERVAL + ); + +ERROR_EXIT: + + return Status; +} + + +/** + Clean the arp service context data. + + @param[in, out] ArpService Pointer to the buffer containing the arp service + context data. + + @return None. + +**/ +VOID +ArpCleanService ( + IN OUT ARP_SERVICE_DATA *ArpService + ) +{ + NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE); + + if (ArpService->PeriodicTimer != NULL) { + // + // Cancle and close the PeriodicTimer. + // + gBS->SetTimer (ArpService->PeriodicTimer, TimerCancel, 0); + gBS->CloseEvent (ArpService->PeriodicTimer); + } + + if (ArpService->RxToken.Event != NULL) { + // + // Cancle the RxToken and close the event in the RxToken. + // + ArpService->Mnp->Cancel (ArpService->Mnp, NULL); + gBS->CloseEvent (ArpService->RxToken.Event); + } + + if (ArpService->Mnp != NULL) { + // + // Reset the Mnp child and close the Mnp protocol. + // + ArpService->Mnp->Configure (ArpService->Mnp, NULL); + gBS->CloseProtocol ( + ArpService->MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + ArpService->ImageHandle, + ArpService->ControllerHandle + ); + } + + if (ArpService->MnpChildHandle != NULL) { + // + // Destroy the mnp child. + // + NetLibDestroyServiceChild( + ArpService->ControllerHandle, + ArpService->ImageHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + ArpService->MnpChildHandle + ); + } +} + +/** + Callback function which provided by user to remove one node in NetDestroyLinkList process. + + @param[in] Entry The entry to be removed. + @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList. + + @retval EFI_SUCCESS The entry has been removed successfully. + @retval Others Fail to remove the entry. + +**/ +EFI_STATUS +EFIAPI +ArpDestroyChildEntryInHandleBuffer ( + IN LIST_ENTRY *Entry, + IN VOID *Context + ) +{ + ARP_INSTANCE_DATA *Instance; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + + if (Entry == NULL || Context == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = NET_LIST_USER_STRUCT_S (Entry, ARP_INSTANCE_DATA, List, ARP_INSTANCE_DATA_SIGNATURE); + ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context; + + return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle); +} + +/** + Tests to see if this driver supports a given controller. + + If a child device is provided, it further tests to see if this driver supports + creating a handle for the specified child device. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + This parameter is ignored by device drivers, + and is optional for bus drivers. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver + specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed + by the driver specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by + a different driver or an application that + requires exclusive acces. Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the + driver specified by This. + +**/ +EFI_STATUS +EFIAPI +ArpDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // Test to see if Arp SB is already installed. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiArpServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (Status == EFI_SUCCESS) { + return EFI_ALREADY_STARTED; + } + + // + // Test to see if MNP SB is installed. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + return Status; +} + + +/** + Start this driver on ControllerHandle. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been + moved into this common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior + will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally + aligned EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified + by This must have been called with the same calling parameters, and Supported() + must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + This parameter is ignored by device drivers, + and is optional for bus drivers. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error. + Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of + resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +ArpDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + ARP_SERVICE_DATA *ArpService; + + // + // Allocate a zero pool for ArpService. + // + ArpService = AllocateZeroPool (sizeof(ARP_SERVICE_DATA)); + if (ArpService == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Initialize the arp service context data. + // + Status = ArpCreateService (This->DriverBindingHandle, ControllerHandle, ArpService); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + // + // Install the ARP service binding protocol. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiArpServiceBindingProtocolGuid, + &ArpService->ServiceBinding, + NULL + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + // + // OK, start to receive arp packets from Mnp. + // + Status = ArpService->Mnp->Receive (ArpService->Mnp, &ArpService->RxToken); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + return Status; + +ERROR: + + // + // On error, clean the arp service context data, and free the memory allocated. + // + ArpCleanService (ArpService); + FreePool (ArpService); + + return Status; +} + + +/** + Stop this driver on ControllerHandle. + + Release the control of this controller and remove the IScsi functions. The Stop() + function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior + will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + Not used. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0.Not used. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +ArpDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_HANDLE NicHandle; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + ARP_SERVICE_DATA *ArpService; + LIST_ENTRY *List; + + // + // Get the NicHandle which the arp servicebinding is installed on. + // + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid); + if (NicHandle == NULL) { + return EFI_SUCCESS; + } + + // + // Try to get the arp servicebinding protocol on the NicHandle. + // + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiArpServiceBindingProtocolGuid, + (VOID **)&ServiceBinding, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ArpDriverBindingStop: Open ArpSb failed, %r.\n", Status)); + return EFI_DEVICE_ERROR; + } + + ArpService = ARP_SERVICE_DATA_FROM_THIS (ServiceBinding); + + if (NumberOfChildren != 0) { + // + // NumberOfChildren is not zero, destroy all the ARP children instances. + // + List = &ArpService->ChildrenList; + Status = NetDestroyLinkList ( + List, + ArpDestroyChildEntryInHandleBuffer, + ServiceBinding, + NULL + ); + ASSERT (IsListEmpty (&ArpService->PendingRequestTable)); + ASSERT (IsListEmpty (&ArpService->DeniedCacheTable)); + ASSERT (IsListEmpty (&ArpService->ResolvedCacheTable)); + } else if (IsListEmpty (&ArpService->ChildrenList)) { + // + // Uninstall the ARP ServiceBinding protocol. + // + gBS->UninstallMultipleProtocolInterfaces ( + NicHandle, + &gEfiArpServiceBindingProtocolGuid, + &ArpService->ServiceBinding, + NULL + ); + + // + // Clean the arp servicebinding context data and free the memory allocated. + // + ArpCleanService (ArpService); + + FreePool (ArpService); + } + + return EFI_SUCCESS; +} + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned + in ChildHandle. If ChildHandle is not a pointer to NULL, then the protocol + installs on the existing ChildHandle. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing + UEFI handle, then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +EFI_STATUS +EFIAPI +ArpServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle + ) +{ + EFI_STATUS Status; + ARP_SERVICE_DATA *ArpService; + ARP_INSTANCE_DATA *Instance; + VOID *Mnp; + EFI_TPL OldTpl; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + ArpService = ARP_SERVICE_DATA_FROM_THIS (This); + + // + // Allocate memory for the instance context data. + // + Instance = AllocateZeroPool (sizeof(ARP_INSTANCE_DATA)); + if (Instance == NULL) { + DEBUG ((EFI_D_ERROR, "ArpSBCreateChild: Failed to allocate memory for Instance.\n")); + + return EFI_OUT_OF_RESOURCES; + } + + // + // Init the instance context data. + // + ArpInitInstance (ArpService, Instance); + + // + // Install the ARP protocol onto the ChildHandle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiArpProtocolGuid, + (VOID *)&Instance->ArpProto, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ArpSBCreateChild: faild to install ARP protocol, %r.\n", Status)); + + FreePool (Instance); + return Status; + } + + // + // Save the ChildHandle. + // + Instance->Handle = *ChildHandle; + + // + // Open the Managed Network protocol BY_CHILD. + // + Status = gBS->OpenProtocol ( + ArpService->MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + (VOID **) &Mnp, + gArpDriverBinding.DriverBindingHandle, + Instance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Insert the instance into children list managed by the arp service context data. + // + InsertTailList (&ArpService->ChildrenList, &Instance->List); + ArpService->ChildrenNumber++; + + gBS->RestoreTPL (OldTpl); + +ERROR: + + if (EFI_ERROR (Status)) { + + gBS->CloseProtocol ( + ArpService->MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + gArpDriverBinding.DriverBindingHandle, + Instance->Handle + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Instance->Handle, + &gEfiArpProtocolGuid, + &Instance->ArpProto, + NULL + ); + + // + // Free the allocated memory. + // + FreePool (Instance); + } + + return Status; +} + + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is + being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +EFI_STATUS +EFIAPI +ArpServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ) +{ + EFI_STATUS Status; + ARP_SERVICE_DATA *ArpService; + ARP_INSTANCE_DATA *Instance; + EFI_ARP_PROTOCOL *Arp; + EFI_TPL OldTpl; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + ArpService = ARP_SERVICE_DATA_FROM_THIS (This); + + // + // Get the arp protocol. + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiArpProtocolGuid, + (VOID **)&Arp, + ArpService->ImageHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Instance = ARP_INSTANCE_DATA_FROM_THIS (Arp); + + if (Instance->InDestroy) { + return EFI_SUCCESS; + } + + // + // Use the InDestroy as a flag to avoid re-entrance. + // + Instance->InDestroy = TRUE; + + // + // Close the Managed Network protocol. + // + gBS->CloseProtocol ( + ArpService->MnpChildHandle, + &gEfiManagedNetworkProtocolGuid, + gArpDriverBinding.DriverBindingHandle, + ChildHandle + ); + + // + // Uninstall the ARP protocol. + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiArpProtocolGuid, + &Instance->ArpProto, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ArpSBDestroyChild: Failed to uninstall the arp protocol, %r.\n", + Status)); + + Instance->InDestroy = FALSE; + return Status; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (Instance->Configured) { + // + // Delete the related cache entry. + // + ArpDeleteCacheEntry (Instance, FALSE, NULL, TRUE); + + // + // Reset the instance configuration. + // + ArpConfigureInstance (Instance, NULL); + } + + // + // Remove this instance from the ChildrenList. + // + RemoveEntryList (&Instance->List); + ArpService->ChildrenNumber--; + + gBS->RestoreTPL (OldTpl); + + FreePool (Instance); + + return Status; +} + +/** + The entry point for Arp driver which installs the driver binding and component name + protocol on its ImageHandle. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_SUCCESS if the driver binding and component name protocols + are successfully + @retval Others Failed to install the protocols. + +**/ +EFI_STATUS +EFIAPI +ArpDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gArpDriverBinding, + ImageHandle, + &gArpComponentName, + &gArpComponentName2 + ); +} + diff --git a/NetworkPkg/ArpDxe/ArpDriver.h b/NetworkPkg/ArpDxe/ArpDriver.h new file mode 100644 index 0000000000..0b5b06ee37 --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpDriver.h @@ -0,0 +1,334 @@ +/** @file + ARP driver header file. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ARP_DRIVER_H_ +#define _ARP_DRIVER_H_ + + +#include + +#include +#include +#include + +#include +#include +#include +#include + + +// +// Global variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gArpDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gArpComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gArpComponentName2; + +// +// Function prototypes for the Drivr Binding Protocol +// +/** + Tests to see if this driver supports a given controller. + + If a child device is provided, it further tests to see if this driver supports + creating a handle for the specified child device. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + This parameter is ignored by device drivers, + and is optional for bus drivers. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver + specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed + by the driver specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by + a different driver or an application that + requires exclusive acces. Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the + driver specified by This. + +**/ +EFI_STATUS +EFIAPI +ArpDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been + moved into this common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior + will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally + aligned EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified + by This must have been called with the same calling parameters, and Supported() + must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. + This parameter is ignored by device drivers, + and is optional for bus drivers. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error. + Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of + resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +ArpDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stop this driver on ControllerHandle. + + Release the control of this controller and remove the IScsi functions. The Stop() + function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior + will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + Not used. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0.Not used. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +ArpDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned + in ChildHandle. If ChildHandle is not a pointer to NULL, then the protocol + installs on the existing ChildHandle. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing + UEFI handle, then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER ChildHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create + the child + @retval other The child handle was not created + +**/ +EFI_STATUS +EFIAPI +ArpServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle + ); + +/** + Destroys a child handle with a protocol installed on it. + + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param ChildHandle Handle of the child to destroy + + @retval EFI_SUCCES The protocol was removed from ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is + being removed. + @retval EFI_INVALID_PARAMETER Child handle is NULL. + @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle + because its services are being used. + @retval other The child handle was not destroyed + +**/ +EFI_STATUS +EFIAPI +ArpServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); + + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +ArpComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +ArpComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +#endif + diff --git a/NetworkPkg/ArpDxe/ArpDxe.inf b/NetworkPkg/ArpDxe/ArpDxe.inf new file mode 100644 index 0000000000..78344edf90 --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpDxe.inf @@ -0,0 +1,62 @@ +## @file +# This module produces EFI ARP Protocol and EFI ARP Service Binding Protocol. +# +# This module produces EFI ARP Protocol upon EFI MNP Protocol, to provide a generic +# implementation of the Address Resolution Protocol that is described in RFCs 826 +# and 1122. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArpDxe + MODULE_UNI_FILE = ArpDxe.uni + FILE_GUID = 529D3F93-E8E9-4e73-B1E1-BDF6A9D50113 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = ArpDriverEntryPoint + UNLOAD_IMAGE = NetLibDefaultUnload +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gArpDriverBinding +# COMPONENT_NAME = gArpComponentName +# COMPONENT_NAME2 = gArpComponentName2 +# + +[Sources] + ArpMain.c + ArpDriver.h + ComponentName.c + ArpImpl.h + ArpImpl.c + ArpDriver.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + NetLib + DpcLib + +[Protocols] + gEfiArpServiceBindingProtocolGuid ## BY_START + gEfiManagedNetworkServiceBindingProtocolGuid ## TO_START + gEfiArpProtocolGuid ## BY_START + gEfiManagedNetworkProtocolGuid ## TO_START + +[UserExtensions.TianoCore."ExtraFiles"] + ArpDxeExtra.uni diff --git a/NetworkPkg/ArpDxe/ArpDxe.uni b/NetworkPkg/ArpDxe/ArpDxe.uni new file mode 100644 index 0000000000..f72063dd43 --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpDxe.uni @@ -0,0 +1,18 @@ +// /** @file +// This module produces EFI ARP Protocol and EFI ARP Service Binding Protocol. +// +// This module produces EFI ARP Protocol upon EFI MNP Protocol, to provide a generic +// implementation of the Address Resolution Protocol that is described in RFCs 826 +// and 1122. +// +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "EFI Address Resolution Protocol" + +#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI ARP Protocol using the EFI MNP Protocol to provide a generic implementation of the Address Resolution Protocol that is described in RFCs 826 and 1122." + diff --git a/NetworkPkg/ArpDxe/ArpDxeExtra.uni b/NetworkPkg/ArpDxe/ArpDxeExtra.uni new file mode 100644 index 0000000000..be612d002e --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// ArpDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"ARP DXE Driver" + + diff --git a/NetworkPkg/ArpDxe/ArpImpl.c b/NetworkPkg/ArpDxe/ArpImpl.c new file mode 100644 index 0000000000..0e9ef103ef --- /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; +} + diff --git a/NetworkPkg/ArpDxe/ArpImpl.h b/NetworkPkg/ArpDxe/ArpImpl.h new file mode 100644 index 0000000000..47eedc1cb6 --- /dev/null +++ b/NetworkPkg/ArpDxe/ArpImpl.h @@ -0,0 +1,770 @@ +/** @file + EFI Address Resolution Protocol (ARP) Protocol interface header file. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ARP_IMPL_H_ +#define _ARP_IMPL_H_ + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Ethernet protocol type definitions. +// +#define ARP_ETHER_PROTO_TYPE 0x0806 +#define IPV4_ETHER_PROTO_TYPE 0x0800 +#define IPV6_ETHER_PROTO_TYPE 0x86DD + +// +// ARP opcode definitions. +// +#define ARP_OPCODE_REQUEST 0x0001 +#define ARP_OPCODE_REPLY 0x0002 + +// +// ARP timeout, retry count and interval definitions. +// +#define ARP_DEFAULT_TIMEOUT_VALUE (400 * TICKS_PER_SECOND) +#define ARP_DEFAULT_RETRY_COUNT 2 +#define ARP_DEFAULT_RETRY_INTERVAL (5 * TICKS_PER_MS) +#define ARP_PERIODIC_TIMER_INTERVAL (500 * TICKS_PER_MS) + +// +// ARP packet head definition. +// +#pragma pack(1) +typedef struct { + UINT16 HwType; + UINT16 ProtoType; + UINT8 HwAddrLen; + UINT8 ProtoAddrLen; + UINT16 OpCode; +} ARP_HEAD; +#pragma pack() + +// +// ARP Address definition for internal use. +// +typedef struct { + UINT8 *SenderHwAddr; + UINT8 *SenderProtoAddr; + UINT8 *TargetHwAddr; + UINT8 *TargetProtoAddr; +} ARP_ADDRESS; + +#define MATCH_SW_ADDRESS 0x1 +#define MATCH_HW_ADDRESS 0x2 + +// +// Enumeration for the search type. A search type is specified as the keyword to find +// a cache entry in the cache table. +// +typedef enum { + ByNone = 0, + ByProtoAddress = MATCH_SW_ADDRESS, + ByHwAddress = MATCH_HW_ADDRESS, + ByBoth = MATCH_SW_ADDRESS | MATCH_HW_ADDRESS +} FIND_OPTYPE; + +#define ARP_INSTANCE_DATA_SIGNATURE SIGNATURE_32('A', 'R', 'P', 'I') + +/** + Returns a pointer to the ARP_INSTANCE_DATA structure from the input a. + + If the signatures matches, then a pointer to the data structure that contains + a specified field of that data structure is returned. + + @param a Pointer to the field specified by ArpProto within a data + structure of type ARP_INSTANCE_DATA. + +**/ +#define ARP_INSTANCE_DATA_FROM_THIS(a) \ + CR ( \ + (a), \ + ARP_INSTANCE_DATA, \ + ArpProto, \ + ARP_INSTANCE_DATA_SIGNATURE \ + ) + +typedef struct _ARP_SERVICE_DATA ARP_SERVICE_DATA; + +// +// ARP instance context data structure. +// +typedef struct { + UINT32 Signature; + ARP_SERVICE_DATA *ArpService; + EFI_HANDLE Handle; + EFI_ARP_PROTOCOL ArpProto; + LIST_ENTRY List; + EFI_ARP_CONFIG_DATA ConfigData; + BOOLEAN Configured; + BOOLEAN InDestroy; +} ARP_INSTANCE_DATA; + +#define ARP_SERVICE_DATA_SIGNATURE SIGNATURE_32('A', 'R', 'P', 'S') + +/** + Returns a pointer to the ARP_SERVICE_DATA structure from the input a. + + If the signatures matches, then a pointer to the data structure that contains + a specified field of that data structure is returned. + + @param a Pointer to the field specified by ServiceBinding within + a data structure of type ARP_SERVICE_DATA. + +**/ +#define ARP_SERVICE_DATA_FROM_THIS(a) \ + CR ( \ + (a), \ + ARP_SERVICE_DATA, \ + ServiceBinding, \ + ARP_SERVICE_DATA_SIGNATURE \ + ) + +// +// ARP service data structure. +// +struct _ARP_SERVICE_DATA { + UINT32 Signature; + EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; + + EFI_HANDLE MnpChildHandle; + EFI_HANDLE ImageHandle; + EFI_HANDLE ControllerHandle; + + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData; + EFI_MANAGED_NETWORK_COMPLETION_TOKEN RxToken; + + EFI_SIMPLE_NETWORK_MODE SnpMode; + + UINTN ChildrenNumber; + LIST_ENTRY ChildrenList; + + LIST_ENTRY PendingRequestTable; + LIST_ENTRY DeniedCacheTable; + LIST_ENTRY ResolvedCacheTable; + + EFI_EVENT PeriodicTimer; +}; + +// +// User request context structure. +// +typedef struct { + LIST_ENTRY List; + ARP_INSTANCE_DATA *Instance; + EFI_EVENT UserRequestEvent; + VOID *UserHwAddrBuffer; +} USER_REQUEST_CONTEXT; + +#define ARP_MAX_PROTOCOL_ADDRESS_LEN sizeof(EFI_IP_ADDRESS) +#define ARP_MAX_HARDWARE_ADDRESS_LEN sizeof(EFI_MAC_ADDRESS) + +typedef union { + UINT8 ProtoAddress[ARP_MAX_PROTOCOL_ADDRESS_LEN]; + UINT8 HwAddress[ARP_MAX_HARDWARE_ADDRESS_LEN]; +} NET_ARP_ADDRESS_UNION; + +// +// ARP address structure in an ARP packet. +// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 *AddressPtr; + NET_ARP_ADDRESS_UNION Buffer; +} NET_ARP_ADDRESS; + +// +// Enumeration for ARP address type. +// +typedef enum { + Hardware, + Protocol +} ARP_ADDRESS_TYPE; + +// +// ARP cache entry definition. +// +typedef struct { + LIST_ENTRY List; + + UINT32 RetryCount; + UINT32 DefaultDecayTime; + UINT32 DecayTime; + UINT32 NextRetryTime; + + NET_ARP_ADDRESS Addresses[2]; + + LIST_ENTRY UserRequestList; +} ARP_CACHE_ENTRY; + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 TargeSwAddress and ResolveEvent 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +#endif diff --git a/NetworkPkg/ArpDxe/ArpMain.c b/NetworkPkg/ArpDxe/ArpMain.c new file mode 100644 index 0000000000..f06121fed4 --- /dev/null +++ b/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.
+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 DeinedCacheTable 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 Overwirte, 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 TargetHwAddrss 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 TargeSwAddress and ResolveEvent 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 ArpCancleRequest. + // + DispatchDpc (); + + gBS->RestoreTPL (OldTpl); + + return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS; +} diff --git a/NetworkPkg/ArpDxe/ComponentName.c b/NetworkPkg/ArpDxe/ComponentName.c new file mode 100644 index 0000000000..bcee1e1444 --- /dev/null +++ b/NetworkPkg/ArpDxe/ComponentName.c @@ -0,0 +1,219 @@ +/** @file + UEFI Component Name(2) protocol implementation for ArpDxe driver. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "ArpDriver.h" + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gArpComponentName = { + ArpComponentNameGetDriverName, + ArpComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gArpComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ArpComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ArpComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mArpDriverNameTable[] = { + { "eng;en", L"ARP Network Service Driver" }, + { NULL, NULL } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mArpControllerNameTable[] = { + { "eng;en", L"ARP Controller" }, + { NULL, NULL } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +ArpComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mArpDriverNameTable, + DriverName, + (BOOLEAN)(This == &gArpComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +ArpComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_ARP_PROTOCOL *Arp; + + // + // Only provide names for child handles. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver produced ChildHandle + // + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + &gEfiManagedNetworkProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Retrieve an instance of a produced protocol from ChildHandle + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiArpProtocolGuid, + (VOID **)&Arp, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mArpControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gArpComponentName) + ); +} -- cgit