summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/Udp4Dxe
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/Network/Udp4Dxe')
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c169
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c526
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h70
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf66
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa77
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c1951
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h299
-rw-r--r--MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c869
8 files changed, 4027 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c b/MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c
new file mode 100644
index 0000000000..b934765207
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/ComponentName.c
@@ -0,0 +1,169 @@
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ ComponentName.c
+
+Abstract:
+
+
+**/
+
+
+#include "Udp4Impl.h"
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+UdpComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+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
+//
+EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName = {
+ UdpComponentNameGetDriverName,
+ UdpComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mUdpDriverNameTable[] = {
+ {
+ "eng",
+ L"UDP Network Service Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+UdpComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+Routine Description:
+
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+Arguments:
+
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ Language - A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that 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.
+ 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.
+
+Returns:
+
+ EFI_SUCCES - The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - DriverName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return LookupUnicodeString (
+ Language,
+ gUdp4ComponentName.SupportedLanguages,
+ mUdpDriverNameTable,
+ DriverName
+ );
+}
+
+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
+ )
+/*++
+
+Routine Description:
+
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+Arguments:
+
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ 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.
+ 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.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that 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.
+ 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.
+
+Returns:
+
+ 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.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ControllerName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c
new file mode 100644
index 0000000000..7b47ef44a9
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c
@@ -0,0 +1,526 @@
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Udp4Driver.c
+
+Abstract:
+
+
+**/
+
+
+#include "Udp4Impl.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = {
+ Udp4DriverBindingSupported,
+ Udp4DriverBindingStart,
+ Udp4DriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding = {
+ Udp4ServiceBindingCreateChild,
+ Udp4ServiceBindingDestroyChild
+};
+
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCES This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on 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.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCES 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 = NetAllocatePool (sizeof (UDP4_SERVICE_DATA));
+ if (Udp4Service == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Udp4CreateService (Udp4Service, This->DriverBindingHandle, ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ goto FREE_SERVICE;
+ }
+
+ //
+ // Install the Udp4ServiceBindingProtocol on the ControllerHandle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ &Udp4Service->ServiceBinding,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto CLEAN_SERVICE;
+ }
+
+ Udp4SetVariableData (Udp4Service);
+
+ return Status;
+
+CLEAN_SERVICE:
+
+ Udp4CleanService (Udp4Service);
+
+FREE_SERVICE:
+
+ NetFreePool (Udp4Service);
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
+ of children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCES 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_INSTANCE_DATA *Instance;
+
+ //
+ // 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);
+
+ //
+ // Uninstall the UDP4 ServiceBinding Protocol.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ NicHandle,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ &Udp4Service->ServiceBinding,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ while (!NetListIsEmpty (&Udp4Service->ChildrenList)) {
+ //
+ // Destroy all instances.
+ //
+ Instance = NET_LIST_HEAD (&Udp4Service->ChildrenList, UDP4_INSTANCE_DATA, Link);
+
+ ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);
+ }
+
+ Udp4ClearVariableData (Udp4Service);
+
+ Udp4CleanService (Udp4Service);
+
+ NetFreePool (Udp4Service);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Creates a child handle with a set of I/O services.
+
+ @param This Protocol instance pointer.
+ @param ChildHandle Pointer to the handle of the child to create. If
+ it is NULL, then a new handle is created. If it
+ is not NULL, then the I/O services are added to
+ the existing child handle.
+
+ @retval EFI_SUCCES The child handle was created with the I/O services
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe 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 = NetAllocatePool (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 FREE_INSTANCE;
+ }
+
+ //
+ // Install the Udp4Protocol for this instance.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiUdp4ProtocolGuid,
+ &Instance->Udp4Proto,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto REMOVE_IPINFO;
+ }
+
+ 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 UNINSTALL_PROTOCOL;
+ }
+
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ //
+ // Link this instance into the service context data and increase the ChildrenNumber.
+ //
+ NetListInsertTail (&Udp4Service->ChildrenList, &Instance->Link);
+ Udp4Service->ChildrenNumber++;
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+
+UNINSTALL_PROTOCOL:
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ Instance->ChildHandle,
+ &gEfiUdp4ProtocolGuid,
+ &Instance->Udp4Proto,
+ NULL
+ );
+
+REMOVE_IPINFO:
+
+ IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);
+
+FREE_INSTANCE:
+
+ Udp4CleanInstance (Instance);
+
+ NetFreePool (Instance);
+
+ return Status;
+}
+
+
+/**
+ Destroys a child handle with a set of I/O services.
+
+ @param This Protocol instance pointer.
+ @param ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCES The I/O services were removed from the child
+ handle
+ @retval EFI_UNSUPPORTED The child handle does not support the I/O services
+ that are being removed
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
+ @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
+ its I/O 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->Destroyed) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Use the Destroyed flag to avoid the re-entering of the following code.
+ //
+ Instance->Destroyed = TRUE;
+
+ //
+ // Close the Ip4 protocol.
+ //
+ gBS->CloseProtocol (
+ Udp4Service->IpIo->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->Destroyed = 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 = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ //
+ // Remove this instance from the service context data's ChildrenList.
+ //
+ NetListRemoveEntry (&Instance->Link);
+ Udp4Service->ChildrenNumber--;
+
+ //
+ // Clean the instance.
+ //
+ Udp4CleanInstance (Instance);
+
+ NET_RESTORE_TPL (OldTpl);
+
+ NetFreePool (Instance);
+
+ return EFI_SUCCESS;
+}
+
+//@MT: EFI_DRIVER_ENTRY_POINT (Udp4DriverEntryPoint)
+
+EFI_STATUS
+EFIAPI
+Udp4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ The entry point for Udp4 driver which installs the driver binding
+ and component name protocol on its ImageHandle.
+
+Arguments:
+
+ ImageHandle - The image handle of the driver.
+ SystemTable - The system table.
+
+Returns:
+
+ EFI_SUCCESS - if the driver binding and component name protocols are
+ successfully installed, otherwise if failed.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Install the Udp4DriverBinding and Udp4ComponentName protocols.
+ //
+ Status = NetLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gUdp4DriverBinding,
+ ImageHandle,
+ &gUdp4ComponentName,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Initialize the UDP random port.
+ //
+ mUdp4RandomPort = ((UINT16) NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN;
+ }
+
+ return Status;
+}
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h
new file mode 100644
index 0000000000..59acb44452
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.h
@@ -0,0 +1,70 @@
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Udp4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _UDP4_DRIVER_H_
+#define _UDP4_DRIVER_H_
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/NetLib.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE *ChildHandle
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
new file mode 100644
index 0000000000..3f97393dc3
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
@@ -0,0 +1,66 @@
+#/** @file
+# Component name for module Udp4
+#
+# FIX ME!
+# Copyright (c) 2006, Intel Corporation. All right reserved.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Udp4
+ FILE_GUID = 6d6963ab-906d-4a65-a7ca-bd40e5d6af2b
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = Udp4DriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ Udp4Impl.h
+ Udp4Main.c
+ ComponentName.c
+ Udp4Impl.c
+ Udp4Driver.h
+ Udp4Driver.c
+ CommonHeader.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ DebugLib
+ IpIoLib
+ NetLib
+
+
+[Protocols]
+ gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa
new file mode 100644
index 0000000000..1415458270
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.msa
@@ -0,0 +1,77 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>Udp4</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>6d6963ab-906d-4a65-a7ca-bd40e5d6af2b</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module Udp4</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>
+ <License>All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>Udp4</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Udp4Driver.c</Filename>
+ <Filename>Udp4Driver.h</Filename>
+ <Filename>Udp4Impl.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>Udp4Main.c</Filename>
+ <Filename>Udp4Impl.h</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>Udp4DriverEntryPoint</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea> \ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c
new file mode 100644
index 0000000000..dd7522e91f
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c
@@ -0,0 +1,1951 @@
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Udp4Impl.c
+
+Abstract:
+
+ The implementation of the Udp4 protocol.
+
+
+**/
+
+
+#include "Udp4Impl.h"
+
+UINT16 mUdp4RandomPort;
+
+STATIC
+VOID
+EFIAPI
+Udp4CheckTimeout (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+STATIC
+BOOLEAN
+Udp4FindInstanceByPort (
+ IN NET_LIST_ENTRY *InstanceList,
+ IN EFI_IPv4_ADDRESS *Address,
+ IN UINT16 Port
+ );
+
+STATIC
+VOID
+Udp4DgramSent (
+ IN EFI_STATUS Status,
+ IN VOID *Context,
+ IN VOID *Sender,
+ IN VOID *NotifyData
+ );
+
+STATIC
+VOID
+Udp4DgramRcvd (
+ IN EFI_STATUS Status,
+ IN ICMP_ERROR IcmpError,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN NET_BUF *Packet,
+ IN VOID *Context
+ );
+
+STATIC
+EFI_STATUS
+Udp4CancelTokens (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Arg OPTIONAL
+ );
+
+STATIC
+BOOLEAN
+Udp4MatchDgram (
+ IN UDP4_INSTANCE_DATA *Instance,
+ IN EFI_UDP4_SESSION_DATA *Udp4Session
+ );
+
+STATIC
+VOID
+EFIAPI
+Udp4RecycleRxDataWrap (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+STATIC
+UDP4_RXDATA_WRAP *
+Udp4WrapRxData (
+ IN UDP4_INSTANCE_DATA *Instance,
+ IN NET_BUF *Packet,
+ IN EFI_UDP4_RECEIVE_DATA *RxData
+ );
+
+STATIC
+UINTN
+Udp4EnqueueDgram (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN NET_BUF *Packet,
+ IN EFI_UDP4_RECEIVE_DATA *RxData
+ );
+
+STATIC
+VOID
+Udp4DeliverDgram (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+STATIC
+VOID
+Udp4Demultiplex (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN NET_BUF *Packet
+ );
+
+STATIC
+VOID
+Udp4IcmpHandler (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN ICMP_ERROR IcmpError,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN NET_BUF *Packet
+ );
+
+STATIC
+VOID
+Udp4SendPortUnreach (
+ IN IP_IO *IpIo,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN VOID *Udp4Header
+ );
+
+
+/**
+ Create the Udp service context data.
+
+ @param Udp4Service Pointer to the UDP4_SERVICE_DATA.
+ @param ImageHandle The image handle of this udp4 driver.
+ @param 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.
+
+**/
+EFI_STATUS
+Udp4CreateService (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+ IP_IO_OPEN_DATA OpenData;
+
+ Udp4Service->Signature = UDP4_SERVICE_DATA_SIGNATURE;
+ Udp4Service->ServiceBinding = mUdp4ServiceBinding;
+ Udp4Service->ImageHandle = ImageHandle;
+ Udp4Service->ControllerHandle = ControllerHandle;
+ Udp4Service->ChildrenNumber = 0;
+
+ NetListInit (&Udp4Service->ChildrenList);
+
+ //
+ // Create the IpIo for this service context.
+ //
+ Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle);
+ if (Udp4Service->IpIo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the OpenData used to open the IpIo.
+ //
+ OpenData.IpConfigData = mIpIoDefaultIpConfigData;
+ OpenData.IpConfigData.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 RELEASE_IPIO;
+ }
+
+ //
+ // Create the event for Udp timeout checking.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ NET_TPL_FAST_TIMER,
+ Udp4CheckTimeout,
+ Udp4Service,
+ &Udp4Service->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto RELEASE_IPIO;
+ }
+
+ //
+ // Start the timeout timer event.
+ //
+ Status = gBS->SetTimer (
+ Udp4Service->TimeoutEvent,
+ TimerPeriodic,
+ UDP4_TIMEOUT_INTERVAL
+ );
+ if (EFI_ERROR (Status)) {
+ goto RELEASE_ALL;
+ }
+
+ Udp4Service->MacString = NULL;
+
+ return EFI_SUCCESS;
+
+RELEASE_ALL:
+
+ gBS->CloseEvent (Udp4Service->TimeoutEvent);
+
+RELEASE_IPIO:
+
+ IpIoDestroy (Udp4Service->IpIo);
+
+ return Status;
+}
+
+
+/**
+ Clean the Udp service context data.
+
+ @param Udp4Service Pointer to the UDP4_SERVICE_DATA.
+
+ @return None.
+
+**/
+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 Event The event this function registered to.
+ @param Conext The context data registered during the creation of
+ the Event.
+
+ @return None.
+
+**/
+STATIC
+VOID
+EFIAPI
+Udp4CheckTimeout (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UDP4_SERVICE_DATA *Udp4Service;
+ NET_LIST_ENTRY *Entry;
+ UDP4_INSTANCE_DATA *Instance;
+ NET_LIST_ENTRY *WrapEntry;
+ NET_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 (Entry, UDP4_RXDATA_WRAP, Link);
+
+ if (Wrap->TimeoutTick <= UDP4_TIMEOUT_INTERVAL / 1000) {
+ //
+ // Remove this RxData if it timeouts.
+ //
+ Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);
+ } else {
+ Wrap->TimeoutTick -= UDP4_TIMEOUT_INTERVAL / 1000;
+ }
+ }
+ }
+}
+
+
+/**
+ This function intializes the new created udp instance.
+
+ @param Udp4Service Pointer to the UDP4_SERVICE_DATA.
+ @param Instance Pointer to the un-initialized UDP4_INSTANCE_DATA.
+
+ @return None.
+
+**/
+VOID
+Udp4InitInstance (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN UDP4_INSTANCE_DATA *Instance
+ )
+{
+ //
+ // Set the signature.
+ //
+ Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE;
+
+ //
+ // Init the lists.
+ //
+ NetListInit (&Instance->Link);
+ NetListInit (&Instance->RcvdDgramQue);
+ NetListInit (&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;
+ Instance->Udp4Proto = mUdp4Protocol;
+ Instance->IcmpError = EFI_SUCCESS;
+ Instance->Configured = FALSE;
+ Instance->IsNoMapping = FALSE;
+ Instance->Destroyed = FALSE;
+}
+
+
+/**
+ This function cleans the udp instance.
+
+ @param Instance Pointer to the UDP4_INSTANCE_DATA to clean.
+
+ @return None.
+
+**/
+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 <Address, Port> pair.
+
+ @param InstanceList Pointer to the head of the list linking the udp
+ instances.
+ @param Address Pointer to the specified IPv4 address.
+ @param Port The udp port number.
+
+ @return Is the specified <Address, Port> pair found or not.
+
+**/
+STATIC
+BOOLEAN
+Udp4FindInstanceByPort (
+ IN NET_LIST_ENTRY *InstanceList,
+ IN EFI_IPv4_ADDRESS *Address,
+ IN UINT16 Port
+ )
+{
+ NET_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_IP_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 stragety.
+
+ @param InstanceList Pointer to the head of the list linking the udp
+ instances.
+ @param ConfigData Pointer to the ConfigData of the instance to be
+ bound.
+
+ @retval EFI_SUCCESS The bound operation is completed successfully.
+ @retval EFI_ACCESS_DENIED The <Address, Port> specified by the ConfigData is
+ already used by other instance.
+ @retval EFI_OUT_OF_RESOURCES No available port resources.
+
+**/
+EFI_STATUS
+Udp4Bind (
+ IN NET_LIST_ENTRY *InstanceList,
+ IN 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 OldConfigData Pointer to the current ConfigData the udp instance
+ uses.
+ @param NewConfigData Pointer to the new ConfigData.
+
+ @return The instance is reconfigurable or not according to the NewConfigData.
+
+**/
+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_IP_EQUAL (NewConfigData->StationAddress, OldConfigData->StationAddress) ||
+ !EFI_IP_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_IP_EQUAL (NewConfigData->RemoteAddress, OldConfigData->RemoteAddress)) {
+ //
+ // The remoteaddress is not the same.
+ //
+ return FALSE;
+ }
+
+ if ((EFI_IP4 (NewConfigData->RemoteAddress) != 0) &&
+ (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 Udp4ConfigData Pointer to the EFI_UDP4_CONFIG_DATA.
+ @param Ip4ConfigData Pointer to the EFI_IP4_CONFIG_DATA.
+
+ @return None.
+
+**/
+VOID
+Udp4BuildIp4ConfigData (
+ IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData,
+ IN EFI_IP4_CONFIG_DATA *Ip4ConfigData
+ )
+{
+ *Ip4ConfigData = mIpIoDefaultIpConfigData;
+ Ip4ConfigData->DefaultProtocol = EFI_IP_PROTO_UDP;
+ Ip4ConfigData->AcceptBroadcast = Udp4ConfigData->AcceptBroadcast;
+ Ip4ConfigData->AcceptPromiscuous = Udp4ConfigData->AcceptPromiscuous;
+ Ip4ConfigData->UseDefaultAddress = Udp4ConfigData->UseDefaultAddress;
+ Ip4ConfigData->StationAddress = Udp4ConfigData->StationAddress;
+ Ip4ConfigData->SubnetMask = Udp4ConfigData->SubnetMask;
+
+ //
+ // 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 Instance Pointer to the udp instance context data.
+ @param 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;
+
+ 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) &&
+ !Ip4IsUnicast(EFI_NTOHL (*(TxData->GatewayAddress)), 0)) {
+ //
+ // 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) {
+
+ SourceAddress = EFI_NTOHL (UdpSessionData->SourceAddress);
+
+ if ((SourceAddress != 0) && !Ip4IsUnicast (SourceAddress, 0)) {
+ //
+ // 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 (UdpSessionData->DestinationAddress) == 0) {
+ //
+ // The DestinationAddress specified in the UdpSessionData is 0.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (EFI_IP4 (ConfigData->RemoteAddress) == 0) {
+ //
+ // 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 Map Pointer to the NET_MAP.
+ @param Item Pointer to the NET_MAP_ITEM contain the pointer to
+ the Token.
+ @param 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
+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 Packet Pointer to the NET_BUF contains the udp datagram.
+ @param HeadSum Checksum of the pseudo header execpt the length
+ field.
+
+ @return 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 ~Checksum;
+}
+
+
+/**
+ This function removes the specified Token from the TokenMap.
+
+ @param TokenMap Pointer to the NET_MAP containing the tokens.
+ @param 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 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 Status The completion status of the output udp datagram.
+ @param Context Pointer to the context data.
+ @param Sender Pointer to the Ip sender of the udp datagram.
+ @param NotifyData Pointer to the notify data.
+
+ @return None.
+
+**/
+STATIC
+VOID
+Udp4DgramSent (
+ IN EFI_STATUS Status,
+ IN VOID *Context,
+ IN VOID *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);
+ }
+}
+
+
+/**
+ This function processes the received datagram passed up by the IpIo layer.
+
+ @param Status The status of this udp datagram.
+ @param IcmpError The IcmpError code, only available when Status is
+ EFI_ICMP_ERROR.
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA.
+ @param Packet Pointer to the NET_BUF containing the received udp
+ datagram.
+ @param Context Pointer to the context data.
+
+ @return None.
+
+**/
+STATIC
+VOID
+Udp4DgramRcvd (
+ IN EFI_STATUS Status,
+ IN ICMP_ERROR 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);
+ }
+}
+
+
+/**
+ This function removes the multicast group specified by Arg from the Map.
+
+ @param Map Pointer to the NET_MAP.
+ @param Item Pointer to the NET_MAP_ITEM.
+ @param 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
+Udp4LeaveGroup (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Arg OPTIONAL
+ )
+{
+ EFI_IPv4_ADDRESS *McastIp;
+
+ McastIp = Arg;
+
+ if ((McastIp != NULL) && ((UINTN) EFI_IP4 (*McastIp) != (UINTN) (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 cancle the token specified by Arg in the Map.
+
+ @param Map Pointer to the NET_MAP.
+ @param Item Pointer to the NET_MAP_ITEM.
+ @param Arg Pointer to the token to be cancelled, if NULL, all
+ the tokens in this Map will be 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.
+
+**/
+STATIC
+EFI_STATUS
+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;
+
+ TokenToCancel->Status = EFI_ABORTED;
+ gBS->SignalEvent (TokenToCancel->Event);
+
+ NetMapRemoveItem (Map, Item, NULL);
+ }
+
+ if (Arg != NULL) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function removes all the Wrap datas in the RcvdDgramQue.
+
+ @param RcvdDgramQue Pointer to the list containing all the Wrap datas.
+
+ @return None.
+
+**/
+VOID
+Udp4FlushRxData (
+ IN NET_LIST_ENTRY *RcvdDgramQue
+ )
+{
+ UDP4_RXDATA_WRAP *Wrap;
+ EFI_TPL OldTpl;
+
+ OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);
+
+ while (!NetListIsEmpty (RcvdDgramQue)) {
+ //
+ // Iterate all the Wraps in the RcvdDgramQue.
+ //
+ Wrap = NET_LIST_HEAD (RcvdDgramQue, UDP4_RXDATA_WRAP, Link);
+
+ //
+ // The Wrap will be removed from the RcvdDgramQue by this function call.
+ //
+ Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);
+ }
+
+ NET_RESTORE_TPL (OldTpl);
+}
+
+
+
+/**
+
+ @param Instance Pointer to the udp instance context data.
+ @param 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;
+
+ //
+ // Cancle 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 Instance Pointer to the udp instance context data.
+ @param Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted
+ from the received udp datagram.
+
+ @return The udp datagram matches the receiving requirments of the Instance or not.
+
+**/
+STATIC
+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 (ConfigData->RemoteAddress) != 0) &&
+ !EFI_IP_EQUAL (ConfigData->RemoteAddress, Udp4Session->SourceAddress)) {
+ //
+ // This datagram doesn't come from the instance's specified sender.
+ //
+ return FALSE;
+ }
+
+ if ((EFI_IP4 (ConfigData->StationAddress) == 0) ||
+ EFI_IP_EQUAL (Udp4Session->DestinationAddress, ConfigData->StationAddress)) {
+ //
+ // The instance is configured to receive datagrams destinated to any station IP or
+ // the destination address of this datagram matches the configured station IP.
+ //
+ return TRUE;
+ }
+
+ Destination = EFI_IP4 (Udp4Session->DestinationAddress);
+
+ 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)) &&
+ (NULL != NetMapFindKey (&Instance->McastIps, (VOID *) (UINTN) Destination))) {
+ //
+ // 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 Event The Event this notify function registered to.
+ @param Context Pointer to the context data.
+
+ @return None.
+
+**/
+STATIC
+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.
+ //
+ NetListRemoveEntry (&Wrap->Link);
+
+ //
+ // Free the Packet associated with this Wrap.
+ //
+ NetbufFree (Wrap->Packet);
+
+ //
+ // Close the event.
+ //
+ gBS->CloseEvent (Wrap->RxData.RecycleSignal);
+
+ NetFreePool (Wrap);
+}
+
+
+/**
+ This function wraps the Packet and the RxData.
+
+ @param Instance Pointer to the instance context data.
+ @param Packet Pointer to the buffer containing the received
+ datagram.
+ @param RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
+ datagram.
+
+ @return Pointer to the structure wrapping the RxData and the Packet.
+
+**/
+STATIC
+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 = NetAllocatePool (sizeof (UDP4_RXDATA_WRAP) +
+ (Packet->BlockOpNum - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
+ if (Wrap == NULL) {
+ return NULL;
+ }
+
+ NetListInit (&Wrap->Link);
+
+ Wrap->RxData = *RxData;
+
+ //
+ // Create the Recycle event.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NET_TPL_RECYCLE,
+ Udp4RecycleRxDataWrap,
+ Wrap,
+ &Wrap->RxData.RecycleSignal
+ );
+ if (EFI_ERROR (Status)) {
+ NetFreePool (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 Udp4Service Pointer to the udp service context data.
+ @param Packet Pointer to the buffer containing the received
+ datagram.
+ @param RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
+ datagram.
+
+ @return The times this datagram is enqueued.
+
+**/
+STATIC
+UINTN
+Udp4EnqueueDgram (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN NET_BUF *Packet,
+ IN EFI_UDP4_RECEIVE_DATA *RxData
+ )
+{
+ NET_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);
+
+ NetListInsertTail (&Instance->RcvdDgramQue, &Wrap->Link);
+
+ Enqueued++;
+ }
+ }
+
+ return Enqueued;
+}
+
+
+/**
+ This function delivers the received datagrams for the specified instance.
+
+ @param Instance Pointer to the instance context data.
+
+ @return None.
+
+**/
+VOID
+Udp4InstanceDeliverDgram (
+ IN UDP4_INSTANCE_DATA *Instance
+ )
+{
+ UDP4_RXDATA_WRAP *Wrap;
+ EFI_UDP4_COMPLETION_TOKEN *Token;
+ NET_BUF *Dup;
+ EFI_UDP4_RECEIVE_DATA *RxData;
+
+ if (!NetListIsEmpty (&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;
+
+ gBS->SignalEvent (Token->Event);
+
+ NetListInsertTail (&Instance->DeliveredDgramQue, &Wrap->Link);
+ }
+}
+
+
+/**
+ This function delivers the datagrams enqueued in the instances.
+
+ @param Udp4Service Pointer to the udp service context data.
+
+ @return None.
+
+**/
+STATIC
+VOID
+Udp4DeliverDgram (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ )
+{
+ NET_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 apropriate instances.
+
+ @param Udp4Service Pointer to the udp service context data.
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA abstrated from
+ the received datagram.
+ @param Packet Pointer to the buffer containing the received udp
+ datagram.
+
+ @return None.
+
+**/
+STATIC
+VOID
+Udp4Demultiplex (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN NET_BUF *Packet
+ )
+{
+ EFI_UDP4_HEADER *Udp4Header;
+ UINT16 HeadSum;
+ EFI_UDP4_RECEIVE_DATA RxData;
+ EFI_UDP4_SESSION_DATA *Udp4Session;
+ UINTN Enqueued;
+
+ //
+ // Get the datagram header from the packet buffer.
+ //
+ Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);
+
+ if (Udp4Header->Checksum != 0) {
+ //
+ // check the checksum.
+ //
+ HeadSum = NetPseudoHeadChecksum (
+ NetSession->Source,
+ NetSession->Dest,
+ EFI_IP_PROTO_UDP,
+ 0
+ );
+
+ if (Udp4Checksum (Packet, HeadSum) != 0) {
+ //
+ // Wrong checksum.
+ //
+ return;
+ }
+ }
+
+ gRT->GetTime (&RxData.TimeStamp, NULL);
+
+ Udp4Session = &RxData.UdpSession;
+ EFI_IP4 (Udp4Session->SourceAddress) = NetSession->Source;
+ EFI_IP4 (Udp4Session->DestinationAddress) = NetSession->Dest;
+ Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort);
+ Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort);
+
+ //
+ // 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 IpIo Pointer to the IP_IO instance.
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA of the packet
+ causes this icmp error message.
+ @param Udp4Header Pointer to the udp header of the datagram causes
+ this icmp error message.
+
+ @return None.
+
+**/
+STATIC
+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->Dest);
+ if (IpSender == NULL) {
+ //
+ // No apropriate sender, since we cannot send out the ICMP message through
+ // the default zero station address IP instance, abort.
+ //
+ return;
+ }
+
+ IpHdr = NetSession->IpHdr;
+
+ //
+ // Calculate the requried 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);
+
+ //
+ // 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.
+ //
+ NetCopyMem (&IcmpErrHdr->IpHead, IpHdr, EFI_IP4_HEADER_LEN (IpHdr));
+
+ //
+ // Copy the UDP header.
+ //
+ Ptr = (UINT8 *) &IcmpErrHdr->IpHead + EFI_IP4_HEADER_LEN (IpHdr);
+ NetCopyMem (Ptr, Udp4Header, ICMP_ERROR_PACKET_LENGTH);
+
+ //
+ // Calculate the checksum.
+ //
+ IcmpErrHdr->Head.Checksum = ~(NetbufChecksum (Packet));
+
+ //
+ // Fill the override data.
+ //
+ Override.DoNotFragment = FALSE;
+ Override.TypeOfService = 0;
+ Override.TimeToLive = 255;
+ Override.Protocol = EFI_IP_PROTO_ICMP;
+ EFI_IP4 (Override.SourceAddress) = NetSession->Dest;
+ EFI_IP4 (Override.GatewayAddress) = 0;
+
+ //
+ // 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 Udp4Service Pointer to the udp service context data.
+ @param IcmpError The icmp error code.
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA abstracted
+ from the received Icmp Error packet.
+ @param Packet Pointer to the Icmp Error packet.
+
+ @return None.
+
+**/
+STATIC
+VOID
+Udp4IcmpHandler (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN ICMP_ERROR IcmpError,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN NET_BUF *Packet
+ )
+{
+ EFI_UDP4_HEADER *Udp4Header;
+ EFI_UDP4_SESSION_DATA Udp4Session;
+ NET_LIST_ENTRY *Entry;
+ UDP4_INSTANCE_DATA *Instance;
+
+ Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);
+
+ EFI_IP4 (Udp4Session.SourceAddress) = NetSession->Source;
+ EFI_IP4 (Udp4Session.DestinationAddress) = NetSession->Dest;
+ 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 ||
+ Instance->ConfigData.AcceptPromiscuous ||
+ Instance->ConfigData.AcceptAnyPort ||
+ (EFI_IP4 (Instance->ConfigData.StationAddress) == 0)) {
+ //
+ // Don't try to deliver the ICMP error to this instance if it is not configured,
+ // or it's configured to be promiscuous or accept any port or accept all the
+ // datagrams.
+ //
+ continue;
+ }
+
+ if (Udp4MatchDgram (Instance, &Udp4Session)) {
+ //
+ // Translate the Icmp Error code according to the udp spec.
+ //
+ Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, 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 Instance Pointer to the udp instance context data.
+
+ @return None.
+
+**/
+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 Context Pointer to the context data.
+
+ @return None.
+
+**/
+VOID
+Udp4NetVectorExtFree (
+ VOID *Context
+ )
+{
+}
+
+
+/**
+ Set the Udp4 variable data.
+
+ @param Udp4Service Udp4 service data.
+
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the
+ variable.
+ @retval other Set variable failed.
+
+**/
+EFI_STATUS
+Udp4SetVariableData (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ )
+{
+ UINT32 NumConfiguredInstance;
+ NET_LIST_ENTRY *Entry;
+ UINTN VariableDataSize;
+ EFI_UDP4_VARIABLE_DATA *Udp4VariableData;
+ EFI_UDP4_SERVICE_POINT *Udp4ServicePoint;
+ UDP4_INSTANCE_DATA *Udp4Instance;
+ CHAR16 *NewMacString;
+ EFI_STATUS Status;
+
+ NumConfiguredInstance = 0;
+
+ //
+ // Go through the children list to count the configured children.
+ //
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
+ Udp4Instance = NET_LIST_USER_STRUCT_S (
+ Entry,
+ UDP4_INSTANCE_DATA,
+ Link,
+ UDP4_INSTANCE_DATA_SIGNATURE
+ );
+
+ if (Udp4Instance->Configured) {
+ NumConfiguredInstance++;
+ }
+ }
+
+ //
+ // Calculate the size of the Udp4VariableData. As there may be no Udp4 child,
+ // we should add extra buffer for the service points only if the number of configured
+ // children is more than 1.
+ //
+ VariableDataSize = sizeof (EFI_UDP4_VARIABLE_DATA);
+
+ if (NumConfiguredInstance > 1) {
+ VariableDataSize += sizeof (EFI_UDP4_SERVICE_POINT) * (NumConfiguredInstance - 1);
+ }
+
+ Udp4VariableData = NetAllocatePool (VariableDataSize);
+ if (Udp4VariableData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Udp4VariableData->DriverHandle = Udp4Service->ImageHandle;
+ Udp4VariableData->ServiceCount = NumConfiguredInstance;
+
+ Udp4ServicePoint = &Udp4VariableData->Services[0];
+
+ //
+ // Go through the children list to fill the configured children's address pairs.
+ //
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
+ Udp4Instance = NET_LIST_USER_STRUCT_S (
+ Entry,
+ UDP4_INSTANCE_DATA,
+ Link,
+ UDP4_INSTANCE_DATA_SIGNATURE
+ );
+
+ if (Udp4Instance->Configured) {
+ Udp4ServicePoint->InstanceHandle = Udp4Instance->ChildHandle;
+ Udp4ServicePoint->LocalAddress = Udp4Instance->ConfigData.StationAddress;
+ Udp4ServicePoint->LocalPort = Udp4Instance->ConfigData.StationPort;
+ Udp4ServicePoint->RemoteAddress = Udp4Instance->ConfigData.RemoteAddress;
+ Udp4ServicePoint->RemotePort = Udp4Instance->ConfigData.RemotePort;
+
+ Udp4ServicePoint++;
+ }
+ }
+
+ //
+ // Get the mac string.
+ //
+ Status = NetLibGetMacString (
+ Udp4Service->ControllerHandle,
+ Udp4Service->ImageHandle,
+ &NewMacString
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ if (Udp4Service->MacString != NULL) {
+ //
+ // The variable is set already, we're going to update it.
+ //
+ if (StrCmp (Udp4Service->MacString, NewMacString) != 0) {
+ //
+ // The mac address is changed, delete the previous variable first.
+ //
+ gRT->SetVariable (
+ Udp4Service->MacString,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ NULL
+ );
+ }
+
+ NetFreePool (Udp4Service->MacString);
+ }
+
+ Udp4Service->MacString = NewMacString;
+
+ Status = gRT->SetVariable (
+ Udp4Service->MacString,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ VariableDataSize,
+ (VOID *) Udp4VariableData
+ );
+
+ON_ERROR:
+
+ NetFreePool (Udp4VariableData);
+
+ return Status;
+}
+
+
+/**
+ Clear the variable and free the resource.
+
+ @param Udp4Service Udp4 service data.
+
+ @return None.
+
+**/
+VOID
+Udp4ClearVariableData (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ )
+{
+ ASSERT (Udp4Service->MacString != NULL);
+
+ gRT->SetVariable (
+ Udp4Service->MacString,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ NULL
+ );
+
+ NetFreePool (Udp4Service->MacString);
+ Udp4Service->MacString = NULL;
+}
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h
new file mode 100644
index 0000000000..7825624090
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.h
@@ -0,0 +1,299 @@
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Udp4Impl.h
+
+Abstract:
+
+ EFI UDPv4 protocol implementation
+
+
+**/
+
+#ifndef _UDP4_IMPL_H_
+#define _UDP4_IMPL_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/IP4.h>
+#include <Protocol/Udp4.h>
+
+#include <Library/IpIoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "Udp4Driver.h"
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName;
+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_UDP4_HEADER)
+#define UDP4_MAX_DATA_SIZE 65507
+
+#define UDP4_PORT_KNOWN 1024
+
+#define UDP4_SERVICE_DATA_SIGNATURE EFI_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;
+ NET_LIST_ENTRY ChildrenList;
+ UINTN ChildrenNumber;
+ IP_IO *IpIo;
+
+ EFI_EVENT TimeoutEvent;
+
+ CHAR16 *MacString;
+} UDP4_SERVICE_DATA;
+
+#define UDP4_INSTANCE_DATA_SIGNATURE EFI_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;
+ NET_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;
+
+ NET_LIST_ENTRY RcvdDgramQue;
+ NET_LIST_ENTRY DeliveredDgramQue;
+
+ UINT16 HeadSum;
+
+ EFI_STATUS IcmpError;
+
+ IP_IO_IP_INFO *IpInfo;
+
+ BOOLEAN Destroyed;
+} UDP4_INSTANCE_DATA;
+
+typedef struct _UDP4_RXDATA_WRAP_ {
+ NET_LIST_ENTRY Link;
+ NET_BUF *Packet;
+ UINT32 TimeoutTick;
+ EFI_UDP4_RECEIVE_DATA RxData;
+} UDP4_RXDATA_WRAP;
+
+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
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Configure (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Groups (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL
+ );
+
+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
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Transmit (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Receive (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Cancel (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Poll (
+ IN EFI_UDP4_PROTOCOL *This
+ );
+
+EFI_STATUS
+Udp4CreateService (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+VOID
+Udp4CleanService (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+VOID
+Udp4InitInstance (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+VOID
+Udp4CleanInstance (
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+EFI_STATUS
+Udp4Bind (
+ IN NET_LIST_ENTRY *InstanceList,
+ IN EFI_UDP4_CONFIG_DATA *ConfigData
+ );
+
+BOOLEAN
+Udp4IsReconfigurable (
+ IN EFI_UDP4_CONFIG_DATA *OldConfigData,
+ IN EFI_UDP4_CONFIG_DATA *NewConfigData
+ );
+
+VOID
+Udp4BuildIp4ConfigData (
+ IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData,
+ IN EFI_IP4_CONFIG_DATA *Ip4ConfigData
+ );
+
+EFI_STATUS
+Udp4ValidateTxToken (
+ IN UDP4_INSTANCE_DATA *Instance,
+ IN EFI_UDP4_COMPLETION_TOKEN *TxToken
+ );
+
+EFI_STATUS
+Udp4TokenExist (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+
+UINT16
+Udp4Checksum (
+ IN NET_BUF *Packet,
+ IN UINT16 HeadSum
+ );
+
+EFI_STATUS
+Udp4RemoveToken (
+ IN NET_MAP *TokenMap,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+Udp4LeaveGroup (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Arg OPTIONAL
+ );
+
+VOID
+Udp4FlushRxData (
+ IN NET_LIST_ENTRY *RcvdDgramQue
+ );
+
+EFI_STATUS
+Udp4InstanceCancelToken (
+ IN UDP4_INSTANCE_DATA *Instance,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL
+ );
+
+VOID
+Udp4InstanceDeliverDgram (
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+VOID
+Udp4ReportIcmpError (
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+VOID
+Udp4NetVectorExtFree (
+ VOID *Context
+ );
+
+EFI_STATUS
+Udp4SetVariableData (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+VOID
+Udp4ClearVariableData (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c
new file mode 100644
index 0000000000..4f897cb54b
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c
@@ -0,0 +1,869 @@
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Udp4Main.c
+
+Abstract:
+
+
+**/
+
+#include "Udp4Impl.h"
+
+#include <Protocol/Ip4.h>
+
+EFI_UDP4_PROTOCOL mUdp4Protocol = {
+ Udp4GetModeData,
+ Udp4Configure,
+ Udp4Groups,
+ Udp4Routes,
+ Udp4Transmit,
+ Udp4Receive,
+ Udp4Cancel,
+ Udp4Poll
+};
+
+
+/**
+ This 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 This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param Udp4ConfigData Pointer to the buffer to receive the current
+ configuration data.
+ @param Ip4ModeData Pointer to the EFI IPv4 Protocol mode data
+ structure.
+ @param MnpConfigData Pointer to the managed network configuration data
+ structure.
+ @param 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 = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ if (Udp4ConfigData != NULL) {
+ //
+ // Set the Udp4ConfigData.
+ //
+ *Udp4ConfigData = Instance->ConfigData;
+ }
+
+ Ip = Instance->IpInfo->Ip;
+
+ //
+ // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData.
+ //
+ Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData);
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This 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.
+
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param UdpConfigData Pointer to the buffer to receive the current mode
+ 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: This is
+ NULL. UdpConfigData.StationAddress is not a valid
+ unicast IPv4 address. UdpConfigData.SubnetMask is
+ not a valid IPv4 address mask.
+ UdpConfigData.RemoteAddress is not a valid unicast
+ IPv4 address if it is not zero.
+ @retval EFI_ALREADY_STARTED The EFI UDPv4 Protocol instance is already
+ started/configured and must be stopped/reset
+ before it can be reconfigured. Only TypeOfService,
+ TimeToLive, DoNotFragment, ReceiveTimeout, and
+ TransmitTimeout can be reconfigured without
+ stopping the current instance of the EFI UDPv4
+ Protocol.
+ @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;
+
+ 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 = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ if (UdpConfigData != NULL) {
+
+ StationAddress = EFI_NTOHL (UdpConfigData->StationAddress);
+ SubnetMask = EFI_NTOHL (UdpConfigData->SubnetMask);
+ RemoteAddress = EFI_NTOHL (UdpConfigData->RemoteAddress);
+
+ if (!UdpConfigData->UseDefaultAddress &&
+ (!IP4_IS_VALID_NETMASK (SubnetMask) ||
+ !((StationAddress == 0) || Ip4IsUnicast (StationAddress, SubnetMask)) ||
+ !((RemoteAddress == 0) || Ip4IsUnicast (RemoteAddress, 0)))) {
+ //
+ // 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.
+ //
+ Instance->ConfigData = *UdpConfigData;
+ Instance->ConfigData.StationAddress = Ip4ConfigData.StationAddress;
+ 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.
+ //
+ Instance->HeadSum = NetPseudoHeadChecksum (
+ EFI_IP4 (Instance->ConfigData.StationAddress),
+ EFI_IP4 (Instance->ConfigData.RemoteAddress),
+ 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.
+ //
+ Udp4InstanceCancelToken (Instance, NULL);
+
+ //
+ // Remove the buffered RxData for this instance.
+ //
+ Udp4FlushRxData (&Instance->RcvdDgramQue);
+ }
+
+ Udp4SetVariableData (Instance->Udp4Service);
+
+ON_EXIT:
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function is used to enable and disable the multicast group filtering.
+
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param JoinFlag Set to TRUE to join a multicast group. Set to
+ FALSE to leave one or all multicast groups.
+ @param 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;
+
+ if ((This == NULL) ||
+ (JoinFlag && (MulticastAddress == NULL)) ||
+ (JoinFlag && !IP4_IS_MULTICAST (EFI_NTOHL (*MulticastAddress)))) {
+ 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;
+
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ //
+ // 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 destinated to multicast IPs the other instances configured.
+ //
+ if (JoinFlag) {
+
+ NetMapInsertTail (
+ &Instance->McastIps,
+ (VOID *) (UINTN) EFI_IP4 (*MulticastAddress),
+ NULL
+ );
+ } else {
+
+ NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress);
+ }
+
+ON_EXIT:
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function adds a route to or deletes a route from the routing table.
+
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param DeleteRoute Set to TRUE to delete this route from the routing
+ table. Set to FALSE to add this route to the
+ routing table.
+ @param SubnetAddress The destination network address that needs to be
+ routed.
+ @param SubnetMask The subnet mask of SubnetAddress.
+ @param 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 of the following conditions is TRUE:
+ This is NULL. SubnetAddress is NULL. SubnetMask is
+ NULL. GatewayAddress is NULL. SubnetAddress is not
+ a valid subnet address. SubnetMask is not a valid
+ subnet mask. GatewayAddress is not a valid unicast
+ IP address.
+ @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;
+
+ //
+ // Invoke the Ip instance the Udp4 instance consumes to do the actual operation.
+ //
+ return Ip->Routes (Ip, DeleteRoute, SubnetAddress, SubnetMask, GatewayAddress);
+}
+
+
+/**
+ This function places a sending request to this instance of the EFI UDPv4 Protocol,
+ alongside the transmit data that was filled by the user.
+
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param 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 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_ACCESS_DENIED The transmit completion token with the same
+ Token.Event is 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_UDP4_HEADER *Udp4Header;
+ EFI_UDP4_CONFIG_DATA *ConfigData;
+ IP4_ADDR Destination;
+ EFI_UDP4_TRANSMIT_DATA *TxData;
+ EFI_UDP4_SESSION_DATA *UdpSessionData;
+ UDP4_SERVICE_DATA *Udp4Service;
+ IP_IO_OVERRIDE Override;
+ UINT16 HeadSum;
+
+ 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 = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ //
+ // 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_UDP4_HEADER *) NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE);
+ ConfigData = &Instance->ConfigData;
+
+ //
+ // Fill the udp header.
+ //
+ Udp4Header->SrcPort = HTONS (ConfigData->StationPort);
+ Udp4Header->DstPort = HTONS (ConfigData->RemotePort);
+ Udp4Header->Length = HTONS (Packet->TotalSize);
+ Udp4Header->Checksum = 0;
+
+ UdpSessionData = TxData->UdpSessionData;
+ Override.SourceAddress = ConfigData->StationAddress;
+
+ if (UdpSessionData != NULL) {
+ //
+ // Set the SourceAddress, SrcPort and Destination according to the specified
+ // UdpSessionData.
+ //
+ if (EFI_IP4 (UdpSessionData->SourceAddress) != 0) {
+ Override.SourceAddress = UdpSessionData->SourceAddress;
+ }
+
+ if (UdpSessionData->SourcePort != 0) {
+ Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);
+ }
+
+ Destination = EFI_IP4 (UdpSessionData->DestinationAddress);
+
+ if (UdpSessionData->DestinationPort != 0) {
+ Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);
+ }
+
+ //
+ // calculate the pseudo head checksum using the overridden parameters.
+ //
+ HeadSum = NetPseudoHeadChecksum (
+ EFI_IP4 (Override.SourceAddress),
+ Destination,
+ EFI_IP_PROTO_UDP,
+ 0
+ );
+ } else {
+ //
+ // UdpSessionData is NULL, use the address and port information previously configured.
+ //
+ Destination = EFI_IP4 (ConfigData->RemoteAddress);
+ 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.
+ //
+ EFI_IP4 (Override.GatewayAddress) = (TxData->GatewayAddress != NULL) ?
+ EFI_IP4 (*(TxData->GatewayAddress)) : 0;
+ Override.Protocol = EFI_IP_PROTO_UDP;
+ Override.TypeOfService = ConfigData->TypeOfService;
+ Override.TimeToLive = ConfigData->TimeToLive;
+ Override.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.
+ //
+ Status = IpIoSend (
+ Udp4Service->IpIo,
+ Packet,
+ Instance->IpInfo,
+ Instance,
+ Token,
+ Destination,
+ &Override
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Remove this token from the TxTokens.
+ //
+ Udp4RemoveToken (&Instance->TxTokens, Token);
+ }
+
+FREE_PACKET:
+
+ NetbufFree (Packet);
+
+ON_EXIT:
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function places a completion token into the receive packet queue. This function
+ is always asynchronous.
+
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param Token Pointer to a token that is associated with the
+ receive data descriptor.
+
+ @retval EFI_SUCCESS The receive completion token is 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:
+ This is NULL. Token is NULL. Token.Event is NULL.
+ @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.
+ The EFI UDPv4 Protocol instance has been reset to
+ startup defaults.
+ @retval EFI_ACCESS_DENIED A receive completion token with the same
+ Token.Event is 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 = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ 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)) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // If there is an icmp error, report it.
+ //
+ Udp4ReportIcmpError (Instance);
+
+ //
+ // Try to delivered the received datagrams.
+ //
+ Udp4InstanceDeliverDgram (Instance);
+
+ON_EXIT:
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function is used to abort a pending transmit or receive request.
+
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.
+ @param Token Pointer to a token that has been issued by
+ EFI_UDP4_PROTOCOL.Transmit() or
+ EFI_UDP4_PROTOCOL.Receive().
+
+ @retval EFI_SUCCESS The asynchronous I/O request is aborted and
+ Token.Event is 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 is not found in the transmit or receive
+ queue. It is either completed or not issued by
+ Transmit() or 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 = NET_RAISE_TPL (NET_TPL_LOCK);
+
+ //
+ // Cancle the tokens specified by Token for this instance.
+ //
+ Status = Udp4InstanceCancelToken (Instance, Token);
+
+ NET_RESTORE_TPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This 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/receive queues.
+ Argumens:
+ 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;
+
+ //
+ // Invode the Ip instance consumed by the udp instance to do the poll operation.
+ //
+ return Ip->Poll (Ip);
+}