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/Udp4Dxe/ComponentName.c | 429 ++++++++ NetworkPkg/Udp4Dxe/Udp4Driver.c | 584 +++++++++++ NetworkPkg/Udp4Dxe/Udp4Driver.h | 148 +++ NetworkPkg/Udp4Dxe/Udp4Dxe.inf | 64 ++ NetworkPkg/Udp4Dxe/Udp4Dxe.uni | 17 + NetworkPkg/Udp4Dxe/Udp4DxeExtra.uni | 14 + NetworkPkg/Udp4Dxe/Udp4Impl.c | 1908 +++++++++++++++++++++++++++++++++++ NetworkPkg/Udp4Dxe/Udp4Impl.h | 689 +++++++++++++ NetworkPkg/Udp4Dxe/Udp4Main.c | 902 +++++++++++++++++ 9 files changed, 4755 insertions(+) create mode 100644 NetworkPkg/Udp4Dxe/ComponentName.c create mode 100644 NetworkPkg/Udp4Dxe/Udp4Driver.c create mode 100644 NetworkPkg/Udp4Dxe/Udp4Driver.h create mode 100644 NetworkPkg/Udp4Dxe/Udp4Dxe.inf create mode 100644 NetworkPkg/Udp4Dxe/Udp4Dxe.uni create mode 100644 NetworkPkg/Udp4Dxe/Udp4DxeExtra.uni create mode 100644 NetworkPkg/Udp4Dxe/Udp4Impl.c create mode 100644 NetworkPkg/Udp4Dxe/Udp4Impl.h create mode 100644 NetworkPkg/Udp4Dxe/Udp4Main.c (limited to 'NetworkPkg/Udp4Dxe') diff --git a/NetworkPkg/Udp4Dxe/ComponentName.c b/NetworkPkg/Udp4Dxe/ComponentName.c new file mode 100644 index 0000000000..41bd834c6d --- /dev/null +++ b/NetworkPkg/Udp4Dxe/ComponentName.c @@ -0,0 +1,429 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Udp4Impl.h" + +// +// 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 +UdpComponentNameGetDriverName ( + 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 +UdpComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName = { + UdpComponentNameGetDriverName, + UdpComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdp4ComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UdpComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UdpComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdpDriverNameTable[] = { + { + "eng;en", + L"UDP Network Service Driver" + }, + { + NULL, + NULL + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gUdpControllerNameTable = 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 +UdpComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mUdpDriverNameTable, + DriverName, + (BOOLEAN)(This == &gUdp4ComponentName) + ); +} + +/** + Update the component name for the Udp4 child handle. + + @param Udp4[in] A pointer to the EFI_UDP4_PROTOCOL. + + + @retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully. + @retval EFI_INVALID_PARAMETER The input parameter is invalid. + +**/ +EFI_STATUS +UpdateName ( + EFI_UDP4_PROTOCOL *Udp4 + ) +{ + EFI_STATUS Status; + CHAR16 HandleName[64]; + EFI_UDP4_CONFIG_DATA Udp4ConfigData; + + if (Udp4 == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format the child name into the string buffer as: + // UDPv4 (SrcPort=59, DestPort=60) + // + Status = Udp4->GetModeData (Udp4, &Udp4ConfigData, NULL, NULL, NULL); + if (!EFI_ERROR (Status)) { + UnicodeSPrint (HandleName, sizeof (HandleName), + L"UDPv4 (SrcPort=%d, DestPort=%d)", + Udp4ConfigData.StationPort, + Udp4ConfigData.RemotePort + ); + } else if (Status == EFI_NOT_STARTED) { + UnicodeSPrint ( + HandleName, + sizeof (HandleName), + L"UDPv4 (Not started)" + ); + } else { + return Status; + } + + if (gUdpControllerNameTable != NULL) { + FreeUnicodeStringTable (gUdpControllerNameTable); + gUdpControllerNameTable = NULL; + } + + Status = AddUnicodeString2 ( + "eng", + gUdp4ComponentName.SupportedLanguages, + &gUdpControllerNameTable, + HandleName, + TRUE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return AddUnicodeString2 ( + "en", + gUdp4ComponentName2.SupportedLanguages, + &gUdpControllerNameTable, + HandleName, + FALSE + ); +} + +/** + 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 +UdpComponentNameGetControllerName ( + 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_UDP4_PROTOCOL *Udp4; + + // + // Only provide names for child handles. + // + if (ChildHandle == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver produced ChildHandle + // + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + &gEfiIp4ProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Retrieve an instance of a produced protocol from ChildHandle + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiUdp4ProtocolGuid, + (VOID **)&Udp4, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update the component name for this child handle. + // + Status = UpdateName (Udp4); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + gUdpControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gUdp4ComponentName) + ); +} + diff --git a/NetworkPkg/Udp4Dxe/Udp4Driver.c b/NetworkPkg/Udp4Dxe/Udp4Driver.c new file mode 100644 index 0000000000..63b103b8ef --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Driver.c @@ -0,0 +1,584 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Udp4Impl.h" + +EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = { + Udp4DriverBindingSupported, + Udp4DriverBindingStart, + Udp4DriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding = { + Udp4ServiceBindingCreateChild, + Udp4ServiceBindingDestroyChild +}; + +/** + 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 +Udp4DestroyChildEntryInHandleBuffer ( + IN LIST_ENTRY *Entry, + IN VOID *Context + ) +{ + UDP4_INSTANCE_DATA *Instance; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + UINTN NumberOfChildren; + EFI_HANDLE *ChildHandleBuffer; + + if (Entry == NULL || Context == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = NET_LIST_USER_STRUCT_S (Entry, UDP4_INSTANCE_DATA, Link, UDP4_INSTANCE_DATA_SIGNATURE); + ServiceBinding = ((UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding; + NumberOfChildren = ((UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren; + ChildHandleBuffer = ((UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer; + + if (!NetIsInHandleBuffer (Instance->ChildHandle, NumberOfChildren, ChildHandleBuffer)) { + return EFI_SUCCESS; + } + + return ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle); +} + + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +Udp4DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // Test for the Udp4ServiceBinding Protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + // + // Test for the Ip4 Protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiIp4ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + return Status; +} + + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +Udp4DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + UDP4_SERVICE_DATA *Udp4Service; + + // + // Allocate Private Context Data Structure. + // + Udp4Service = AllocatePool (sizeof (UDP4_SERVICE_DATA)); + if (Udp4Service == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Udp4CreateService (Udp4Service, This->DriverBindingHandle, ControllerHandle); + if (EFI_ERROR (Status)) { + FreePool (Udp4Service); + return Status; + } + + // + // Install the Udp4ServiceBindingProtocol on the ControllerHandle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + &Udp4Service->ServiceBinding, + NULL + ); + if (EFI_ERROR (Status)) { + Udp4CleanService (Udp4Service); + FreePool (Udp4Service); + } + + return Status; +} + + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +Udp4DriverBindingStop ( + 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; + UDP4_SERVICE_DATA *Udp4Service; + UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; + LIST_ENTRY *List; + + // + // Find the NicHandle where UDP4 ServiceBinding Protocol is installed. + // + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid); + if (NicHandle == NULL) { + return EFI_SUCCESS; + } + + // + // Retrieve the UDP4 ServiceBinding Protocol. + // + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + NicHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (ServiceBinding); + if (NumberOfChildren != 0) { + // + // NumberOfChildren is not zero, destroy the children instances in ChildHandleBuffer. + // + List = &Udp4Service->ChildrenList; + Context.ServiceBinding = ServiceBinding; + Context.NumberOfChildren = NumberOfChildren; + Context.ChildHandleBuffer = ChildHandleBuffer; + Status = NetDestroyLinkList ( + List, + Udp4DestroyChildEntryInHandleBuffer, + &Context, + NULL + ); + } else { + gBS->UninstallMultipleProtocolInterfaces ( + NicHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + &Udp4Service->ServiceBinding, + NULL + ); + + Udp4CleanService (Udp4Service); + + if (gUdpControllerNameTable != NULL) { + FreeUnicodeStringTable (gUdpControllerNameTable); + gUdpControllerNameTable = NULL; + } + FreePool (Udp4Service); + } + + return Status; +} + + +/** + 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[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] 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 +Udp4ServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle + ) +{ + EFI_STATUS Status; + UDP4_SERVICE_DATA *Udp4Service; + UDP4_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + VOID *Ip4; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This); + + // + // Allocate the instance private data structure. + // + Instance = AllocateZeroPool (sizeof (UDP4_INSTANCE_DATA)); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Udp4InitInstance (Udp4Service, Instance); + + // + // Add an IpInfo for this instance. + // + Instance->IpInfo = IpIoAddIp (Udp4Service->IpIo); + if (Instance->IpInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Install the Udp4Protocol for this instance. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiUdp4ProtocolGuid, + &Instance->Udp4Proto, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Instance->ChildHandle = *ChildHandle; + + // + // Open the default Ip4 protocol in the IP_IO BY_CHILD. + // + Status = gBS->OpenProtocol ( + Udp4Service->IpIo->ChildHandle, + &gEfiIp4ProtocolGuid, + (VOID **) &Ip4, + gUdp4DriverBinding.DriverBindingHandle, + Instance->ChildHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Open this instance's Ip4 protocol in the IpInfo BY_CHILD. + // + Status = gBS->OpenProtocol ( + Instance->IpInfo->ChildHandle, + &gEfiIp4ProtocolGuid, + (VOID **) &Ip4, + gUdp4DriverBinding.DriverBindingHandle, + Instance->ChildHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Link this instance into the service context data and increase the ChildrenNumber. + // + InsertTailList (&Udp4Service->ChildrenList, &Instance->Link); + Udp4Service->ChildrenNumber++; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +ON_ERROR: + + if (Instance->ChildHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + Instance->ChildHandle, + &gEfiUdp4ProtocolGuid, + &Instance->Udp4Proto, + NULL + ); + } + + if (Instance->IpInfo != NULL) { + IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo); + } + + Udp4CleanInstance (Instance); + + 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[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] 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 +Udp4ServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ) +{ + EFI_STATUS Status; + UDP4_SERVICE_DATA *Udp4Service; + EFI_UDP4_PROTOCOL *Udp4Proto; + UDP4_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This); + + // + // Try to get the Udp4 protocol from the ChildHandle. + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiUdp4ProtocolGuid, + (VOID **) &Udp4Proto, + gUdp4DriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (Udp4Proto); + + if (Instance->InDestroy) { + return EFI_SUCCESS; + } + + // + // Use the Destroyed flag to avoid the re-entering of the following code. + // + Instance->InDestroy = TRUE; + + // + // Close the Ip4 protocol. + // + gBS->CloseProtocol ( + Udp4Service->IpIo->ChildHandle, + &gEfiIp4ProtocolGuid, + gUdp4DriverBinding.DriverBindingHandle, + Instance->ChildHandle + ); + // + // Close the Ip4 protocol on this instance's IpInfo. + // + gBS->CloseProtocol ( + Instance->IpInfo->ChildHandle, + &gEfiIp4ProtocolGuid, + gUdp4DriverBinding.DriverBindingHandle, + Instance->ChildHandle + ); + + // + // Uninstall the Udp4Protocol previously installed on the ChildHandle. + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiUdp4ProtocolGuid, + (VOID *) &Instance->Udp4Proto, + NULL + ); + if (EFI_ERROR (Status)) { + Instance->InDestroy = FALSE; + return Status; + } + + // + // Reset the configuration in case the instance's consumer forgets to do this. + // + Udp4Proto->Configure (Udp4Proto, NULL); + + // + // Remove the IpInfo this instance consumes. + // + IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Remove this instance from the service context data's ChildrenList. + // + RemoveEntryList (&Instance->Link); + Udp4Service->ChildrenNumber--; + + // + // Clean the instance. + // + Udp4CleanInstance (Instance); + + gBS->RestoreTPL (OldTpl); + + FreePool (Instance); + + return EFI_SUCCESS; +} + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + The entry point for Udp4 driver which installs the driver binding + and component name protocol on its ImageHandle. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +Udp4DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install the Udp4DriverBinding and Udp4ComponentName protocols. + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gUdp4DriverBinding, + ImageHandle, + &gUdp4ComponentName, + &gUdp4ComponentName2 + ); + if (!EFI_ERROR (Status)) { + // + // Initialize the UDP random port. + // + mUdp4RandomPort = (UINT16) (((UINT16) NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN); + } + + return Status; +} + diff --git a/NetworkPkg/Udp4Dxe/Udp4Driver.h b/NetworkPkg/Udp4Dxe/Udp4Driver.h new file mode 100644 index 0000000000..4e9a0c7356 --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Driver.h @@ -0,0 +1,148 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UDP4_DRIVER_H_ +#define _UDP4_DRIVER_H_ + +#include +#include +#include +#include +#include + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +Udp4DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +Udp4DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +Udp4DriverBindingStop ( + 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[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] 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 +Udp4ServiceBindingCreateChild ( + 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[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in] 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 +Udp4ServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); + +#endif + diff --git a/NetworkPkg/Udp4Dxe/Udp4Dxe.inf b/NetworkPkg/Udp4Dxe/Udp4Dxe.inf new file mode 100644 index 0000000000..ba623a6637 --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Dxe.inf @@ -0,0 +1,64 @@ +## @file +# This module produces EFI UDP Protocol and EFI UDPv4 Service Binding Protocol. +# +# This module produces EFI UDP(User Datagram Protocol) Protocol upon EFI IPv4 +# Protocol, to provide basic UDPv4 I/O services. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Udp4Dxe + MODULE_UNI_FILE = Udp4Dxe.uni + FILE_GUID = 6d6963ab-906d-4a65-a7ca-bd40e5d6af2b + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Udp4DriverEntryPoint + UNLOAD_IMAGE = NetLibDefaultUnload +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gUdp4DriverBinding +# COMPONENT_NAME = gUdp4ComponentName +# COMPONENT_NAME2 = gUdp4ComponentName2 +# + +[Sources] + Udp4Impl.h + Udp4Main.c + ComponentName.c + Udp4Impl.c + Udp4Driver.h + Udp4Driver.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + UefiLib + BaseLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + DebugLib + IpIoLib + NetLib + DpcLib + +[Protocols] + gEfiUdp4ServiceBindingProtocolGuid ## BY_START + gEfiIp4ServiceBindingProtocolGuid ## TO_START + gEfiUdp4ProtocolGuid ## BY_START + gEfiIp4ProtocolGuid ## TO_START + +[UserExtensions.TianoCore."ExtraFiles"] + Udp4DxeExtra.uni diff --git a/NetworkPkg/Udp4Dxe/Udp4Dxe.uni b/NetworkPkg/Udp4Dxe/Udp4Dxe.uni new file mode 100644 index 0000000000..1e3e4aafe7 --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Dxe.uni @@ -0,0 +1,17 @@ +// /** @file +// This module produces EFI UDP Protocol and EFI UDPv4 Service Binding Protocol. +// +// This module produces EFI UDP(User Datagram Protocol) Protocol upon EFI IPv4 +// Protocol, to provide basic UDPv4 I/O services. +// +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces EFI UDP Protocol and EFI UDPv4 Service Binding Protocol" + +#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI UDP(User Datagram Protocol) Protocol upon EFI IPv4 Protocol to provide basic UDPv4 I/O services." + diff --git a/NetworkPkg/Udp4Dxe/Udp4DxeExtra.uni b/NetworkPkg/Udp4Dxe/Udp4DxeExtra.uni new file mode 100644 index 0000000000..b048ce31a5 --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4DxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// Udp4Dxe 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 +"UDP v4 DXE Driver" + + diff --git a/NetworkPkg/Udp4Dxe/Udp4Impl.c b/NetworkPkg/Udp4Dxe/Udp4Impl.c new file mode 100644 index 0000000000..fb1951fb13 --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Impl.c @@ -0,0 +1,1908 @@ +/** @file + The implementation of the Udp4 protocol. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Udp4Impl.h" + +UINT16 mUdp4RandomPort; + +/** + This function checks and timeouts the I/O datagrams holding by the corresponding + service context. + + @param[in] Event The event this function registered to. + @param[in] Context The context data registered during the creation of + the Event. + +**/ +VOID +EFIAPI +Udp4CheckTimeout ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + This function finds the udp instance by the specified pair. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in] Address Pointer to the specified IPv4 address. + @param[in] Port The udp port number. + + @retval TRUE The specified pair is found. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp4FindInstanceByPort ( + IN LIST_ENTRY *InstanceList, + IN EFI_IPv4_ADDRESS *Address, + IN UINT16 Port + ); + +/** + This function is the packet transmitting notify function registered to the IpIo + interface. It's called to signal the udp TxToken when IpIo layer completes the + transmitting of the udp datagram. + + @param[in] Status The completion status of the output udp datagram. + @param[in] Context Pointer to the context data. + @param[in] Sender Specify a pointer of EFI_IP4_PROTOCOL for sending. + @param[in] NotifyData Pointer to the notify data. + +**/ +VOID +EFIAPI +Udp4DgramSent ( + IN EFI_STATUS Status, + IN VOID *Context, + IN IP_IO_IP_PROTOCOL Sender, + IN VOID *NotifyData + ); + +/** + This function processes the received datagram passed up by the IpIo layer. + + @param[in] Status The status of this udp datagram. + @param[in] IcmpError The IcmpError code, only available when Status is + EFI_ICMP_ERROR. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA. + @param[in] Packet Pointer to the NET_BUF containing the received udp + datagram. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp4DgramRcvd ( + IN EFI_STATUS Status, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet, + IN VOID *Context + ); + +/** + This function cancels the token specified by Arg in the Map. This is a callback + used by Udp4InstanceCancelToken(). + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled, if NULL, + the token specified by Item is cancelled. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token + is not the same as that in the Item if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Udp4CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ); + +/** + This function matches the received udp datagram with the Instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted + from the received udp datagram. + + @retval TRUE The udp datagram matches the receiving requirments of the + udp Instance. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp4MatchDgram ( + IN UDP4_INSTANCE_DATA *Instance, + IN EFI_UDP4_SESSION_DATA *Udp4Session + ); + +/** + This function removes the Wrap specified by Context and release relevant resources. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp4RecycleRxDataWrap ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + This function wraps the Packet and the RxData. + + @param[in] Instance Pointer to the instance context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this + datagram. + + @return Pointer to the structure wrapping the RxData and the Packet. + +**/ +UDP4_RXDATA_WRAP * +Udp4WrapRxData ( + IN UDP4_INSTANCE_DATA *Instance, + IN NET_BUF *Packet, + IN EFI_UDP4_RECEIVE_DATA *RxData + ); + +/** + This function enqueues the received datagram into the instances' receiving queues. + + @param[in] Udp4Service Pointer to the udp service context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this + datagram. + + @return The times this datagram is enqueued. + +**/ +UINTN +Udp4EnqueueDgram ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN NET_BUF *Packet, + IN EFI_UDP4_RECEIVE_DATA *RxData + ); + +/** + This function delivers the datagrams enqueued in the instances. + + @param[in] Udp4Service Pointer to the udp service context data. + +**/ +VOID +Udp4DeliverDgram ( + IN UDP4_SERVICE_DATA *Udp4Service + ); + +/** + This function demultiplexes the received udp datagram to the appropriate instances. + + @param[in] Udp4Service Pointer to the udp service context data. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted from + the received datagram. + @param[in] Packet Pointer to the buffer containing the received udp + datagram. + +**/ +VOID +Udp4Demultiplex ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet + ); + +/** + This function handles the received Icmp Error message and demultiplexes it to the + instance. + + @param[in] Udp4Service Pointer to the udp service context data. + @param[in] IcmpError The icmp error code. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted + from the received Icmp Error packet. + @param[in] Packet Pointer to the Icmp Error packet. + +**/ +VOID +Udp4IcmpHandler ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet + ); + +/** + This function builds and sends out a icmp port unreachable message. + + @param[in] IpIo Pointer to the IP_IO instance. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet + causes this icmp error message. + @param[in] Udp4Header Pointer to the udp header of the datagram causes + this icmp error message. + +**/ +VOID +Udp4SendPortUnreach ( + IN IP_IO *IpIo, + IN EFI_NET_SESSION_DATA *NetSession, + IN VOID *Udp4Header + ); + + +/** + Create the Udp service context data. + + @param[in, out] Udp4Service Pointer to the UDP4_SERVICE_DATA. + @param[in] ImageHandle The image handle of this udp4 driver. + @param[in] ControllerHandle The controller handle this udp4 driver binds on. + + @retval EFI_SUCCESS The udp4 service context data is created and + initialized. + @retval EFI_OUT_OF_RESOURCES Cannot allocate memory. + @retval other Other error occurs. + +**/ +EFI_STATUS +Udp4CreateService ( + IN OUT UDP4_SERVICE_DATA *Udp4Service, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + IP_IO_OPEN_DATA OpenData; + EFI_IP4_CONFIG_DATA *Ip4ConfigData; + + ZeroMem (Udp4Service, sizeof (UDP4_SERVICE_DATA)); + + Udp4Service->Signature = UDP4_SERVICE_DATA_SIGNATURE; + Udp4Service->ServiceBinding = mUdp4ServiceBinding; + Udp4Service->ImageHandle = ImageHandle; + Udp4Service->ControllerHandle = ControllerHandle; + Udp4Service->ChildrenNumber = 0; + + InitializeListHead (&Udp4Service->ChildrenList); + + // + // Create the IpIo for this service context. + // + Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle, IP_VERSION_4); + if (Udp4Service->IpIo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Set the OpenData used to open the IpIo. + // + Ip4ConfigData = &OpenData.IpConfigData.Ip4CfgData; + CopyMem (Ip4ConfigData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA)); + Ip4ConfigData->AcceptBroadcast = TRUE; + OpenData.RcvdContext = (VOID *) Udp4Service; + OpenData.SndContext = NULL; + OpenData.PktRcvdNotify = Udp4DgramRcvd; + OpenData.PktSentNotify = Udp4DgramSent; + + // + // Configure and start the IpIo. + // + Status = IpIoOpen (Udp4Service->IpIo, &OpenData); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create the event for Udp timeout checking. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Udp4CheckTimeout, + Udp4Service, + &Udp4Service->TimeoutEvent + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Start the timeout timer event. + // + Status = gBS->SetTimer ( + Udp4Service->TimeoutEvent, + TimerPeriodic, + UDP4_TIMEOUT_INTERVAL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (Udp4Service->TimeoutEvent != NULL) { + gBS->CloseEvent (Udp4Service->TimeoutEvent); + } + + IpIoDestroy (Udp4Service->IpIo); + + return Status; +} + + +/** + Clean the Udp service context data. + + @param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA. + +**/ +VOID +Udp4CleanService ( + IN UDP4_SERVICE_DATA *Udp4Service + ) +{ + // + // Cancel the TimeoutEvent timer. + // + gBS->SetTimer (Udp4Service->TimeoutEvent, TimerCancel, 0); + + // + // Close the TimeoutEvent timer. + // + gBS->CloseEvent (Udp4Service->TimeoutEvent); + + // + // Destroy the IpIo. + // + IpIoDestroy (Udp4Service->IpIo); +} + + +/** + This function checks and timeouts the I/O datagrams holding by the corresponding + service context. + + @param[in] Event The event this function registered to. + @param[in] Context The context data registered during the creation of + the Event. + +**/ +VOID +EFIAPI +Udp4CheckTimeout ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UDP4_SERVICE_DATA *Udp4Service; + LIST_ENTRY *Entry; + UDP4_INSTANCE_DATA *Instance; + LIST_ENTRY *WrapEntry; + LIST_ENTRY *NextEntry; + UDP4_RXDATA_WRAP *Wrap; + + Udp4Service = (UDP4_SERVICE_DATA *) Context; + NET_CHECK_SIGNATURE (Udp4Service, UDP4_SERVICE_DATA_SIGNATURE); + + NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) { + // + // Iterate all the instances belonging to this service context. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link); + NET_CHECK_SIGNATURE (Instance, UDP4_INSTANCE_DATA_SIGNATURE); + + if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) { + // + // Skip this instance if it's not configured or no receive timeout. + // + continue; + } + + NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) { + // + // Iterate all the rxdatas belonging to this udp instance. + // + Wrap = NET_LIST_USER_STRUCT (WrapEntry, UDP4_RXDATA_WRAP, Link); + + // + // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns. + // + if (Wrap->TimeoutTick < (UDP4_TIMEOUT_INTERVAL / 10)) { + // + // Remove this RxData if it timeouts. + // + Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap); + } else { + Wrap->TimeoutTick -= (UDP4_TIMEOUT_INTERVAL / 10); + } + } + } +} + + +/** + This function intializes the new created udp instance. + + @param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA. + @param[in, out] Instance Pointer to the un-initialized UDP4_INSTANCE_DATA. + +**/ +VOID +Udp4InitInstance ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN OUT UDP4_INSTANCE_DATA *Instance + ) +{ + // + // Set the signature. + // + Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE; + + // + // Init the lists. + // + InitializeListHead (&Instance->Link); + InitializeListHead (&Instance->RcvdDgramQue); + InitializeListHead (&Instance->DeliveredDgramQue); + + // + // Init the NET_MAPs. + // + NetMapInit (&Instance->TxTokens); + NetMapInit (&Instance->RxTokens); + NetMapInit (&Instance->McastIps); + + // + // Save the pointer to the UDP4_SERVICE_DATA, and initialize other members. + // + Instance->Udp4Service = Udp4Service; + CopyMem (&Instance->Udp4Proto, &mUdp4Protocol, sizeof (Instance->Udp4Proto)); + Instance->IcmpError = EFI_SUCCESS; + Instance->Configured = FALSE; + Instance->IsNoMapping = FALSE; + Instance->InDestroy = FALSE; +} + + +/** + This function cleans the udp instance. + + @param[in] Instance Pointer to the UDP4_INSTANCE_DATA to clean. + +**/ +VOID +Udp4CleanInstance ( + IN UDP4_INSTANCE_DATA *Instance + ) +{ + NetMapClean (&Instance->McastIps); + NetMapClean (&Instance->RxTokens); + NetMapClean (&Instance->TxTokens); +} + + +/** + This function finds the udp instance by the specified pair. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in] Address Pointer to the specified IPv4 address. + @param[in] Port The udp port number. + + @retval TRUE The specified pair is found. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp4FindInstanceByPort ( + IN LIST_ENTRY *InstanceList, + IN EFI_IPv4_ADDRESS *Address, + IN UINT16 Port + ) +{ + LIST_ENTRY *Entry; + UDP4_INSTANCE_DATA *Instance; + EFI_UDP4_CONFIG_DATA *ConfigData; + + NET_LIST_FOR_EACH (Entry, InstanceList) { + // + // Iterate all the udp instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link); + ConfigData = &Instance->ConfigData; + + if (!Instance->Configured || ConfigData->AcceptAnyPort) { + // + // If the instance is not configured or the configdata of the instance indicates + // this instance accepts any port, skip it. + // + continue; + } + + if (EFI_IP4_EQUAL (&ConfigData->StationAddress, Address) && + (ConfigData->StationPort == Port)) { + // + // if both the address and the port are the same, return TRUE. + // + return TRUE; + } + } + + // + // return FALSE when matching fails. + // + return FALSE; +} + + +/** + This function tries to bind the udp instance according to the configured port + allocation strategy. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in, out] ConfigData Pointer to the ConfigData of the instance to be + bound. ConfigData->StationPort will be assigned + with an available port value on success. + + @retval EFI_SUCCESS The bound operation is completed successfully. + @retval EFI_ACCESS_DENIED The specified by the ConfigData is + already used by other instance. + @retval EFI_OUT_OF_RESOURCES No available port resources. + +**/ +EFI_STATUS +Udp4Bind ( + IN LIST_ENTRY *InstanceList, + IN OUT EFI_UDP4_CONFIG_DATA *ConfigData + ) +{ + EFI_IPv4_ADDRESS *StationAddress; + UINT16 StartPort; + + if (ConfigData->AcceptAnyPort) { + return EFI_SUCCESS; + } + + StationAddress = &ConfigData->StationAddress; + + if (ConfigData->StationPort != 0) { + + if (!ConfigData->AllowDuplicatePort && + Udp4FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)) { + // + // Do not allow duplicate port and the port is already used by other instance. + // + return EFI_ACCESS_DENIED; + } + } else { + // + // select a random port for this instance; + // + + if (ConfigData->AllowDuplicatePort) { + // + // Just pick up the random port if the instance allows duplicate port. + // + ConfigData->StationPort = mUdp4RandomPort; + } else { + + StartPort = mUdp4RandomPort; + + while (Udp4FindInstanceByPort(InstanceList, StationAddress, mUdp4RandomPort)) { + + mUdp4RandomPort++; + if (mUdp4RandomPort == 0) { + mUdp4RandomPort = UDP4_PORT_KNOWN; + } + + if (mUdp4RandomPort == StartPort) { + // + // No available port. + // + return EFI_OUT_OF_RESOURCES; + } + } + + ConfigData->StationPort = mUdp4RandomPort; + } + + mUdp4RandomPort++; + if (mUdp4RandomPort == 0) { + mUdp4RandomPort = UDP4_PORT_KNOWN; + } + } + + return EFI_SUCCESS; +} + + +/** + This function is used to check whether the NewConfigData has any un-reconfigurable + parameters changed compared to the OldConfigData. + + @param[in] OldConfigData Pointer to the current ConfigData the udp instance + uses. + @param[in] NewConfigData Pointer to the new ConfigData. + + @retval TRUE The instance is reconfigurable. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp4IsReconfigurable ( + IN EFI_UDP4_CONFIG_DATA *OldConfigData, + IN EFI_UDP4_CONFIG_DATA *NewConfigData + ) +{ + if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) || + (NewConfigData->AcceptBroadcast != OldConfigData->AcceptBroadcast) || + (NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) || + (NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort) + ) { + // + // The receiving filter parameters cannot be changed. + // + return FALSE; + } + + if ((!NewConfigData->AcceptAnyPort) && + (NewConfigData->StationPort != OldConfigData->StationPort) + ) { + // + // The port is not changeable. + // + return FALSE; + } + + if (!NewConfigData->AcceptPromiscuous) { + + if (NewConfigData->UseDefaultAddress != OldConfigData->UseDefaultAddress) { + // + // The NewConfigData differs to the old one on the UseDefaultAddress. + // + return FALSE; + } + + if (!NewConfigData->UseDefaultAddress && + (!EFI_IP4_EQUAL (&NewConfigData->StationAddress, &OldConfigData->StationAddress) || + !EFI_IP4_EQUAL (&NewConfigData->SubnetMask, &OldConfigData->SubnetMask)) + ) { + // + // If the instance doesn't use the default address, and the new address or + // new subnet mask is different from the old values. + // + return FALSE; + } + } + + if (!EFI_IP4_EQUAL (&NewConfigData->RemoteAddress, &OldConfigData->RemoteAddress)) { + // + // The remoteaddress is not the same. + // + return FALSE; + } + + if (!EFI_IP4_EQUAL (&NewConfigData->RemoteAddress, &mZeroIp4Addr) && + NewConfigData->RemotePort != OldConfigData->RemotePort + ) { + // + // The RemotePort differs if it's designated in the configdata. + // + return FALSE; + } + + // + // All checks pass, return TRUE. + // + return TRUE; +} + + +/** + This function builds the Ip4 configdata from the Udp4ConfigData. + + @param[in] Udp4ConfigData Pointer to the EFI_UDP4_CONFIG_DATA. + @param[in, out] Ip4ConfigData Pointer to the EFI_IP4_CONFIG_DATA. + +**/ +VOID +Udp4BuildIp4ConfigData ( + IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData, + IN OUT EFI_IP4_CONFIG_DATA *Ip4ConfigData + ) +{ + CopyMem (Ip4ConfigData, &mIp4IoDefaultIpConfigData, sizeof (*Ip4ConfigData)); + + Ip4ConfigData->DefaultProtocol = EFI_IP_PROTO_UDP; + Ip4ConfigData->AcceptBroadcast = Udp4ConfigData->AcceptBroadcast; + Ip4ConfigData->AcceptPromiscuous = Udp4ConfigData->AcceptPromiscuous; + Ip4ConfigData->UseDefaultAddress = Udp4ConfigData->UseDefaultAddress; + CopyMem (&Ip4ConfigData->StationAddress, &Udp4ConfigData->StationAddress, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Ip4ConfigData->SubnetMask, &Udp4ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + + // + // use the -1 magic number to disable the receiving process of the ip instance. + // + Ip4ConfigData->ReceiveTimeout = (UINT32) (-1); +} + + +/** + This function validates the TxToken, it returns the error code according to the spec. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] TxToken Pointer to the token to be checked. + + @retval EFI_SUCCESS The TxToken is valid. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: This is + NULL. Token is NULL. Token.Event is NULL. + Token.Packet.TxData is NULL. + Token.Packet.TxData.FragmentCount is zero. + Token.Packet.TxData.DataLength is not equal to the + sum of fragment lengths. One or more of the + Token.Packet.TxData.FragmentTable[]. + FragmentLength fields is zero. One or more of the + Token.Packet.TxData.FragmentTable[]. + FragmentBuffer fields is NULL. + Token.Packet.TxData. GatewayAddress is not a + unicast IPv4 address if it is not NULL. One or + more IPv4 addresses in Token.Packet.TxData. + UdpSessionData are not valid unicast IPv4 + addresses if the UdpSessionData is not NULL. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP + packet size. + +**/ +EFI_STATUS +Udp4ValidateTxToken ( + IN UDP4_INSTANCE_DATA *Instance, + IN EFI_UDP4_COMPLETION_TOKEN *TxToken + ) +{ + EFI_UDP4_TRANSMIT_DATA *TxData; + UINT32 Index; + UINT32 TotalLen; + EFI_UDP4_CONFIG_DATA *ConfigData; + EFI_UDP4_SESSION_DATA *UdpSessionData; + IP4_ADDR SourceAddress; + IP4_ADDR GatewayAddress; + + if (TxToken->Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + TxData = TxToken->Packet.TxData; + + if ((TxData == NULL) || (TxData->FragmentCount == 0)) { + return EFI_INVALID_PARAMETER; + } + + TotalLen = 0; + for (Index = 0; Index < TxData->FragmentCount; Index++) { + + if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) || + (TxData->FragmentTable[Index].FragmentLength == 0)) { + // + // if the FragmentBuffer is NULL or the FragmentLeng is zero. + // + return EFI_INVALID_PARAMETER; + } + + TotalLen += TxData->FragmentTable[Index].FragmentLength; + } + + if (TotalLen != TxData->DataLength) { + // + // The TotalLen calculated by adding all the FragmentLeng doesn't equal to the + // DataLength. + // + return EFI_INVALID_PARAMETER; + } + + if (TxData->GatewayAddress != NULL) { + CopyMem (&GatewayAddress, TxData->GatewayAddress, sizeof (IP4_ADDR)); + + if (!Instance->ConfigData.UseDefaultAddress && + (EFI_NTOHL(Instance->ConfigData.SubnetMask) != 0) && + !NetIp4IsUnicast (NTOHL (GatewayAddress), EFI_NTOHL(Instance->ConfigData.SubnetMask))) { + // + // The specified GatewayAddress is not a unicast IPv4 address while it's not 0. + // + return EFI_INVALID_PARAMETER; + } + } + + ConfigData = &Instance->ConfigData; + UdpSessionData = TxData->UdpSessionData; + + if (UdpSessionData != NULL) { + + CopyMem (&SourceAddress, &UdpSessionData->SourceAddress, sizeof (IP4_ADDR)); + + if ((SourceAddress != 0) && + !Instance->ConfigData.UseDefaultAddress && + (EFI_NTOHL(Instance->ConfigData.SubnetMask) != 0) && + !NetIp4IsUnicast (HTONL (SourceAddress), EFI_NTOHL(Instance->ConfigData.SubnetMask))) { + // + // Check whether SourceAddress is a valid IPv4 address in case it's not zero. + // The configured station address is used if SourceAddress is zero. + // + return EFI_INVALID_PARAMETER; + } + + if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) { + // + // Ambiguous, no avalaible DestinationPort for this token. + // + return EFI_INVALID_PARAMETER; + } + + if (EFI_IP4_EQUAL (&UdpSessionData->DestinationAddress, &mZeroIp4Addr)) { + // + // The DestinationAddress specified in the UdpSessionData is 0. + // + return EFI_INVALID_PARAMETER; + } + } else if (EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &mZeroIp4Addr)) { + // + // the configured RemoteAddress is all zero, and the user doens't override the + // destination address. + // + return EFI_INVALID_PARAMETER; + } + + if (TxData->DataLength > UDP4_MAX_DATA_SIZE) { + return EFI_BAD_BUFFER_SIZE; + } + + return EFI_SUCCESS; +} + + +/** + This function checks whether the specified Token duplicates with the one in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM contain the pointer to + the Token. + @param[in] Context Pointer to the Token to be checked. + + @retval EFI_SUCCESS The Token specified by Context differs from the + one in the Item. + @retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item. + +**/ +EFI_STATUS +EFIAPI +Udp4TokenExist ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Context + ) +{ + EFI_UDP4_COMPLETION_TOKEN *Token; + EFI_UDP4_COMPLETION_TOKEN *TokenInItem; + + Token = (EFI_UDP4_COMPLETION_TOKEN*) Context; + TokenInItem = (EFI_UDP4_COMPLETION_TOKEN*) Item->Key; + + if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) { + // + // The Token duplicates with the TokenInItem in case either the two pointers are the + // same or the Events of these two tokens are the same. + // + return EFI_ACCESS_DENIED; + } + + return EFI_SUCCESS; +} + + +/** + This function calculates the checksum for the Packet, utilizing the pre-calculated + pseudo HeadSum to reduce some overhead. + + @param[in] Packet Pointer to the NET_BUF contains the udp datagram. + @param[in] HeadSum Checksum of the pseudo header execpt the length + field. + + @retval The 16-bit checksum of this udp datagram. + +**/ +UINT16 +Udp4Checksum ( + IN NET_BUF *Packet, + IN UINT16 HeadSum + ) +{ + UINT16 Checksum; + + Checksum = NetbufChecksum (Packet); + Checksum = NetAddChecksum (Checksum, HeadSum); + + Checksum = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize)); + + return (UINT16) ~Checksum; +} + + +/** + This function removes the specified Token from the TokenMap. + + @param[in, out] TokenMap Pointer to the NET_MAP containing the tokens. + @param[in] Token Pointer to the Token to be removed. + + @retval EFI_SUCCESS The specified Token is removed from the TokenMap. + @retval EFI_NOT_FOUND The specified Token is not found in the TokenMap. + +**/ +EFI_STATUS +Udp4RemoveToken ( + IN OUT NET_MAP *TokenMap, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ) +{ + NET_MAP_ITEM *Item; + + // + // Find the Token first. + // + Item = NetMapFindKey (TokenMap, (VOID *) Token); + + if (Item != NULL) { + // + // Remove the token if it's found in the map. + // + NetMapRemoveItem (TokenMap, Item, NULL); + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + + +/** + This function is the packet transmitting notify function registered to the IpIo + interface. It's called to signal the udp TxToken when IpIo layer completes the + transmitting of the udp datagram. + + @param[in] Status The completion status of the output udp datagram. + @param[in] Context Pointer to the context data. + @param[in] Sender Specify a pointer of EFI_IP4_PROTOCOL for sending. + @param[in] NotifyData Pointer to the notify data. + +**/ +VOID +EFIAPI +Udp4DgramSent ( + IN EFI_STATUS Status, + IN VOID *Context, + IN IP_IO_IP_PROTOCOL Sender, + IN VOID *NotifyData + ) +{ + UDP4_INSTANCE_DATA *Instance; + EFI_UDP4_COMPLETION_TOKEN *Token; + + Instance = (UDP4_INSTANCE_DATA *) Context; + Token = (EFI_UDP4_COMPLETION_TOKEN *) NotifyData; + + if (Udp4RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) { + // + // The token may be cancelled. Only signal it if the remove operation succeeds. + // + Token->Status = Status; + gBS->SignalEvent (Token->Event); + DispatchDpc (); + } +} + + +/** + This function processes the received datagram passed up by the IpIo layer. + + @param[in] Status The status of this udp datagram. + @param[in] IcmpError The IcmpError code, only available when Status is + EFI_ICMP_ERROR. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA. + @param[in] Packet Pointer to the NET_BUF containing the received udp + datagram. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp4DgramRcvd ( + IN EFI_STATUS Status, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet, + IN VOID *Context + ) +{ + NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE); + + // + // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR. + // + if (Status == EFI_SUCCESS) { + // + // Demultiplex the received datagram. + // + Udp4Demultiplex ((UDP4_SERVICE_DATA *) Context, NetSession, Packet); + } else { + // + // Handle the ICMP_ERROR packet. + // + Udp4IcmpHandler ((UDP4_SERVICE_DATA *) Context, IcmpError, NetSession, Packet); + } + + // + // Dispatch the DPC queued by the NotifyFunction of the rx token's events + // which are signaled with received data. + // + DispatchDpc (); +} + + +/** + This function removes the multicast group specified by Arg from the Map. + + @param[in, out] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the Arg, it's the pointer to a + multicast IPv4 Address. + + @retval EFI_SUCCESS The multicast address is removed. + @retval EFI_ABORTED The specified multicast address is removed and the + Arg is not NULL. + +**/ +EFI_STATUS +EFIAPI +Udp4LeaveGroup ( + IN OUT NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ) +{ + EFI_IPv4_ADDRESS *McastIp; + + McastIp = Arg; + + if ((McastIp != NULL) && (!EFI_IP4_EQUAL (McastIp, &(Item->Key)))) { + // + // McastIp is not NULL and the multicast address contained in the Item + // is not the same as McastIp. + // + return EFI_SUCCESS; + } + + // + // Remove this Item. + // + NetMapRemoveItem (Map, Item, NULL); + + if (McastIp != NULL) { + // + // Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration. + // + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + + +/** + This function cancels the token specified by Arg in the Map. This is a callback + used by Udp4InstanceCancelToken(). + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled, if NULL, + the token specified by Item is cancelled. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token + is not the same as that in the Item if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Udp4CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ) +{ + EFI_UDP4_COMPLETION_TOKEN *TokenToCancel; + NET_BUF *Packet; + IP_IO *IpIo; + + if ((Arg != NULL) && (Item->Key != Arg)) { + return EFI_SUCCESS; + } + + if (Item->Value != NULL) { + // + // If the token is a transmit token, the corresponding Packet is recorded in + // Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken + // will invoke Udp4DgramSent, the token will be signaled and this Item will + // be removed from the Map there. + // + Packet = (NET_BUF *) (Item->Value); + IpIo = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0])); + + IpIoCancelTxToken (IpIo, Packet); + } else { + // + // The token is a receive token. Abort it and remove it from the Map. + // + TokenToCancel = (EFI_UDP4_COMPLETION_TOKEN *) Item->Key; + NetMapRemoveItem (Map, Item, NULL); + + TokenToCancel->Status = EFI_ABORTED; + gBS->SignalEvent (TokenToCancel->Event); + } + + if (Arg != NULL) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + + +/** + This function removes all the Wrap datas in the RcvdDgramQue. + + @param[in] Instance Pointer to the udp instance context data. + +**/ +VOID +Udp4FlushRcvdDgram ( + IN UDP4_INSTANCE_DATA *Instance + ) +{ + UDP4_RXDATA_WRAP *Wrap; + + while (!IsListEmpty (&Instance->RcvdDgramQue)) { + // + // Iterate all the Wraps in the RcvdDgramQue. + // + Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link); + + // + // The Wrap will be removed from the RcvdDgramQue by this function call. + // + Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap); + } +} + + + +/** + Cancel Udp4 tokens from the Udp4 instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Token Pointer to the token to be canceled, if NULL, all + tokens in this instance will be cancelled. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Udp4InstanceCancelToken ( + IN UDP4_INSTANCE_DATA *Instance, + IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // Cancel this token from the TxTokens map. + // + Status = NetMapIterate (&Instance->TxTokens, Udp4CancelTokens, Token); + + if ((Token != NULL) && (Status == EFI_ABORTED)) { + // + // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from + // the TxTokens, just return success. + // + return EFI_SUCCESS; + } + + // + // Try to cancel this token from the RxTokens map in condition either the Token + // is NULL or the specified Token is not in TxTokens. + // + Status = NetMapIterate (&Instance->RxTokens, Udp4CancelTokens, Token); + + if ((Token != NULL) && (Status == EFI_SUCCESS)) { + // + // If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the + // TxTokens nor the RxTokens, or say, it's not found. + // + return EFI_NOT_FOUND; + } + + ASSERT ((Token != NULL) || ((0 == NetMapGetCount (&Instance->TxTokens)) + && (0 == NetMapGetCount (&Instance->RxTokens)))); + + return EFI_SUCCESS; +} + + +/** + This function matches the received udp datagram with the Instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted + from the received udp datagram. + + @retval TRUE The udp datagram matches the receiving requirments of the + udp Instance. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp4MatchDgram ( + IN UDP4_INSTANCE_DATA *Instance, + IN EFI_UDP4_SESSION_DATA *Udp4Session + ) +{ + EFI_UDP4_CONFIG_DATA *ConfigData; + IP4_ADDR Destination; + + ConfigData = &Instance->ConfigData; + + if (ConfigData->AcceptPromiscuous) { + // + // Always matches if this instance is in the promiscuous state. + // + return TRUE; + } + + if ((!ConfigData->AcceptAnyPort && (Udp4Session->DestinationPort != ConfigData->StationPort)) || + ((ConfigData->RemotePort != 0) && (Udp4Session->SourcePort != ConfigData->RemotePort)) + ) { + // + // The local port or the remote port doesn't match. + // + return FALSE; + } + + if (!EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &mZeroIp4Addr) && + !EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &Udp4Session->SourceAddress) + ) { + // + // This datagram doesn't come from the instance's specified sender. + // + return FALSE; + } + + if (EFI_IP4_EQUAL (&ConfigData->StationAddress, &mZeroIp4Addr) || + EFI_IP4_EQUAL (&Udp4Session->DestinationAddress, &ConfigData->StationAddress) + ) { + // + // The instance is configured to receive datagrams destined to any station IP or + // the destination address of this datagram matches the configured station IP. + // + return TRUE; + } + + CopyMem (&Destination, &Udp4Session->DestinationAddress, sizeof (IP4_ADDR)); + + if (IP4_IS_LOCAL_BROADCAST (Destination) && ConfigData->AcceptBroadcast) { + // + // The instance is configured to receive broadcast and this is a broadcast packet. + // + return TRUE; + } + + if (IP4_IS_MULTICAST (NTOHL (Destination)) && + NetMapFindKey (&Instance->McastIps, (VOID *) (UINTN) Destination) != NULL + ) { + // + // It's a multicast packet and the multicast address is accepted by this instance. + // + return TRUE; + } + + return FALSE; +} + + +/** + This function removes the Wrap specified by Context and release relevant resources. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp4RecycleRxDataWrap ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UDP4_RXDATA_WRAP *Wrap; + + Wrap = (UDP4_RXDATA_WRAP *) Context; + + // + // Remove the Wrap from the list it belongs to. + // + RemoveEntryList (&Wrap->Link); + + // + // Free the Packet associated with this Wrap. + // + NetbufFree (Wrap->Packet); + + // + // Close the event. + // + gBS->CloseEvent (Wrap->RxData.RecycleSignal); + + FreePool (Wrap); +} + + +/** + This function wraps the Packet and the RxData. + + @param[in] Instance Pointer to the instance context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this + datagram. + + @return Pointer to the structure wrapping the RxData and the Packet. + +**/ +UDP4_RXDATA_WRAP * +Udp4WrapRxData ( + IN UDP4_INSTANCE_DATA *Instance, + IN NET_BUF *Packet, + IN EFI_UDP4_RECEIVE_DATA *RxData + ) +{ + EFI_STATUS Status; + UDP4_RXDATA_WRAP *Wrap; + + // + // Allocate buffer for the Wrap. + // + Wrap = AllocatePool (sizeof (UDP4_RXDATA_WRAP) + + (Packet->BlockOpNum - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA)); + if (Wrap == NULL) { + return NULL; + } + + InitializeListHead (&Wrap->Link); + + CopyMem (&Wrap->RxData, RxData, sizeof (Wrap->RxData)); + + // + // Create the Recycle event. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + Udp4RecycleRxDataWrap, + Wrap, + &Wrap->RxData.RecycleSignal + ); + if (EFI_ERROR (Status)) { + FreePool (Wrap); + return NULL; + } + + Wrap->Packet = Packet; + Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout; + + return Wrap; +} + + +/** + This function enqueues the received datagram into the instances' receiving queues. + + @param[in] Udp4Service Pointer to the udp service context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this + datagram. + + @return The times this datagram is enqueued. + +**/ +UINTN +Udp4EnqueueDgram ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN NET_BUF *Packet, + IN EFI_UDP4_RECEIVE_DATA *RxData + ) +{ + LIST_ENTRY *Entry; + UDP4_INSTANCE_DATA *Instance; + UDP4_RXDATA_WRAP *Wrap; + UINTN Enqueued; + + Enqueued = 0; + + NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) { + // + // Iterate the instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link); + + if (!Instance->Configured) { + continue; + } + + if (Udp4MatchDgram (Instance, &RxData->UdpSession)) { + // + // Wrap the RxData and put this Wrap into the instances RcvdDgramQue. + // + Wrap = Udp4WrapRxData (Instance, Packet, RxData); + if (Wrap == NULL) { + continue; + } + + NET_GET_REF (Packet); + + InsertTailList (&Instance->RcvdDgramQue, &Wrap->Link); + + Enqueued++; + } + } + + return Enqueued; +} + + +/** + This function delivers the received datagrams for the specified instance. + + @param[in] Instance Pointer to the instance context data. + +**/ +VOID +Udp4InstanceDeliverDgram ( + IN UDP4_INSTANCE_DATA *Instance + ) +{ + UDP4_RXDATA_WRAP *Wrap; + EFI_UDP4_COMPLETION_TOKEN *Token; + NET_BUF *Dup; + EFI_UDP4_RECEIVE_DATA *RxData; + EFI_TPL OldTpl; + + if (!IsListEmpty (&Instance->RcvdDgramQue) && + !NetMapIsEmpty (&Instance->RxTokens)) { + + Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link); + + if (NET_BUF_SHARED (Wrap->Packet)) { + // + // Duplicate the Packet if it is shared between instances. + // + Dup = NetbufDuplicate (Wrap->Packet, NULL, 0); + if (Dup == NULL) { + return; + } + + NetbufFree (Wrap->Packet); + + Wrap->Packet = Dup; + } + + NetListRemoveHead (&Instance->RcvdDgramQue); + + Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL); + + // + // Build the FragmentTable and set the FragmentCount in RxData. + // + RxData = &Wrap->RxData; + RxData->FragmentCount = Wrap->Packet->BlockOpNum; + + NetbufBuildExt ( + Wrap->Packet, + (NET_FRAGMENT *) RxData->FragmentTable, + &RxData->FragmentCount + ); + + Token->Status = EFI_SUCCESS; + Token->Packet.RxData = &Wrap->RxData; + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Instance->DeliveredDgramQue, &Wrap->Link); + gBS->RestoreTPL (OldTpl); + + gBS->SignalEvent (Token->Event); + } +} + + +/** + This function delivers the datagrams enqueued in the instances. + + @param[in] Udp4Service Pointer to the udp service context data. + +**/ +VOID +Udp4DeliverDgram ( + IN UDP4_SERVICE_DATA *Udp4Service + ) +{ + LIST_ENTRY *Entry; + UDP4_INSTANCE_DATA *Instance; + + NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) { + // + // Iterate the instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link); + + if (!Instance->Configured) { + continue; + } + + // + // Deliver the datagrams of this instance. + // + Udp4InstanceDeliverDgram (Instance); + } +} + + +/** + This function demultiplexes the received udp datagram to the appropriate instances. + + @param[in] Udp4Service Pointer to the udp service context data. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted from + the received datagram. + @param[in] Packet Pointer to the buffer containing the received udp + datagram. + +**/ +VOID +Udp4Demultiplex ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet + ) +{ + EFI_UDP_HEADER *Udp4Header; + UINT16 HeadSum; + EFI_UDP4_RECEIVE_DATA RxData; + EFI_UDP4_SESSION_DATA *Udp4Session; + UINTN Enqueued; + + if (Packet->TotalSize < sizeof (EFI_UDP_HEADER)) { + NetbufFree (Packet); + return; + } + + // + // Get the datagram header from the packet buffer. + // + Udp4Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL); + ASSERT (Udp4Header != NULL); + + if (Udp4Header->Checksum != 0) { + // + // check the checksum. + // + HeadSum = NetPseudoHeadChecksum ( + NetSession->Source.Addr[0], + NetSession->Dest.Addr[0], + EFI_IP_PROTO_UDP, + 0 + ); + + if (Udp4Checksum (Packet, HeadSum) != 0) { + // + // Wrong checksum. + // + NetbufFree (Packet); + return; + } + } + + Udp4Session = &RxData.UdpSession; + Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort); + Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort); + + CopyMem (&Udp4Session->SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Udp4Session->DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS)); + + // + // Trim the UDP header. + // + NetbufTrim (Packet, UDP4_HEADER_SIZE, TRUE); + + RxData.DataLength = (UINT32) Packet->TotalSize; + + // + // Try to enqueue this datagram into the instances. + // + Enqueued = Udp4EnqueueDgram (Udp4Service, Packet, &RxData); + + if (Enqueued == 0) { + // + // Send the port unreachable ICMP packet before we free this NET_BUF + // + Udp4SendPortUnreach (Udp4Service->IpIo, NetSession, Udp4Header); + } + + // + // Try to free the packet before deliver it. + // + NetbufFree (Packet); + + if (Enqueued > 0) { + // + // Deliver the datagram. + // + Udp4DeliverDgram (Udp4Service); + } +} + + +/** + This function builds and sends out a icmp port unreachable message. + + @param[in] IpIo Pointer to the IP_IO instance. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet + causes this icmp error message. + @param[in] Udp4Header Pointer to the udp header of the datagram causes + this icmp error message. + +**/ +VOID +Udp4SendPortUnreach ( + IN IP_IO *IpIo, + IN EFI_NET_SESSION_DATA *NetSession, + IN VOID *Udp4Header + ) +{ + NET_BUF *Packet; + UINT32 Len; + IP4_ICMP_ERROR_HEAD *IcmpErrHdr; + EFI_IP4_HEADER *IpHdr; + UINT8 *Ptr; + IP_IO_OVERRIDE Override; + IP_IO_IP_INFO *IpSender; + + IpSender = IpIoFindSender (&IpIo, NetSession->IpVersion, &NetSession->Dest); + if (IpSender == NULL) { + // + // No appropriate sender, since we cannot send out the ICMP message through + // the default zero station address IP instance, abort. + // + return; + } + + IpHdr = NetSession->IpHdr.Ip4Hdr; + + // + // Calculate the required length of the icmp error message. + // + Len = sizeof (IP4_ICMP_ERROR_HEAD) + (EFI_IP4_HEADER_LEN (IpHdr) - + sizeof (IP4_HEAD)) + ICMP_ERROR_PACKET_LENGTH; + + // + // Allocate buffer for the icmp error message. + // + Packet = NetbufAlloc (Len); + if (Packet == NULL) { + return; + } + + // + // Allocate space for the IP4_ICMP_ERROR_HEAD. + // + IcmpErrHdr = (IP4_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE); + ASSERT (IcmpErrHdr != NULL); + + // + // Set the required fields for the icmp port unreachable message. + // + IcmpErrHdr->Head.Type = ICMP_TYPE_UNREACH; + IcmpErrHdr->Head.Code = ICMP_CODE_UNREACH_PORT; + IcmpErrHdr->Head.Checksum = 0; + IcmpErrHdr->Fourth = 0; + + // + // Copy the IP header of the datagram tragged the error. + // + CopyMem (&IcmpErrHdr->IpHead, IpHdr, EFI_IP4_HEADER_LEN (IpHdr)); + + // + // Copy the UDP header. + // + Ptr = (UINT8 *) &IcmpErrHdr->IpHead + EFI_IP4_HEADER_LEN (IpHdr); + CopyMem (Ptr, Udp4Header, ICMP_ERROR_PACKET_LENGTH); + + // + // Calculate the checksum. + // + IcmpErrHdr->Head.Checksum = (UINT16) ~(NetbufChecksum (Packet)); + + // + // Fill the override data. + // + Override.Ip4OverrideData.DoNotFragment = FALSE; + Override.Ip4OverrideData.TypeOfService = 0; + Override.Ip4OverrideData.TimeToLive = 255; + Override.Ip4OverrideData.Protocol = EFI_IP_PROTO_ICMP; + + CopyMem (&Override.Ip4OverrideData.SourceAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS)); + ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS)); + + // + // Send out this icmp packet. + // + IpIoSend (IpIo, Packet, IpSender, NULL, NULL, &NetSession->Source, &Override); + + NetbufFree (Packet); +} + + +/** + This function handles the received Icmp Error message and demultiplexes it to the + instance. + + @param[in] Udp4Service Pointer to the udp service context data. + @param[in] IcmpError The icmp error code. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted + from the received Icmp Error packet. + @param[in] Packet Pointer to the Icmp Error packet. + +**/ +VOID +Udp4IcmpHandler ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet + ) +{ + EFI_UDP_HEADER *Udp4Header; + EFI_UDP4_SESSION_DATA Udp4Session; + LIST_ENTRY *Entry; + UDP4_INSTANCE_DATA *Instance; + + if (Packet->TotalSize < sizeof (EFI_UDP_HEADER)) { + NetbufFree (Packet); + return; + } + + Udp4Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL); + ASSERT (Udp4Header != NULL); + + CopyMem (&Udp4Session.SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Udp4Session.DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS)); + + Udp4Session.SourcePort = NTOHS (Udp4Header->DstPort); + Udp4Session.DestinationPort = NTOHS (Udp4Header->SrcPort); + + NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) { + // + // Iterate all the instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link); + + if (!Instance->Configured) { + continue; + } + + if (Udp4MatchDgram (Instance, &Udp4Session)) { + // + // Translate the Icmp Error code according to the udp spec. + // + Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, IP_VERSION_4, NULL, NULL); + + if (IcmpError > ICMP_ERR_UNREACH_PORT) { + Instance->IcmpError = EFI_ICMP_ERROR; + } + + // + // Notify the instance with the received Icmp Error. + // + Udp4ReportIcmpError (Instance); + + break; + } + } + + NetbufFree (Packet); +} + + +/** + This function reports the received ICMP error. + + @param[in] Instance Pointer to the udp instance context data. + +**/ +VOID +Udp4ReportIcmpError ( + IN UDP4_INSTANCE_DATA *Instance + ) +{ + EFI_UDP4_COMPLETION_TOKEN *Token; + + if (NetMapIsEmpty (&Instance->RxTokens)) { + // + // There are no receive tokens to deliver the ICMP error. + // + return; + } + + if (EFI_ERROR (Instance->IcmpError)) { + // + // Try to get a RxToken from the RxTokens map. + // + Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL); + + if (Token != NULL) { + // + // Report the error through the Token. + // + Token->Status = Instance->IcmpError; + gBS->SignalEvent (Token->Event); + + // + // Clear the IcmpError. + // + Instance->IcmpError = EFI_SUCCESS; + } + } +} + + +/** + This function is a dummy ext-free function for the NET_BUF created for the output + udp datagram. + + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp4NetVectorExtFree ( + VOID *Context + ) +{ +} + diff --git a/NetworkPkg/Udp4Dxe/Udp4Impl.h b/NetworkPkg/Udp4Dxe/Udp4Impl.h new file mode 100644 index 0000000000..a5dd1ecabe --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Impl.h @@ -0,0 +1,689 @@ +/** @file + EFI UDPv4 protocol implementation. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UDP4_IMPL_H_ +#define _UDP4_IMPL_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Udp4Driver.h" + + +extern EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gUdp4ComponentName2; +extern EFI_UNICODE_STRING_TABLE *gUdpControllerNameTable; +extern EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding; +extern EFI_UDP4_PROTOCOL mUdp4Protocol; +extern UINT16 mUdp4RandomPort; + +#define ICMP_ERROR_PACKET_LENGTH 8 + +#define UDP4_TIMEOUT_INTERVAL (50 * TICKS_PER_MS) // 50 milliseconds + +#define UDP4_HEADER_SIZE sizeof (EFI_UDP_HEADER) +#define UDP4_MAX_DATA_SIZE 65507 + +#define UDP4_PORT_KNOWN 1024 + +#define UDP4_SERVICE_DATA_SIGNATURE SIGNATURE_32('U', 'd', 'p', '4') + +#define UDP4_SERVICE_DATA_FROM_THIS(a) \ + CR ( \ + (a), \ + UDP4_SERVICE_DATA, \ + ServiceBinding, \ + UDP4_SERVICE_DATA_SIGNATURE \ + ) + +typedef struct _UDP4_SERVICE_DATA_ { + UINT32 Signature; + EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; + EFI_HANDLE ImageHandle; + EFI_HANDLE ControllerHandle; + LIST_ENTRY ChildrenList; + UINTN ChildrenNumber; + IP_IO *IpIo; + + EFI_EVENT TimeoutEvent; +} UDP4_SERVICE_DATA; + +#define UDP4_INSTANCE_DATA_SIGNATURE SIGNATURE_32('U', 'd', 'p', 'I') + +#define UDP4_INSTANCE_DATA_FROM_THIS(a) \ + CR ( \ + (a), \ + UDP4_INSTANCE_DATA, \ + Udp4Proto, \ + UDP4_INSTANCE_DATA_SIGNATURE \ + ) + +typedef struct _UDP4_INSTANCE_DATA_ { + UINT32 Signature; + LIST_ENTRY Link; + + UDP4_SERVICE_DATA *Udp4Service; + EFI_UDP4_PROTOCOL Udp4Proto; + EFI_UDP4_CONFIG_DATA ConfigData; + EFI_HANDLE ChildHandle; + BOOLEAN Configured; + BOOLEAN IsNoMapping; + + NET_MAP TxTokens; + NET_MAP RxTokens; + + NET_MAP McastIps; + + LIST_ENTRY RcvdDgramQue; + LIST_ENTRY DeliveredDgramQue; + + UINT16 HeadSum; + + EFI_STATUS IcmpError; + + IP_IO_IP_INFO *IpInfo; + + BOOLEAN InDestroy; +} UDP4_INSTANCE_DATA; + +typedef struct _UDP4_RXDATA_WRAP_ { + LIST_ENTRY Link; + NET_BUF *Packet; + UINT32 TimeoutTick; + EFI_UDP4_RECEIVE_DATA RxData; +} UDP4_RXDATA_WRAP; + +typedef struct { + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + UINTN NumberOfChildren; + EFI_HANDLE *ChildHandleBuffer; +} UDP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT; + +/** + Reads the current operational settings. + + The GetModeData() function copies the current operational settings of this EFI + UDPv4 Protocol instance into user-supplied buffers. This function is used + optionally to retrieve the operational mode data of underlying networks or + drivers. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[out] Udp4ConfigData Pointer to the buffer to receive the current configuration data. + @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure. + @param[out] MnpConfigData Pointer to the managed network configuration data structure. + @param[out] SnpModeData Pointer to the simple network mode data structure. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED When Udp4ConfigData is queried, no configuration data is + available because this instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +EFI_STATUS +EFIAPI +Udp4GetModeData ( + IN EFI_UDP4_PROTOCOL *This, + OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Initializes, changes, or resets the operational parameters for this instance of the EFI UDPv4 + Protocol. + + The Configure() function is used to do the following: + * Initialize and start this instance of the EFI UDPv4 Protocol. + * Change the filtering rules and operational parameters. + * Reset this instance of the EFI UDPv4 Protocol. + Until these parameters are initialized, no network traffic can be sent or + received by this instance. This instance can be also reset by calling Configure() + with UdpConfigData set to NULL. Once reset, the receiving queue and transmitting + queue are flushed and no traffic is allowed through this instance. + With different parameters in UdpConfigData, Configure() can be used to bind + this instance to specified port. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] UdpConfigData Pointer to the buffer to receive the current configuration data. + + @retval EFI_SUCCESS The configuration settings were set, changed, or reset successfully. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + @retval EFI_ALREADY_STARTED The EFI UDPv4 Protocol instance is already started/configured + and must be stopped/reset before it can be reconfigured. + @retval EFI_ACCESS_DENIED UdpConfigData. AllowDuplicatePort is FALSE + and UdpConfigData.StationPort is already used by + other instance. + @retval EFI_OUT_OF_RESOURCES The EFI UDPv4 Protocol driver cannot allocate memory for this + EFI UDPv4 Protocol instance. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred and this instance + was not opened. + +**/ +EFI_STATUS +EFIAPI +Udp4Configure ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL + ); + +/** + Joins and leaves multicast groups. + + The Groups() function is used to enable and disable the multicast group + filtering. If the JoinFlag is FALSE and the MulticastAddress is NULL, then all + currently joined groups are left. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] JoinFlag Set to TRUE to join a multicast group. Set to FALSE to leave one + or all multicast groups. + @param[in] MulticastAddress Pointer to multicast group address to join or leave. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_OUT_OF_RESOURCES Could not allocate resources to join the group. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - JoinFlag is TRUE and MulticastAddress is NULL. + - JoinFlag is TRUE and *MulticastAddress is not + a valid multicast address. + @retval EFI_ALREADY_STARTED The group address is already in the group table (when + JoinFlag is TRUE). + @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is + FALSE). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +EFI_STATUS +EFIAPI +Udp4Groups ( + IN EFI_UDP4_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL + ); + +/** + Adds and deletes routing table entries. + + The Routes() function adds a route to or deletes a route from the routing table. + Routes are determined by comparing the SubnetAddress with the destination IP + address and arithmetically AND-ing it with the SubnetMask. The gateway address + must be on the same subnet as the configured station address. + The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0. + The default route matches all destination IP addresses that do not match any + other routes. + A zero GatewayAddress is a nonroute. Packets are sent to the destination IP + address if it can be found in the Address Resolution Protocol (ARP) cache or + on the local subnet. One automatic nonroute entry will be inserted into the + routing table for outgoing packets that are addressed to a local subnet + (gateway address of 0.0.0.0). + Each instance of the EFI UDPv4 Protocol has its own independent routing table. + Instances of the EFI UDPv4 Protocol that use the default IP address will also + have copies of the routing table provided by the EFI_IP4_CONFIG_PROTOCOL. These + copies will be updated automatically whenever the IP driver reconfigures its + instances; as a result, the previous modification to these copies will be lost. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. + Set to FALSE to add this route to the routing table. + @param[in] SubnetAddress The destination network address that needs to be routed. + @param[in] SubnetMask The subnet mask of SubnetAddress. + @param[in] GatewayAddress The gateway IP address for this route. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + - RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table. + @retval EFI_NOT_FOUND This route is not in the routing table. + @retval EFI_ACCESS_DENIED The route is already defined in the routing table. + +**/ +EFI_STATUS +EFIAPI +Udp4Routes ( + IN EFI_UDP4_PROTOCOL *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ); + +/** + Queues outgoing data packets into the transmit queue. + + The Transmit() function places a sending request to this instance of the EFI + UDPv4 Protocol, alongside the transmit data that was filled by the user. Whenever + the packet in the token is sent out or some errors occur, the Token.Event will + be signaled and Token.Status is updated. Providing a proper notification function + and context for the event will enable the user to receive the notification and + transmitting status. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] Token Pointer to the completion token that will be placed into the + transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED The transmit completion token with the same + Token.Event was already in the transmit queue. + @retval EFI_NOT_READY The completion token could not be queued because the + transmit queue is full. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data. + @retval EFI_NOT_FOUND There is no route to the destination network or address. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP packet + size. Or the length of the IP header + UDP header + data + length is greater than MTU if DoNotFragment is TRUE. + +**/ +EFI_STATUS +EFIAPI +Udp4Transmit ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +/** + Places an asynchronous receive request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. + This function is always asynchronous. + The caller must fill in the Token.Event field in the completion token, and this + field cannot be NULL. When the receive operation completes, the EFI UDPv4 Protocol + driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event + is signaled. Providing a proper notification function and context for the event + will enable the user to receive the notification and receiving status. That + notification function is guaranteed to not be re-entered. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] Token Pointer to a token that is associated with + the receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, RARP, etc.) + is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system + resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_ACCESS_DENIED A receive completion token with the same Token.Event was already in + the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +EFI_STATUS +EFIAPI +Udp4Receive ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +/** + Aborts an asynchronous transmit or receive request. + + The Cancel() function is used to abort a pending transmit or receive request. + If the token is in the transmit or receive request queues, after calling this + function, Token.Status will be set to EFI_ABORTED and then Token.Event will be + signaled. If the token is not in one of the queues, which usually means that + the asynchronous operation has completed, this function will not signal the + token and EFI_NOT_FOUND is returned. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_UDP4_PROTOCOL.Transmit() or + EFI_UDP4_PROTOCOL.Receive().If NULL, all pending + tokens are aborted. + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and Token.Event + was signaled. When Token is NULL, all pending requests are + aborted and their events are signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was + not found in the transmit or receive queue. It has either completed + or was not issued by Transmit() and Receive(). + +**/ +EFI_STATUS +EFIAPI +Udp4Cancel ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase + the rate that data packets are moved between the communications device and the + transmit and receive queues. + In some systems, the periodic timer event in the managed network driver may not + poll the underlying communications device fast enough to transmit and/or receive + all data packets without missing incoming packets or dropping outgoing packets. + Drivers and applications that are experiencing packet loss should try calling + the Poll() function more often. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + +**/ +EFI_STATUS +EFIAPI +Udp4Poll ( + IN EFI_UDP4_PROTOCOL *This + ); + +/** + Create the Udp service context data. + + @param[in, out] Udp4Service Pointer to the UDP4_SERVICE_DATA. + @param[in] ImageHandle The image handle of this udp4 driver. + @param[in] ControllerHandle The controller handle this udp4 driver binds on. + + @retval EFI_SUCCESS The udp4 service context data is created and + initialized. + @retval EFI_OUT_OF_RESOURCES Cannot allocate memory. + @retval other Other error occurs. + +**/ +EFI_STATUS +Udp4CreateService ( + IN OUT UDP4_SERVICE_DATA *Udp4Service, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle + ); + +/** + Clean the Udp service context data. + + @param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA. + +**/ +VOID +Udp4CleanService ( + IN UDP4_SERVICE_DATA *Udp4Service + ); + +/** + This function intializes the new created udp instance. + + @param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA. + @param[in, out] Instance Pointer to the un-initialized UDP4_INSTANCE_DATA. + +**/ +VOID +Udp4InitInstance ( + IN UDP4_SERVICE_DATA *Udp4Service, + IN OUT UDP4_INSTANCE_DATA *Instance + ); + +/** + This function cleans the udp instance. + + @param[in] Instance Pointer to the UDP4_INSTANCE_DATA to clean. + +**/ +VOID +Udp4CleanInstance ( + IN UDP4_INSTANCE_DATA *Instance + ); + +/** + This function tries to bind the udp instance according to the configured port + allocation strategy. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in, out] ConfigData Pointer to the ConfigData of the instance to be + bound. ConfigData->StationPort will be assigned + with an available port value on success. + + @retval EFI_SUCCESS The bound operation is completed successfully. + @retval EFI_ACCESS_DENIED The specified by the ConfigData is + already used by other instance. + @retval EFI_OUT_OF_RESOURCES No available port resources. + +**/ +EFI_STATUS +Udp4Bind ( + IN LIST_ENTRY *InstanceList, + IN OUT EFI_UDP4_CONFIG_DATA *ConfigData + ); + +/** + This function is used to check whether the NewConfigData has any un-reconfigurable + parameters changed compared to the OldConfigData. + + @param[in] OldConfigData Pointer to the current ConfigData the udp instance + uses. + @param[in] NewConfigData Pointer to the new ConfigData. + + @retval TRUE The instance is reconfigurable. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp4IsReconfigurable ( + IN EFI_UDP4_CONFIG_DATA *OldConfigData, + IN EFI_UDP4_CONFIG_DATA *NewConfigData + ); + +/** + This function builds the Ip4 configdata from the Udp4ConfigData. + + @param[in] Udp4ConfigData Pointer to the EFI_UDP4_CONFIG_DATA. + @param[in, out] Ip4ConfigData Pointer to the EFI_IP4_CONFIG_DATA. + +**/ +VOID +Udp4BuildIp4ConfigData ( + IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData, + IN OUT EFI_IP4_CONFIG_DATA *Ip4ConfigData + ); + +/** + This function validates the TxToken, it returns the error code according to the spec. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] TxToken Pointer to the token to be checked. + + @retval EFI_SUCCESS The TxToken is valid. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: This is + NULL. Token is NULL. Token.Event is NULL. + Token.Packet.TxData is NULL. + Token.Packet.TxData.FragmentCount is zero. + Token.Packet.TxData.DataLength is not equal to the + sum of fragment lengths. One or more of the + Token.Packet.TxData.FragmentTable[]. + FragmentLength fields is zero. One or more of the + Token.Packet.TxData.FragmentTable[]. + FragmentBuffer fields is NULL. + Token.Packet.TxData. GatewayAddress is not a + unicast IPv4 address if it is not NULL. One or + more IPv4 addresses in Token.Packet.TxData. + UdpSessionData are not valid unicast IPv4 + addresses if the UdpSessionData is not NULL. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP + packet size. + +**/ +EFI_STATUS +Udp4ValidateTxToken ( + IN UDP4_INSTANCE_DATA *Instance, + IN EFI_UDP4_COMPLETION_TOKEN *TxToken + ); + +/** + This function checks whether the specified Token duplicates with the one in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM contain the pointer to + the Token. + @param[in] Context Pointer to the Token to be checked. + + @retval EFI_SUCCESS The Token specified by Context differs from the + one in the Item. + @retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item. + +**/ +EFI_STATUS +EFIAPI +Udp4TokenExist ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Context + ); + +/** + This function calculates the checksum for the Packet, utilizing the pre-calculated + pseudo HeadSum to reduce some overhead. + + @param[in] Packet Pointer to the NET_BUF contains the udp datagram. + @param[in] HeadSum Checksum of the pseudo header execpt the length + field. + + @retval The 16-bit checksum of this udp datagram. + +**/ +UINT16 +Udp4Checksum ( + IN NET_BUF *Packet, + IN UINT16 HeadSum + ); + +/** + This function removes the specified Token from the TokenMap. + + @param[in, out] TokenMap Pointer to the NET_MAP containing the tokens. + @param[in] Token Pointer to the Token to be removed. + + @retval EFI_SUCCESS The specified Token is removed from the TokenMap. + @retval EFI_NOT_FOUND The specified Token is not found in the TokenMap. + +**/ +EFI_STATUS +Udp4RemoveToken ( + IN OUT NET_MAP *TokenMap, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +/** + This function removes the multicast group specified by Arg from the Map. + + @param[in, out] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the Arg, it's the pointer to a + multicast IPv4 Address. + + @retval EFI_SUCCESS The multicast address is removed. + @retval EFI_ABORTED The specified multicast address is removed and the + Arg is not NULL. + +**/ +EFI_STATUS +EFIAPI +Udp4LeaveGroup ( + IN OUT NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ); + +/** + This function removes all the Wrap datas in the RcvdDgramQue. + + @param[in] Instance Pointer to the udp instance context data. + +**/ +VOID +Udp4FlushRcvdDgram ( + IN UDP4_INSTANCE_DATA *Instance + ); + +/** + Cancel Udp4 tokens from the Udp4 instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Token Pointer to the token to be canceled, if NULL, all + tokens in this instance will be cancelled. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Udp4InstanceCancelToken ( + IN UDP4_INSTANCE_DATA *Instance, + IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + This function delivers the received datagrams for the specified instance. + + @param[in] Instance Pointer to the instance context data. + +**/ +VOID +Udp4InstanceDeliverDgram ( + IN UDP4_INSTANCE_DATA *Instance + ); + +/** + This function reports the received ICMP error. + + @param[in] Instance Pointer to the udp instance context data. + +**/ +VOID +Udp4ReportIcmpError ( + IN UDP4_INSTANCE_DATA *Instance + ); + +/** + This function is a dummy ext-free function for the NET_BUF created for the output + udp datagram. + + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp4NetVectorExtFree ( + VOID *Context + ); + +#endif diff --git a/NetworkPkg/Udp4Dxe/Udp4Main.c b/NetworkPkg/Udp4Dxe/Udp4Main.c new file mode 100644 index 0000000000..aa1956cd4b --- /dev/null +++ b/NetworkPkg/Udp4Dxe/Udp4Main.c @@ -0,0 +1,902 @@ +/** @file + +(C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Udp4Impl.h" + +EFI_UDP4_PROTOCOL mUdp4Protocol = { + Udp4GetModeData, + Udp4Configure, + Udp4Groups, + Udp4Routes, + Udp4Transmit, + Udp4Receive, + Udp4Cancel, + Udp4Poll +}; + + +/** + Reads the current operational settings. + + The GetModeData() function copies the current operational settings of this EFI + UDPv4 Protocol instance into user-supplied buffers. This function is used + optionally to retrieve the operational mode data of underlying networks or + drivers. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[out] Udp4ConfigData Pointer to the buffer to receive the current configuration data. + @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure. + @param[out] MnpConfigData Pointer to the managed network configuration data structure. + @param[out] SnpModeData Pointer to the simple network mode data structure. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED When Udp4ConfigData is queried, no configuration data is + available because this instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +EFI_STATUS +EFIAPI +Udp4GetModeData ( + IN EFI_UDP4_PROTOCOL *This, + OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ) +{ + UDP4_INSTANCE_DATA *Instance; + EFI_IP4_PROTOCOL *Ip; + EFI_TPL OldTpl; + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured && (Udp4ConfigData != NULL)) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (Udp4ConfigData != NULL) { + // + // Set the Udp4ConfigData. + // + CopyMem (Udp4ConfigData, &Instance->ConfigData, sizeof (*Udp4ConfigData)); + } + + Ip = Instance->IpInfo->Ip.Ip4; + + // + // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData. + // + Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Initializes, changes, or resets the operational parameters for this instance of the EFI UDPv4 + Protocol. + + The Configure() function is used to do the following: + * Initialize and start this instance of the EFI UDPv4 Protocol. + * Change the filtering rules and operational parameters. + * Reset this instance of the EFI UDPv4 Protocol. + Until these parameters are initialized, no network traffic can be sent or + received by this instance. This instance can be also reset by calling Configure() + with UdpConfigData set to NULL. Once reset, the receiving queue and transmitting + queue are flushed and no traffic is allowed through this instance. + With different parameters in UdpConfigData, Configure() can be used to bind + this instance to specified port. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] UdpConfigData Pointer to the buffer to receive the current configuration data. + + @retval EFI_SUCCESS The configuration settings were set, changed, or reset successfully. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + @retval EFI_ALREADY_STARTED The EFI UDPv4 Protocol instance is already started/configured + and must be stopped/reset before it can be reconfigured. + @retval EFI_ACCESS_DENIED UdpConfigData. AllowDuplicatePort is FALSE + and UdpConfigData.StationPort is already used by + other instance. + @retval EFI_OUT_OF_RESOURCES The EFI UDPv4 Protocol driver cannot allocate memory for this + EFI UDPv4 Protocol instance. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred and this instance + was not opened. + +**/ +EFI_STATUS +EFIAPI +Udp4Configure ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL + ) +{ + EFI_STATUS Status; + UDP4_INSTANCE_DATA *Instance; + UDP4_SERVICE_DATA *Udp4Service; + EFI_TPL OldTpl; + IP4_ADDR StationAddress; + IP4_ADDR SubnetMask; + IP4_ADDR RemoteAddress; + EFI_IP4_CONFIG_DATA Ip4ConfigData; + IP4_ADDR LocalAddr; + IP4_ADDR RemoteAddr; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured && (UdpConfigData == NULL)) { + return EFI_SUCCESS; + } + + Udp4Service = Instance->Udp4Service; + Status = EFI_SUCCESS; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (UdpConfigData != NULL) { + + CopyMem (&StationAddress, &UdpConfigData->StationAddress, sizeof (IP4_ADDR)); + CopyMem (&SubnetMask, &UdpConfigData->SubnetMask, sizeof (IP4_ADDR)); + CopyMem (&RemoteAddress, &UdpConfigData->RemoteAddress, sizeof (IP4_ADDR)); + + StationAddress = NTOHL (StationAddress); + SubnetMask = NTOHL (SubnetMask); + RemoteAddress = NTOHL (RemoteAddress); + + + if (!UdpConfigData->UseDefaultAddress && + (!IP4_IS_VALID_NETMASK (SubnetMask) || + !((StationAddress == 0) || (SubnetMask != 0 && NetIp4IsUnicast (StationAddress, SubnetMask))) || + IP4_IS_LOCAL_BROADCAST (RemoteAddress))) { + // + // Don't use default address, and subnet mask is invalid or StationAddress is not + // a valid unicast IPv4 address or RemoteAddress is not a valid unicast IPv4 address + // if it is not 0. + // + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + if (Instance->Configured) { + // + // The instance is already configured, try to do the re-configuration. + // + if (!Udp4IsReconfigurable (&Instance->ConfigData, UdpConfigData)) { + // + // If the new configuration data wants to change some unreconfigurable + // settings, return EFI_ALREADY_STARTED. + // + Status = EFI_ALREADY_STARTED; + goto ON_EXIT; + } + + // + // Save the reconfigurable parameters. + // + Instance->ConfigData.TypeOfService = UdpConfigData->TypeOfService; + Instance->ConfigData.TimeToLive = UdpConfigData->TimeToLive; + Instance->ConfigData.DoNotFragment = UdpConfigData->DoNotFragment; + Instance->ConfigData.ReceiveTimeout = UdpConfigData->ReceiveTimeout; + Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout; + } else { + // + // Construct the Ip configuration data from the UdpConfigData. + // + Udp4BuildIp4ConfigData (UdpConfigData, &Ip4ConfigData); + + // + // Configure the Ip instance wrapped in the IpInfo. + // + Status = IpIoConfigIp (Instance->IpInfo, &Ip4ConfigData); + if (EFI_ERROR (Status)) { + if (Status == EFI_NO_MAPPING) { + Instance->IsNoMapping = TRUE; + } + + goto ON_EXIT; + } + + Instance->IsNoMapping = FALSE; + + // + // Save the configuration data. + // + CopyMem (&Instance->ConfigData, UdpConfigData, sizeof (Instance->ConfigData)); + IP4_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip4ConfigData.StationAddress); + IP4_COPY_ADDRESS (&Instance->ConfigData.SubnetMask, &Ip4ConfigData.SubnetMask); + + // + // Try to allocate the required port resource. + // + Status = Udp4Bind (&Udp4Service->ChildrenList, &Instance->ConfigData); + if (EFI_ERROR (Status)) { + // + // Reset the ip instance if bind fails. + // + IpIoConfigIp (Instance->IpInfo, NULL); + goto ON_EXIT; + } + + // + // Pre calculate the checksum for the pseudo head, ignore the UDP length first. + // + CopyMem (&LocalAddr, &Instance->ConfigData.StationAddress, sizeof (IP4_ADDR)); + CopyMem (&RemoteAddr, &Instance->ConfigData.RemoteAddress, sizeof (IP4_ADDR)); + Instance->HeadSum = NetPseudoHeadChecksum ( + LocalAddr, + RemoteAddr, + EFI_IP_PROTO_UDP, + 0 + ); + + Instance->Configured = TRUE; + } + } else { + // + // UdpConfigData is NULL, reset the instance. + // + Instance->Configured = FALSE; + Instance->IsNoMapping = FALSE; + + // + // Reset the Ip instance wrapped in the IpInfo. + // + IpIoConfigIp (Instance->IpInfo, NULL); + + // + // Cancel all the user tokens. + // + Instance->Udp4Proto.Cancel (&Instance->Udp4Proto, NULL); + + // + // Remove the buffered RxData for this instance. + // + Udp4FlushRcvdDgram (Instance); + + ASSERT (IsListEmpty (&Instance->DeliveredDgramQue)); + } + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Joins and leaves multicast groups. + + The Groups() function is used to enable and disable the multicast group + filtering. If the JoinFlag is FALSE and the MulticastAddress is NULL, then all + currently joined groups are left. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] JoinFlag Set to TRUE to join a multicast group. Set to FALSE to leave one + or all multicast groups. + @param[in] MulticastAddress Pointer to multicast group address to join or leave. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_OUT_OF_RESOURCES Could not allocate resources to join the group. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - JoinFlag is TRUE and MulticastAddress is NULL. + - JoinFlag is TRUE and *MulticastAddress is not + a valid multicast address. + @retval EFI_ALREADY_STARTED The group address is already in the group table (when + JoinFlag is TRUE). + @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is + FALSE). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +EFI_STATUS +EFIAPI +Udp4Groups ( + IN EFI_UDP4_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL + ) +{ + EFI_STATUS Status; + UDP4_INSTANCE_DATA *Instance; + EFI_IP4_PROTOCOL *Ip; + EFI_TPL OldTpl; + IP4_ADDR McastIp; + + if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) { + return EFI_INVALID_PARAMETER; + } + + McastIp = 0; + if (JoinFlag) { + CopyMem (&McastIp, MulticastAddress, sizeof (IP4_ADDR)); + + if (!IP4_IS_MULTICAST (NTOHL (McastIp))) { + return EFI_INVALID_PARAMETER; + } + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (Instance->IsNoMapping) { + return EFI_NO_MAPPING; + } + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + Ip = Instance->IpInfo->Ip.Ip4; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Invoke the Ip instance the Udp4 instance consumes to do the group operation. + // + Status = Ip->Groups (Ip, JoinFlag, MulticastAddress); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Keep a local copy of the configured multicast IPs because IpIo receives + // datagrams from the 0 station address IP instance and then UDP delivers to + // the matched instance. This copy of multicast IPs is used to avoid receive + // the mutlicast datagrams destined to multicast IPs the other instances configured. + // + if (JoinFlag) { + + NetMapInsertTail (&Instance->McastIps, (VOID *) (UINTN) McastIp, NULL); + } else { + + NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress); + } + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Adds and deletes routing table entries. + + The Routes() function adds a route to or deletes a route from the routing table. + Routes are determined by comparing the SubnetAddress with the destination IP + address and arithmetically AND-ing it with the SubnetMask. The gateway address + must be on the same subnet as the configured station address. + The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0. + The default route matches all destination IP addresses that do not match any + other routes. + A zero GatewayAddress is a nonroute. Packets are sent to the destination IP + address if it can be found in the Address Resolution Protocol (ARP) cache or + on the local subnet. One automatic nonroute entry will be inserted into the + routing table for outgoing packets that are addressed to a local subnet + (gateway address of 0.0.0.0). + Each instance of the EFI UDPv4 Protocol has its own independent routing table. + Instances of the EFI UDPv4 Protocol that use the default IP address will also + have copies of the routing table provided by the EFI_IP4_CONFIG_PROTOCOL. These + copies will be updated automatically whenever the IP driver reconfigures its + instances; as a result, the previous modification to these copies will be lost. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. + Set to FALSE to add this route to the routing table. + @param[in] SubnetAddress The destination network address that needs to be routed. + @param[in] SubnetMask The subnet mask of SubnetAddress. + @param[in] GatewayAddress The gateway IP address for this route. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + - RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table. + @retval EFI_NOT_FOUND This route is not in the routing table. + @retval EFI_ACCESS_DENIED The route is already defined in the routing table. + +**/ +EFI_STATUS +EFIAPI +Udp4Routes ( + IN EFI_UDP4_PROTOCOL *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ) +{ + UDP4_INSTANCE_DATA *Instance; + EFI_IP4_PROTOCOL *Ip; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (Instance->IsNoMapping) { + return EFI_NO_MAPPING; + } + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + Ip = Instance->IpInfo->Ip.Ip4; + + // + // Invoke the Ip instance the Udp4 instance consumes to do the actual operation. + // + return Ip->Routes (Ip, DeleteRoute, SubnetAddress, SubnetMask, GatewayAddress); +} + + +/** + Queues outgoing data packets into the transmit queue. + + The Transmit() function places a sending request to this instance of the EFI + UDPv4 Protocol, alongside the transmit data that was filled by the user. Whenever + the packet in the token is sent out or some errors occur, the Token.Event will + be signaled and Token.Status is updated. Providing a proper notification function + and context for the event will enable the user to receive the notification and + transmitting status. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] Token Pointer to the completion token that will be placed into the + transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED The transmit completion token with the same + Token.Event was already in the transmit queue. + @retval EFI_NOT_READY The completion token could not be queued because the + transmit queue is full. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data. + @retval EFI_NOT_FOUND There is no route to the destination network or address. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP packet + size. Or the length of the IP header + UDP header + data + length is greater than MTU if DoNotFragment is TRUE. + +**/ +EFI_STATUS +EFIAPI +Udp4Transmit ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + UDP4_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + NET_BUF *Packet; + EFI_UDP_HEADER *Udp4Header; + EFI_UDP4_CONFIG_DATA *ConfigData; + IP4_ADDR Source; + IP4_ADDR Destination; + EFI_UDP4_TRANSMIT_DATA *TxData; + EFI_UDP4_SESSION_DATA *UdpSessionData; + UDP4_SERVICE_DATA *Udp4Service; + IP_IO_OVERRIDE Override; + UINT16 HeadSum; + EFI_IP_ADDRESS IpDestAddr; + + if ((This == NULL) || (Token == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (Instance->IsNoMapping) { + return EFI_NO_MAPPING; + } + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Validate the Token, if the token is invalid return the error code. + // + Status = Udp4ValidateTxToken (Instance, Token); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)) || + EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))) { + // + // Try to find a duplicate token in the two token maps, if found, return + // EFI_ACCESS_DENIED. + // + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + TxData = Token->Packet.TxData; + + // + // Create a net buffer to hold the user buffer and the udp header. + // + Packet = NetbufFromExt ( + (NET_FRAGMENT *)TxData->FragmentTable, + TxData->FragmentCount, + UDP4_HEADER_SIZE, + 0, + Udp4NetVectorExtFree, + NULL + ); + if (Packet == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Store the IpIo in ProtoData. + // + Udp4Service = Instance->Udp4Service; + *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp4Service->IpIo); + + Udp4Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE); + ASSERT (Udp4Header != NULL); + + ConfigData = &Instance->ConfigData; + + // + // Fill the udp header. + // + Udp4Header->SrcPort = HTONS (ConfigData->StationPort); + Udp4Header->DstPort = HTONS (ConfigData->RemotePort); + Udp4Header->Length = HTONS ((UINT16) Packet->TotalSize); + Udp4Header->Checksum = 0; + + UdpSessionData = TxData->UdpSessionData; + IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &ConfigData->StationAddress); + + if (UdpSessionData != NULL) { + // + // Set the SourceAddress, SrcPort and Destination according to the specified + // UdpSessionData. + // + if (!EFI_IP4_EQUAL (&UdpSessionData->SourceAddress, &mZeroIp4Addr)) { + IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &UdpSessionData->SourceAddress); + } + + if (UdpSessionData->SourcePort != 0) { + Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort); + } + + if (UdpSessionData->DestinationPort != 0) { + Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort); + } + + CopyMem (&Source, &Override.Ip4OverrideData.SourceAddress, sizeof (IP4_ADDR)); + CopyMem (&Destination, &UdpSessionData->DestinationAddress, sizeof (IP4_ADDR)); + + // + // calculate the pseudo head checksum using the overridden parameters. + // + HeadSum = NetPseudoHeadChecksum ( + Source, + Destination, + EFI_IP_PROTO_UDP, + 0 + ); + } else { + // + // UdpSessionData is NULL, use the address and port information previously configured. + // + CopyMem (&Destination, &ConfigData->RemoteAddress, sizeof (IP4_ADDR)); + + HeadSum = Instance->HeadSum; + } + + // + // calculate the checksum. + // + Udp4Header->Checksum = Udp4Checksum (Packet, HeadSum); + if (Udp4Header->Checksum == 0) { + // + // If the calculated checksum is 0, fill the Checksum field with all ones. + // + Udp4Header->Checksum = 0xffff; + } + + // + // Fill the IpIo Override data. + // + if (TxData->GatewayAddress != NULL) { + IP4_COPY_ADDRESS (&Override.Ip4OverrideData.GatewayAddress, TxData->GatewayAddress); + } else { + ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS)); + } + + Override.Ip4OverrideData.Protocol = EFI_IP_PROTO_UDP; + Override.Ip4OverrideData.TypeOfService = ConfigData->TypeOfService; + Override.Ip4OverrideData.TimeToLive = ConfigData->TimeToLive; + Override.Ip4OverrideData.DoNotFragment = ConfigData->DoNotFragment; + + // + // Save the token into the TxToken map. + // + Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet); + if (EFI_ERROR (Status)) { + goto FREE_PACKET; + } + + // + // Send out this datagram through IpIo. + // + IpDestAddr.Addr[0] = Destination; + Status = IpIoSend ( + Udp4Service->IpIo, + Packet, + Instance->IpInfo, + Instance, + Token, + &IpDestAddr, + &Override + ); + if (EFI_ERROR (Status)) { + // + // Remove this token from the TxTokens. + // + Udp4RemoveToken (&Instance->TxTokens, Token); + } + +FREE_PACKET: + + NetbufFree (Packet); + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Places an asynchronous receive request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. + This function is always asynchronous. + The caller must fill in the Token.Event field in the completion token, and this + field cannot be NULL. When the receive operation completes, the EFI UDPv4 Protocol + driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event + is signaled. Providing a proper notification function and context for the event + will enable the user to receive the notification and receiving status. That + notification function is guaranteed to not be re-entered. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] Token Pointer to a token that is associated with + the receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, RARP, etc.) + is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system + resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_ACCESS_DENIED A receive completion token with the same Token.Event was already in + the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +EFI_STATUS +EFIAPI +Udp4Receive ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + UDP4_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + + if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (Instance->IsNoMapping) { + return EFI_NO_MAPPING; + } + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))|| + EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token))) { + // + // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or + // RxTokens map. + // + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + Token->Packet.RxData = NULL; + + // + // Save the token into the RxTokens map. + // + Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_READY; + goto ON_EXIT; + } + + // + // If there is an icmp error, report it. + // + Udp4ReportIcmpError (Instance); + + // + // Try to deliver the received datagrams. + // + Udp4InstanceDeliverDgram (Instance); + + // + // Dispatch the DPC queued by the NotifyFunction of Token->Event. + // + DispatchDpc (); + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Aborts an asynchronous transmit or receive request. + + The Cancel() function is used to abort a pending transmit or receive request. + If the token is in the transmit or receive request queues, after calling this + function, Token.Status will be set to EFI_ABORTED and then Token.Event will be + signaled. If the token is not in one of the queues, which usually means that + the asynchronous operation has completed, this function will not signal the + token and EFI_NOT_FOUND is returned. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_UDP4_PROTOCOL.Transmit() or + EFI_UDP4_PROTOCOL.Receive().If NULL, all pending + tokens are aborted. + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and Token.Event + was signaled. When Token is NULL, all pending requests are + aborted and their events are signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was + not found in the transmit or receive queue. It has either completed + or was not issued by Transmit() and Receive(). + +**/ +EFI_STATUS +EFIAPI +Udp4Cancel ( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL + ) +{ + EFI_STATUS Status; + UDP4_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + + if (Instance->IsNoMapping) { + return EFI_NO_MAPPING; + } + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Cancle the tokens specified by Token for this instance. + // + Status = Udp4InstanceCancelToken (Instance, Token); + + // + // Dispatch the DPC queued by the NotifyFunction of the cancelled token's events. + // + DispatchDpc (); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase + the rate that data packets are moved between the communications device and the + transmit and receive queues. + In some systems, the periodic timer event in the managed network driver may not + poll the underlying communications device fast enough to transmit and/or receive + all data packets without missing incoming packets or dropping outgoing packets. + Drivers and applications that are experiencing packet loss should try calling + the Poll() function more often. + + @param[in] This Pointer to the EFI_UDP4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + +**/ +EFI_STATUS +EFIAPI +Udp4Poll ( + IN EFI_UDP4_PROTOCOL *This + ) +{ + UDP4_INSTANCE_DATA *Instance; + EFI_IP4_PROTOCOL *Ip; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP4_INSTANCE_DATA_FROM_THIS (This); + Ip = Instance->IpInfo->Ip.Ip4; + + // + // Invode the Ip instance consumed by the udp instance to do the poll operation. + // + return Ip->Poll (Ip); +} -- cgit v1.2.3