From a3bcde70e6dc69000f85cc5deee98101d2ae200a Mon Sep 17 00:00:00 2001 From: hhtian Date: Mon, 1 Nov 2010 06:13:54 +0000 Subject: Add NetworkPkg (P.UDK2010.UP3.Network.P1) git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10986 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/Udp6Dxe/ComponentName.c | 313 ++++++ NetworkPkg/Udp6Dxe/Udp6Driver.c | 556 ++++++++++ NetworkPkg/Udp6Dxe/Udp6Driver.h | 182 +++ NetworkPkg/Udp6Dxe/Udp6Dxe.inf | 63 ++ NetworkPkg/Udp6Dxe/Udp6Impl.c | 2131 ++++++++++++++++++++++++++++++++++++ NetworkPkg/Udp6Dxe/Udp6Impl.h | 673 ++++++++++++ NetworkPkg/Udp6Dxe/Udp6Main.c | 855 +++++++++++++++ 7 files changed, 4773 insertions(+) create mode 100644 NetworkPkg/Udp6Dxe/ComponentName.c create mode 100644 NetworkPkg/Udp6Dxe/Udp6Driver.c create mode 100644 NetworkPkg/Udp6Dxe/Udp6Driver.h create mode 100644 NetworkPkg/Udp6Dxe/Udp6Dxe.inf create mode 100644 NetworkPkg/Udp6Dxe/Udp6Impl.c create mode 100644 NetworkPkg/Udp6Dxe/Udp6Impl.h create mode 100644 NetworkPkg/Udp6Dxe/Udp6Main.c (limited to 'NetworkPkg/Udp6Dxe') diff --git a/NetworkPkg/Udp6Dxe/ComponentName.c b/NetworkPkg/Udp6Dxe/ComponentName.c new file mode 100644 index 0000000000..d7df0965a0 --- /dev/null +++ b/NetworkPkg/Udp6Dxe/ComponentName.c @@ -0,0 +1,313 @@ +/** @file + UEFI Component Name(2) protocol implementation for UDP6 driver. + + Copyright (c) 2009 - 2010, 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. + +**/ + +#include "Udp6Impl.h" + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user-readable name of the driver. + + This function retrieves the user-readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user-readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +Udp6ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user-readable name of the controller + that is being managed by a driver. + + This function retrieves the user-readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user-readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +Udp6ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUdp6ComponentName = { + Udp6ComponentNameGetDriverName, + Udp6ComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdp6ComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Udp6ComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Udp6ComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdp6DriverNameTable[] = { + { + "eng;en", + L"UDP6 Network Service Driver" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user-readable name of the driver. + + This function retrieves the user-readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user-readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +Udp6ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mUdp6DriverNameTable, + DriverName, + (BOOLEAN) (This == &gUdp6ComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user-readable name of the controller + that is being managed by a driver. + + This function retrieves the user-readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user-readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +Udp6ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} + diff --git a/NetworkPkg/Udp6Dxe/Udp6Driver.c b/NetworkPkg/Udp6Dxe/Udp6Driver.c new file mode 100644 index 0000000000..1cfd5f1b4d --- /dev/null +++ b/NetworkPkg/Udp6Dxe/Udp6Driver.c @@ -0,0 +1,556 @@ +/** @file + Driver Binding functions and Service Binding functions for the Network driver module. + + Copyright (c) 2009 - 2010, 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. + +**/ + +#include "Udp6Impl.h" + +EFI_DRIVER_BINDING_PROTOCOL gUdp6DriverBinding = { + Udp6DriverBindingSupported, + Udp6DriverBindingStart, + Udp6DriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_SERVICE_BINDING_PROTOCOL mUdp6ServiceBinding = { + Udp6ServiceBindingCreateChild, + Udp6ServiceBindingDestroyChild +}; + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +Udp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + // + // Test for the Udp6ServiceBinding Protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + // + // Test for the Ip6ServiceBinding Protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiIp6ServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + return Status; +} + +/** + Start this driver on ControllerHandle. + + This service is called by the EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind the driver to. + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCES This driver is added to ControllerHandle. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +Udp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + UDP6_SERVICE_DATA *Udp6Service; + + // + // Allocate Private Context Data Structure. + // + Udp6Service = AllocateZeroPool (sizeof (UDP6_SERVICE_DATA)); + if (Udp6Service == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + Status = Udp6CreateService (Udp6Service, This->DriverBindingHandle, ControllerHandle); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Install the Udp6ServiceBindingProtocol on the ControllerHandle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + &Udp6Service->ServiceBinding, + NULL + ); + if (EFI_ERROR (Status)) { + Udp6CleanService (Udp6Service); + goto EXIT; + } else { + Status = Udp6SetVariableData (Udp6Service); + } + +EXIT: + if (EFI_ERROR (Status)) { + if (Udp6Service != NULL) { + FreePool (Udp6Service); + } + } + return Status; +} + +/** + Stop this driver on ControllerHandle. + + This service is called by the EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop(), it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop the driver on. + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If the number + of children is zero stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. It is optional. + + @retval EFI_SUCCES This driver is removed ControllerHandle. + @retval EFI_DEVICE_ERROR Can't find the NicHandle from the ControllerHandle and specified GUID. + @retval other This driver was not removed from this device. + +**/ +EFI_STATUS +EFIAPI +Udp6DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE NicHandle; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + UDP6_SERVICE_DATA *Udp6Service; + UDP6_INSTANCE_DATA *Instance; + + // + // Find the NicHandle where UDP6 ServiceBinding Protocol is installed. + // + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp6ProtocolGuid); + if (NicHandle == NULL) { + return EFI_DEVICE_ERROR; + } + + // + // Retrieve the UDP6 ServiceBinding Protocol. + // + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + NicHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Udp6Service = UDP6_SERVICE_DATA_FROM_THIS (ServiceBinding); + + if (NumberOfChildren == 0) { + + gBS->UninstallMultipleProtocolInterfaces ( + NicHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + &Udp6Service->ServiceBinding, + NULL + ); + + Udp6ClearVariableData (Udp6Service); + + Udp6CleanService (Udp6Service); + + FreePool (Udp6Service); + } else { + + while (!IsListEmpty (&Udp6Service->ChildrenList)) { + Instance = NET_LIST_HEAD (&Udp6Service->ChildrenList, UDP6_INSTANCE_DATA, Link); + + Status = ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle); + } + } + + return Status; +} + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in, out] ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER This is NULL or ChildHandle is NULL. + @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 +Udp6ServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN OUT EFI_HANDLE *ChildHandle + ) +{ + EFI_STATUS Status; + UDP6_SERVICE_DATA *Udp6Service; + UDP6_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + VOID *Ip6; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Udp6Service = UDP6_SERVICE_DATA_FROM_THIS (This); + + // + // Allocate the instance private data structure. + // + Instance = AllocateZeroPool (sizeof (UDP6_INSTANCE_DATA)); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Udp6InitInstance (Udp6Service, Instance); + + // + // Add an IpInfo for this instance. + // + Instance->IpInfo = IpIoAddIp (Udp6Service->IpIo); + if (Instance->IpInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Install the Udp6Protocol for this instance. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiUdp6ProtocolGuid, + &Instance->Udp6Proto, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Instance->ChildHandle = *ChildHandle; + + // + // Open the default Ip6 protocol in the IP_IO BY_CHILD. + // + Status = gBS->OpenProtocol ( + Udp6Service->IpIo->ChildHandle, + &gEfiIp6ProtocolGuid, + (VOID **) &Ip6, + gUdp6DriverBinding.DriverBindingHandle, + Instance->ChildHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Link this instance into the service context data and increase the ChildrenNumber. + // + InsertTailList (&Udp6Service->ChildrenList, &Instance->Link); + Udp6Service->ChildrenNumber++; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +ON_ERROR: + + if (Instance->ChildHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + Instance->ChildHandle, + &gEfiUdp6ProtocolGuid, + &Instance->Udp6Proto, + NULL + ); + } + + if (Instance->IpInfo != NULL) { + IpIoRemoveIp (Udp6Service->IpIo, Instance->IpInfo); + } + + Udp6CleanInstance (Instance); + + FreePool (Instance); + + return Status; +} + +/** + Destroys a child handle with a set of I/O services. + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param[in] This Protocol instance pointer. + @param[in] 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 +Udp6ServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ) +{ + EFI_STATUS Status; + UDP6_SERVICE_DATA *Udp6Service; + EFI_UDP6_PROTOCOL *Udp6Proto; + UDP6_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + + if ((This == NULL) || (ChildHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Udp6Service = UDP6_SERVICE_DATA_FROM_THIS (This); + + // + // Try to get the Udp6 protocol from the ChildHandle. + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiUdp6ProtocolGuid, + (VOID **) &Udp6Proto, + gUdp6DriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (Udp6Proto); + + if (Instance->Destroyed) { + return EFI_SUCCESS; + } + + // + // Use the Destroyed flag to avoid the re-entering of the following code. + // + Instance->Destroyed = TRUE; + + // + // Close the Ip6 protocol. + // + gBS->CloseProtocol ( + Udp6Service->IpIo->ChildHandle, + &gEfiIp6ProtocolGuid, + gUdp6DriverBinding.DriverBindingHandle, + Instance->ChildHandle + ); + + // + // Uninstall the Udp6Protocol previously installed on the ChildHandle. + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandle, + &gEfiUdp6ProtocolGuid, + (VOID *) &Instance->Udp6Proto, + NULL + ); + if (EFI_ERROR (Status)) { + Instance->Destroyed = FALSE; + return Status; + } + + // + // Reset the configuration in case the instance's consumer forgets to do this. + // + Udp6Proto->Configure (Udp6Proto, NULL); + + // + // Remove the IpInfo this instance consumes. + // + IpIoRemoveIp (Udp6Service->IpIo, Instance->IpInfo); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Remove this instance from the service context data's ChildrenList. + // + RemoveEntryList (&Instance->Link); + Udp6Service->ChildrenNumber--; + + // + // Clean the instance. + // + Udp6CleanInstance (Instance); + + gBS->RestoreTPL (OldTpl); + + FreePool (Instance); + + return EFI_SUCCESS; +} + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including + both device drivers and bus drivers. + + The entry point for Udp6 driver that installs the driver binding + and component name protocol on its ImageHandle. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +Udp6DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install the Udp6DriverBinding and Udp6ComponentName protocols. + // + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gUdp6DriverBinding, + ImageHandle, + &gUdp6ComponentName, + &gUdp6ComponentName2 + ); + if (!EFI_ERROR (Status)) { + // + // Initialize the UDP random port. + // + mUdp6RandomPort = (UINT16)( + ((UINT16) NetRandomInitSeed ()) % + UDP6_PORT_KNOWN + + UDP6_PORT_KNOWN + ); + } + + return Status; +} + + diff --git a/NetworkPkg/Udp6Dxe/Udp6Driver.h b/NetworkPkg/Udp6Dxe/Udp6Driver.h new file mode 100644 index 0000000000..e5a923be68 --- /dev/null +++ b/NetworkPkg/Udp6Dxe/Udp6Driver.h @@ -0,0 +1,182 @@ +/** @file + Driver Binding functions and Service Binding functions for the Network driver module. + + Copyright (c) 2009 - 2010, 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. + +**/ + +#ifndef _UDP6_DRIVER_H_ +#define _UDP6_DRIVER_H_ + +#include +#include +#include + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +Udp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. + + This service is called by the EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind a driver to. + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCES This driver is added to ControllerHandle. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +Udp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stop this driver on ControllerHandle. + + This service is called by the EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop(), it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop the driver on. + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number + of children is zero, stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. It is optional. + + @retval EFI_SUCCESS This driver removed ControllerHandle. + @retval EFI_DEVICE_ERROR Can't find the NicHandle from the ControllerHandle and specified GUID. + @retval other This driver was not removed from this device. + +**/ +EFI_STATUS +EFIAPI +Udp6DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +/** + Creates a child handle and installs a protocol. + + The CreateChild() function installs a protocol on ChildHandle. + If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. + If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. + + @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. + @param[in, out] ChildHandle Pointer to the handle of the child to create. If it is NULL, + then a new handle is created. If it is a pointer to an existing UEFI handle, + then the protocol is added to the existing UEFI handle. + + @retval EFI_SUCCES The protocol was added to ChildHandle. + @retval EFI_INVALID_PARAMETER This is NULL or ChildHandle is NULL. + @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 +Udp6ServiceBindingCreateChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN OUT EFI_HANDLE *ChildHandle + ); + +/** + Destroys a child handle with a set of I/O services. + The DestroyChild() function does the opposite of CreateChild(). It removes a protocol + that was installed by CreateChild() from ChildHandle. If the removed protocol is the + last protocol on ChildHandle, then ChildHandle is destroyed. + + @param[in] This Protocol instance pointer. + @param[in] 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 +Udp6ServiceBindingDestroyChild ( + IN EFI_SERVICE_BINDING_PROTOCOL *This, + IN EFI_HANDLE ChildHandle + ); + +#endif + diff --git a/NetworkPkg/Udp6Dxe/Udp6Dxe.inf b/NetworkPkg/Udp6Dxe/Udp6Dxe.inf new file mode 100644 index 0000000000..30b2bc1cc7 --- /dev/null +++ b/NetworkPkg/Udp6Dxe/Udp6Dxe.inf @@ -0,0 +1,63 @@ +## @file Udp6Dxe.inf +# Component description file for Udp6 module. +# +# Copyright (c) 2009 - 2010, 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Udp6Dxe + FILE_GUID = D912C7BC-F098-4367-92BA-E911083C7B0E + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = Udp6DriverEntryPoint + UNLOAD_IMAGE = NetLibDefaultUnload + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + Udp6Driver.h + Udp6Driver.c + Udp6Impl.c + Udp6Impl.h + ComponentName.c + Udp6Main.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + UefiLib + DebugLib + IpIoLib + NetLib + DpcLib + + +[Protocols] + gEfiIp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiIp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUdp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUdp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED + diff --git a/NetworkPkg/Udp6Dxe/Udp6Impl.c b/NetworkPkg/Udp6Dxe/Udp6Impl.c new file mode 100644 index 0000000000..8e259319b9 --- /dev/null +++ b/NetworkPkg/Udp6Dxe/Udp6Impl.c @@ -0,0 +1,2131 @@ +/** @file + Udp6 driver's whole implementation. + + Copyright (c) 2009 - 2010, 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. + +**/ + +#include "Udp6Impl.h" + +UINT16 mUdp6RandomPort; + +/** + This function checks and timeouts the I/O datagrams holding by the corresponding + service context. + + @param[in] Event The event this function is registered to. + @param[in] Context The context data registered during the creation of + the Event. + +**/ +VOID +EFIAPI +Udp6CheckTimeout ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + This function finds the udp instance by the specified pair. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in] Address Pointer to the specified IPv6 address. + @param[in] Port The udp port number. + + @retval TRUE The specified pair is found. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp6FindInstanceByPort ( + IN LIST_ENTRY *InstanceList, + IN EFI_IPv6_ADDRESS *Address, + IN UINT16 Port + ); + +/** + This function is the packet transmitting notify function registered to the IpIo + interface. It's called to signal the udp TxToken when the IpIo layer completes + transmitting of the udp datagram. + + @param[in] Status The completion status of the output udp datagram. + @param[in] Context Pointer to the context data. + @param[in] Sender Specify a EFI_IP6_PROTOCOL for sending. + @param[in] NotifyData Pointer to the notify data. + +**/ +VOID +EFIAPI +Udp6DgramSent ( + IN EFI_STATUS Status, + IN VOID *Context, + IN IP_IO_IP_PROTOCOL Sender, + IN VOID *NotifyData + ); + +/** + This function processes the received datagram passed up by the IpIo layer. + + @param[in] Status The status of this udp datagram. + @param[in] IcmpError The IcmpError code, only available when Status is + EFI_ICMP_ERROR. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA. + @param[in] Packet Pointer to the NET_BUF containing the received udp + datagram. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp6DgramRcvd ( + IN EFI_STATUS Status, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet, + IN VOID *Context + ); + +/** + This function cancle the token specified by Arg in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled, if NULL, all + the tokens in this Map will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token + is not the same as that in the Item if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Udp6CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ); + +/** + This function check if the received udp datagram matches with the Instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Udp6Session Pointer to the EFI_UDP6_SESSION_DATA abstracted + from the received udp datagram. + + @retval TRUE The udp datagram matches the receiving requirements of the Instance. + @retval FALSE The udp datagram doe not match the receiving requirements of the Instance. + +**/ +BOOLEAN +Udp6MatchDgram ( + IN UDP6_INSTANCE_DATA *Instance, + IN EFI_UDP6_SESSION_DATA *Udp6Session + ); + +/** + This function removes the Wrap specified by Context and releases relevant resources. + + @param[in] Event The Event this notify function is registered to. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp6RecycleRxDataWrap ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + This function wraps the Packet into RxData. + + @param[in] Instance Pointer to the instance context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP6_RECEIVE_DATA of this + datagram. + + @return Pointer to the structure wrapping the RxData and the Packet. + +**/ +UDP6_RXDATA_WRAP * +Udp6WrapRxData ( + IN UDP6_INSTANCE_DATA *Instance, + IN NET_BUF *Packet, + IN EFI_UDP6_RECEIVE_DATA *RxData + ); + +/** + This function enqueues the received datagram into the instances' receiving queues. + + @param[in] Udp6Service Pointer to the udp service context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP6_RECEIVE_DATA of this + datagram. + + @return The times this datagram is enqueued. + +**/ +UINTN +Udp6EnqueueDgram ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN NET_BUF *Packet, + IN EFI_UDP6_RECEIVE_DATA *RxData + ); + +/** + This function delivers the datagrams enqueued in the instances. + + @param[in] Udp6Service Pointer to the udp service context data. + +**/ +VOID +Udp6DeliverDgram ( + IN UDP6_SERVICE_DATA *Udp6Service + ); + +/** + This function demultiplexes the received udp datagram to the apropriate instances. + + @param[in] Udp6Service Pointer to the udp service context data. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstrated from + the received datagram. + @param[in] Packet Pointer to the buffer containing the received udp + datagram. + +**/ +VOID +Udp6Demultiplex ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet + ); + +/** + This function handles the received Icmp Error message and demultiplexes it to the + instance. + + @param[in] Udp6Service Pointer to the udp service context data. + @param[in] IcmpError The icmp error code. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted + from the received Icmp Error packet. + @param[in, out] Packet Pointer to the Icmp Error packet. + +**/ +VOID +Udp6IcmpHandler ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN OUT NET_BUF *Packet + ); + +/** + This function builds and sends out a icmp port unreachable message. + + @param[in] IpIo Pointer to the IP_IO instance. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet + causes this icmp error message. + @param[in] Udp6Header Pointer to the udp header of the datagram causes + this icmp error message. + +**/ +VOID +Udp6SendPortUnreach ( + IN IP_IO *IpIo, + IN EFI_NET_SESSION_DATA *NetSession, + IN VOID *Udp6Header + ); + +/** + Find the key in the netmap + + @param[in] Map The netmap to search within. + @param[in] Key The key to search. + + @return The point to the item contains the Key, or NULL if Key isn't in the map. + +**/ +NET_MAP_ITEM * +Udp6MapMultiCastAddr ( + IN NET_MAP *Map, + IN VOID *Key + ); + +/** + Create the Udp service context data. + + @param[in] Udp6Service Pointer to the UDP6_SERVICE_DATA. + @param[in] ImageHandle The image handle of this udp6 driver. + @param[in] ControllerHandle The controller handle this udp6 driver binds on. + + @retval EFI_SUCCESS The udp6 service context data was created and + initialized. + @retval EFI_OUT_OF_RESOURCES Cannot allocate memory. + @retval Others An error condition occurred. + +**/ +EFI_STATUS +Udp6CreateService ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + IP_IO_OPEN_DATA OpenData; + + ZeroMem (Udp6Service, sizeof (UDP6_SERVICE_DATA)); + + Udp6Service->Signature = UDP6_SERVICE_DATA_SIGNATURE; + Udp6Service->ServiceBinding = mUdp6ServiceBinding; + Udp6Service->ImageHandle = ImageHandle; + Udp6Service->ControllerHandle = ControllerHandle; + Udp6Service->ChildrenNumber = 0; + + InitializeListHead (&Udp6Service->ChildrenList); + + // + // Create the IpIo for this service context. + // + Udp6Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle, IP_VERSION_6); + if (Udp6Service->IpIo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Set the OpenData used to open the IpIo. + // + CopyMem ( + &OpenData.IpConfigData.Ip6CfgData, + &mIp6IoDefaultIpConfigData, + sizeof (EFI_IP6_CONFIG_DATA) + ); + OpenData.RcvdContext = (VOID *) Udp6Service; + OpenData.SndContext = NULL; + OpenData.PktRcvdNotify = Udp6DgramRcvd; + OpenData.PktSentNotify = Udp6DgramSent; + + // + // Configure and start the IpIo. + // + Status = IpIoOpen (Udp6Service->IpIo, &OpenData); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create the event for Udp timeout checking. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Udp6CheckTimeout, + Udp6Service, + &Udp6Service->TimeoutEvent + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Start the timeout timer event. + // + Status = gBS->SetTimer ( + Udp6Service->TimeoutEvent, + TimerPeriodic, + UDP6_TIMEOUT_INTERVAL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (Udp6Service->TimeoutEvent != NULL) { + gBS->CloseEvent (Udp6Service->TimeoutEvent); + } + + IpIoDestroy (Udp6Service->IpIo); + + return Status; +} + + +/** + Clean the Udp service context data. + + @param[in, out] Udp6Service Pointer to the UDP6_SERVICE_DATA. + +**/ +VOID +Udp6CleanService ( + IN OUT UDP6_SERVICE_DATA *Udp6Service + ) +{ + // + // Close the TimeoutEvent timer. + // + gBS->CloseEvent (Udp6Service->TimeoutEvent); + + // + // Destroy the IpIo. + // + IpIoDestroy (Udp6Service->IpIo); +} + + +/** + This function checks and times out the I/O datagrams listed in the + UDP6_SERVICE_DATA which is specified by the input parameter Context. + + + @param[in] Event The event this function registered to. + @param[in] Context The context data registered during the creation of + the Event. + +**/ +VOID +EFIAPI +Udp6CheckTimeout ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UDP6_SERVICE_DATA *Udp6Service; + LIST_ENTRY *Entry; + UDP6_INSTANCE_DATA *Instance; + LIST_ENTRY *WrapEntry; + LIST_ENTRY *NextEntry; + UDP6_RXDATA_WRAP *Wrap; + + Udp6Service = (UDP6_SERVICE_DATA *) Context; + NET_CHECK_SIGNATURE (Udp6Service, UDP6_SERVICE_DATA_SIGNATURE); + + NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) { + // + // Iterate all the instances belonging to this service context. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link); + NET_CHECK_SIGNATURE (Instance, UDP6_INSTANCE_DATA_SIGNATURE); + + if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) { + // + // Skip this instance if it's not configured or no receive timeout. + // + continue; + } + + NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) { + // + // Iterate all the rxdatas belonging to this udp instance. + // + Wrap = NET_LIST_USER_STRUCT (WrapEntry, UDP6_RXDATA_WRAP, Link); + + if (Wrap->TimeoutTick < UDP6_TIMEOUT_INTERVAL / 10) { + // + // Remove this RxData if it timeouts. + // + Udp6RecycleRxDataWrap (NULL, (VOID *) Wrap); + } else { + Wrap->TimeoutTick -= UDP6_TIMEOUT_INTERVAL / 10; + } + } + } +} + + +/** + This function intializes the new created udp instance. + + @param[in] Udp6Service Pointer to the UDP6_SERVICE_DATA. + @param[in, out] Instance Pointer to the un-initialized UDP6_INSTANCE_DATA. + +**/ +VOID +Udp6InitInstance ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN OUT UDP6_INSTANCE_DATA *Instance + ) +{ + // + // Set the signature. + // + Instance->Signature = UDP6_INSTANCE_DATA_SIGNATURE; + + // + // Init the lists. + // + InitializeListHead (&Instance->Link); + InitializeListHead (&Instance->RcvdDgramQue); + InitializeListHead (&Instance->DeliveredDgramQue); + + // + // Init the NET_MAPs. + // + NetMapInit (&Instance->TxTokens); + NetMapInit (&Instance->RxTokens); + NetMapInit (&Instance->McastIps); + + // + // Save the pointer to the UDP6_SERVICE_DATA, and initialize other members. + // + Instance->Udp6Service = Udp6Service; + CopyMem (&Instance->Udp6Proto, &mUdp6Protocol, sizeof (EFI_UDP6_PROTOCOL)); + Instance->IcmpError = EFI_SUCCESS; + Instance->Configured = FALSE; + Instance->IsNoMapping = FALSE; + Instance->Destroyed = FALSE; +} + + +/** + This function cleans the udp instance. + + @param[in, out] Instance Pointer to the UDP6_INSTANCE_DATA to clean. + +**/ +VOID +Udp6CleanInstance ( + IN OUT UDP6_INSTANCE_DATA *Instance + ) +{ + NetMapClean (&Instance->McastIps); + NetMapClean (&Instance->RxTokens); + NetMapClean (&Instance->TxTokens); +} + + +/** + This function finds the udp instance by the specified pair. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in] Address Pointer to the specified IPv6 address. + @param[in] Port The udp port number. + + @retval TRUE The specified pair is found. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp6FindInstanceByPort ( + IN LIST_ENTRY *InstanceList, + IN EFI_IPv6_ADDRESS *Address, + IN UINT16 Port + ) +{ + LIST_ENTRY *Entry; + UDP6_INSTANCE_DATA *Instance; + EFI_UDP6_CONFIG_DATA *ConfigData; + + NET_LIST_FOR_EACH (Entry, InstanceList) { + // + // Iterate all the udp instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP6_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_IP6_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[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in] ConfigData Pointer to the ConfigData of the instance to be + bound. + + @retval EFI_SUCCESS The bound operation completed successfully. + @retval EFI_ACCESS_DENIED The specified by the ConfigData is + already used by other instance. + @retval EFI_OUT_OF_RESOURCES No available port resources. + +**/ +EFI_STATUS +Udp6Bind ( + IN LIST_ENTRY *InstanceList, + IN EFI_UDP6_CONFIG_DATA *ConfigData + ) +{ + EFI_IPv6_ADDRESS *StationAddress; + UINT16 StartPort; + + if (ConfigData->AcceptAnyPort) { + return EFI_SUCCESS; + } + + StationAddress = &ConfigData->StationAddress; + + if (ConfigData->StationPort != 0) { + + if (!ConfigData->AllowDuplicatePort && + Udp6FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort) + ) { + // + // Do not allow duplicate ports 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 = mUdp6RandomPort; + } else { + + StartPort = mUdp6RandomPort; + + while (Udp6FindInstanceByPort (InstanceList, StationAddress, mUdp6RandomPort)) { + + mUdp6RandomPort++; + if (mUdp6RandomPort == 0) { + mUdp6RandomPort = UDP6_PORT_KNOWN; + } + + if (mUdp6RandomPort == StartPort) { + // + // No available port. + // + return EFI_OUT_OF_RESOURCES; + } + } + + ConfigData->StationPort = mUdp6RandomPort; + } + + mUdp6RandomPort++; + if (mUdp6RandomPort == 0) { + mUdp6RandomPort = UDP6_PORT_KNOWN; + } + } + return EFI_SUCCESS; +} + + +/** + This function is used to check whether the NewConfigData has any un-reconfigurable + parameters changed compared to the OldConfigData. + + @param[in] OldConfigData Pointer to the current ConfigData the udp instance + uses. + @param[in] NewConfigData Pointer to the new ConfigData. + + @retval TRUE The instance is reconfigurable according to the NewConfigData. + @retval FALSE Otherwise. + +**/ +BOOLEAN +Udp6IsReconfigurable ( + IN EFI_UDP6_CONFIG_DATA *OldConfigData, + IN EFI_UDP6_CONFIG_DATA *NewConfigData + ) +{ + if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) || + (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 (!EFI_IP6_EQUAL (&NewConfigData->StationAddress, &OldConfigData->StationAddress)) { + // + // The StationAddress is not the same. + // + return FALSE; + } + + + if (!EFI_IP6_EQUAL (&NewConfigData->RemoteAddress, &OldConfigData->RemoteAddress)) { + // + // The remoteaddress is not the same. + // + return FALSE; + } + + if (!NetIp6IsUnspecifiedAddr (&NewConfigData->RemoteAddress) && + (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 Ip6 configdata from the Udp6ConfigData. + + @param[in] Udp6ConfigData Pointer to the EFI_UDP6_CONFIG_DATA. + @param[in, out] Ip6ConfigData Pointer to the EFI_IP6_CONFIG_DATA. + +**/ +VOID +Udp6BuildIp6ConfigData ( + IN EFI_UDP6_CONFIG_DATA *Udp6ConfigData, + IN OUT EFI_IP6_CONFIG_DATA *Ip6ConfigData + ) +{ + CopyMem ( + Ip6ConfigData, + &mIp6IoDefaultIpConfigData, + sizeof (EFI_IP6_CONFIG_DATA) + ); + Ip6ConfigData->DefaultProtocol = EFI_IP_PROTO_UDP; + Ip6ConfigData->AcceptPromiscuous = Udp6ConfigData->AcceptPromiscuous; + IP6_COPY_ADDRESS (&Ip6ConfigData->StationAddress, &Udp6ConfigData->StationAddress); + IP6_COPY_ADDRESS (&Ip6ConfigData->DestinationAddress, &Udp6ConfigData->RemoteAddress); + // + // Use the -1 magic number to disable the receiving process of the ip instance. + // + Ip6ConfigData->ReceiveTimeout = (UINT32) (-1); +} + + +/** + This function validates the TxToken. It returns the error code according to the spec. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] TxToken Pointer to the token to be checked. + + @retval EFI_SUCCESS The TxToken is valid. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 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; + UdpSessionData.DestinationAddress are not valid + unicast IPv6 addresses if the UdpSessionData is + not NULL; + UdpSessionData.DestinationPort and + ConfigData.RemotePort are all zero if the + UdpSessionData is not NULL. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP + packet size. + +**/ +EFI_STATUS +Udp6ValidateTxToken ( + IN UDP6_INSTANCE_DATA *Instance, + IN EFI_UDP6_COMPLETION_TOKEN *TxToken + ) +{ + EFI_UDP6_TRANSMIT_DATA *TxData; + UINT32 Index; + UINT32 TotalLen; + EFI_UDP6_CONFIG_DATA *ConfigData; + EFI_UDP6_SESSION_DATA *UdpSessionData; + + + 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; + } + + ConfigData = &Instance->ConfigData; + UdpSessionData = TxData->UdpSessionData; + + if (UdpSessionData != NULL) { + + if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) { + // + // Ambiguous; no avalaible DestinationPort for this token. + // + return EFI_INVALID_PARAMETER; + } + + if (NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress) && + NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress) + ) { + // + // The DestinationAddress is not specificed. + // + return EFI_INVALID_PARAMETER; + } + + if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress) && + !NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress) + ) { + // + // The ConfigData.RemoteAddress is not zero and the UdpSessionData.DestinationAddress + // is not zero too. + // + return EFI_INVALID_PARAMETER; + } + } else if (NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)) { + // + // The configured RemoteAddress is all zero, and the user doesn't override the + // destination address. + // + return EFI_INVALID_PARAMETER; + } + + if (TxData->DataLength > UDP6_MAX_DATA_SIZE) { + return EFI_BAD_BUFFER_SIZE; + } + + return EFI_SUCCESS; +} + + +/** + This function checks whether the specified Token duplicates the one in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM contain the pointer to + the Token. + @param[in] Context Pointer to the Token to be checked. + + @retval EFI_SUCCESS The Token specified by Context differs from the + one in the Item. + @retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item. + +**/ +EFI_STATUS +EFIAPI +Udp6TokenExist ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Context + ) +{ + EFI_UDP6_COMPLETION_TOKEN *Token; + EFI_UDP6_COMPLETION_TOKEN *TokenInItem; + + Token = (EFI_UDP6_COMPLETION_TOKEN *) Context; + TokenInItem = (EFI_UDP6_COMPLETION_TOKEN *) Item->Key; + + if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) { + // + // The Token duplicates with the TokenInItem in case either the two pointers are the + // same, or the Events of these two tokens are the same. + // + return EFI_ACCESS_DENIED; + } + + return EFI_SUCCESS; +} + + +/** + This function calculates the checksum for the Packet, utilizing the pre-calculated + pseudo HeadSum to reduce some overhead. + + @param[in] Packet Pointer to the NET_BUF contains the udp datagram. + @param[in] HeadSum Checksum of the pseudo header, execpt the length + field. + + @return The 16-bit checksum of this udp datagram. + +**/ +UINT16 +Udp6Checksum ( + IN NET_BUF *Packet, + IN UINT16 HeadSum + ) +{ + UINT16 Checksum; + + Checksum = NetbufChecksum (Packet); + Checksum = NetAddChecksum (Checksum, HeadSum); + + Checksum = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize)); + Checksum = (UINT16) (~Checksum); + return Checksum; +} + + +/** + This function removes the specified Token from the TokenMap. + + @param[in] TokenMap Pointer to the NET_MAP containing the tokens. + @param[in] Token Pointer to the Token to be removed. + + @retval EFI_SUCCESS The specified Token is removed from the TokenMap. + @retval EFI_NOT_FOUND The specified Token is not found in the TokenMap. + +**/ +EFI_STATUS +Udp6RemoveToken ( + IN NET_MAP *TokenMap, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ) +{ + NET_MAP_ITEM *Item; + + // + // Find the Token first. + // + Item = NetMapFindKey (TokenMap, (VOID *) Token); + + if (Item != NULL) { + // + // Remove the token if it's found in the map. + // + NetMapRemoveItem (TokenMap, Item, NULL); + + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + + +/** + This function is the packet transmitting notify function registered to the IpIo + interface. It's called to signal the udp TxToken when IpIo layer completes the + transmitting of the udp datagram. + + @param[in] Status The completion status of the output udp datagram. + @param[in] Context Pointer to the context data. + @param[in] Sender Specify a EFI_IP6_PROTOCOL for sending. + @param[in] NotifyData Pointer to the notify data. + +**/ +VOID +EFIAPI +Udp6DgramSent ( + IN EFI_STATUS Status, + IN VOID *Context, + IN IP_IO_IP_PROTOCOL Sender, + IN VOID *NotifyData + ) +{ + UDP6_INSTANCE_DATA *Instance; + EFI_UDP6_COMPLETION_TOKEN *Token; + + Instance = (UDP6_INSTANCE_DATA *) Context; + Token = (EFI_UDP6_COMPLETION_TOKEN *) NotifyData; + + if (Udp6RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) { + // + // The token may be cancelled. Only signal it if the remove operation succeeds. + // + Token->Status = Status; + gBS->SignalEvent (Token->Event); + DispatchDpc (); + } +} + + +/** + This function processes the received datagram passed up by the IpIo layer. + + @param[in] Status The status of this udp datagram. + @param[in] IcmpError The IcmpError code, only available when Status is + EFI_ICMP_ERROR. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA. + @param[in] Packet Pointer to the NET_BUF containing the received udp + datagram. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp6DgramRcvd ( + IN EFI_STATUS Status, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet, + IN VOID *Context + ) +{ + NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE); + + // + // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR. + // + if (Status == EFI_SUCCESS) { + + // + // Demultiplex the received datagram. + // + Udp6Demultiplex ((UDP6_SERVICE_DATA *) Context, NetSession, Packet); + } else { + // + // Handle the ICMP6 Error packet. + // + Udp6IcmpHandler ((UDP6_SERVICE_DATA *) Context, IcmpError, NetSession, Packet); + } + + // + // Dispatch the DPC queued by the NotifyFunction of the rx token's events + // that are signaled with received data. + // + DispatchDpc (); +} + + +/** + This function removes the multicast group specified by Arg from the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the Arg, it's the pointer to a + multicast IPv6 Address. This parameter is + optional and may be NULL. + + @retval EFI_SUCCESS The multicast address is removed. + @retval EFI_ABORTED The specified multicast address is removed, and the + Arg is not NULL. + +**/ +EFI_STATUS +EFIAPI +Udp6LeaveGroup ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ) +{ + EFI_IPv6_ADDRESS *McastIp; + + McastIp = Arg; + + if ((McastIp != NULL) && + !EFI_IP6_EQUAL (McastIp, ((EFI_IPv6_ADDRESS *)Item->Key)) + ) { + // + // McastIp is not NULL and the multicast address contained in the Item + // is not the same as McastIp. + // + return EFI_SUCCESS; + } + + FreePool (Item->Key); + + // + // 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[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the token to be cancelled. If NULL, all + the tokens in this Map will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The token is cancelled if Arg is NULL, or the token + is not the same as that in the Item, if Arg is not + NULL. + @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is + cancelled. + +**/ +EFI_STATUS +EFIAPI +Udp6CancelTokens ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ) +{ + EFI_UDP6_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 Udp6DgramSent, 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_UDP6_COMPLETION_TOKEN *) Item->Key; + NetMapRemoveItem (Map, Item, NULL); + + TokenToCancel->Status = EFI_ABORTED; + gBS->SignalEvent (TokenToCancel->Event); + } + + if (Arg != NULL) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + + +/** + This function removes all the Wrap datas in the RcvdDgramQue. + + @param[in] Instance Pointer to the Udp6 Instance. + +**/ +VOID +Udp6FlushRcvdDgram ( + IN UDP6_INSTANCE_DATA *Instance + ) +{ + UDP6_RXDATA_WRAP *Wrap; + + while (!IsListEmpty (&Instance->RcvdDgramQue)) { + // + // Iterate all the Wraps in the RcvdDgramQue. + // + Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP6_RXDATA_WRAP, Link); + + // + // The Wrap will be removed from the RcvdDgramQue by this function call. + // + Udp6RecycleRxDataWrap (NULL, (VOID *) Wrap); + } +} + + + +/** + Cancel Udp6 tokens from the Udp6 instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Token Pointer to the token to be canceled. If NULL, all + tokens in this instance will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Udp6InstanceCancelToken ( + IN UDP6_INSTANCE_DATA *Instance, + IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // Cancel this token from the TxTokens map. + // + Status = NetMapIterate (&Instance->TxTokens, Udp6CancelTokens, Token); + + if ((Token != NULL) && (Status == EFI_ABORTED)) { + // + // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from + // the TxTokens and returns 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, Udp6CancelTokens, 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 checks if the received udp datagram matches with the Instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Udp6Session Pointer to the EFI_UDP6_SESSION_DATA abstracted + from the received udp datagram. + + @retval TRUE The udp datagram matches the receiving requirements of the Instance. + @retval FALSE The udp datagram does not matche the receiving requirements of the Instance. + +**/ +BOOLEAN +Udp6MatchDgram ( + IN UDP6_INSTANCE_DATA *Instance, + IN EFI_UDP6_SESSION_DATA *Udp6Session + ) +{ + EFI_UDP6_CONFIG_DATA *ConfigData; + EFI_IPv6_ADDRESS Destination; + + ConfigData = &Instance->ConfigData; + + if (ConfigData->AcceptPromiscuous) { + // + // Always matches if this instance is in the promiscuous state. + // + return TRUE; + } + + if ((!ConfigData->AcceptAnyPort && (Udp6Session->DestinationPort != ConfigData->StationPort)) || + ((ConfigData->RemotePort != 0) && (Udp6Session->SourcePort != ConfigData->RemotePort)) + ) { + // + // The local port or the remote port doesn't match. + // + return FALSE; + } + + if (!NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress) && + !EFI_IP6_EQUAL (&ConfigData->RemoteAddress, &Udp6Session->SourceAddress) + ) { + // + // This datagram doesn't come from the instance's specified sender. + // + return FALSE; + } + + if (NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress) || + EFI_IP6_EQUAL (&Udp6Session->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; + } + + IP6_COPY_ADDRESS (&Destination, &Udp6Session->DestinationAddress); + + if (IP6_IS_MULTICAST (&Destination) && + (NULL != Udp6MapMultiCastAddr (&Instance->McastIps, &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[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp6RecycleRxDataWrap ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UDP6_RXDATA_WRAP *Wrap; + + Wrap = (UDP6_RXDATA_WRAP *) Context; + + // + // Remove the Wrap from the list it belongs to. + // + RemoveEntryList (&Wrap->Link); + + // + // Free the Packet associated with this Wrap. + // + NetbufFree (Wrap->Packet); + + // + // Close the event. + // + gBS->CloseEvent (Wrap->RxData.RecycleSignal); + + FreePool (Wrap); +} + + +/** + This function wraps the Packet into RxData. + + @param[in] Instance Pointer to the instance context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP6_RECEIVE_DATA of this + datagram. + + @return Pointer to the structure wrapping the RxData and the Packet. + +**/ +UDP6_RXDATA_WRAP * +Udp6WrapRxData ( + IN UDP6_INSTANCE_DATA *Instance, + IN NET_BUF *Packet, + IN EFI_UDP6_RECEIVE_DATA *RxData + ) +{ + EFI_STATUS Status; + UDP6_RXDATA_WRAP *Wrap; + + // + // Allocate buffer for the Wrap. + // + Wrap = AllocateZeroPool (sizeof (UDP6_RXDATA_WRAP) + + (Packet->BlockOpNum - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA)); + if (Wrap == NULL) { + return NULL; + } + + InitializeListHead (&Wrap->Link); + + CopyMem (&Wrap->RxData, RxData, sizeof(EFI_UDP6_RECEIVE_DATA)); + // + // Create the Recycle event. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + Udp6RecycleRxDataWrap, + Wrap, + &Wrap->RxData.RecycleSignal + ); + if (EFI_ERROR (Status)) { + FreePool (Wrap); + return NULL; + } + + Wrap->Packet = Packet; + Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout; + + return Wrap; +} + + +/** + This function enqueues the received datagram into the instances' receiving queues. + + @param[in] Udp6Service Pointer to the udp service context data. + @param[in] Packet Pointer to the buffer containing the received + datagram. + @param[in] RxData Pointer to the EFI_UDP6_RECEIVE_DATA of this + datagram. + + @return The times this datagram is enqueued. + +**/ +UINTN +Udp6EnqueueDgram ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN NET_BUF *Packet, + IN EFI_UDP6_RECEIVE_DATA *RxData + ) +{ + LIST_ENTRY *Entry; + UDP6_INSTANCE_DATA *Instance; + UDP6_RXDATA_WRAP *Wrap; + UINTN Enqueued; + + Enqueued = 0; + + NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) { + // + // Iterate the instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link); + + if (!Instance->Configured) { + continue; + } + + if (Udp6MatchDgram (Instance, &RxData->UdpSession)) { + // + // Wrap the RxData and put this Wrap into the instances RcvdDgramQue. + // + Wrap = Udp6WrapRxData (Instance, Packet, RxData); + if (Wrap == NULL) { + continue; + } + + NET_GET_REF (Packet); + + InsertTailList (&Instance->RcvdDgramQue, &Wrap->Link); + + Enqueued++; + } + } + + return Enqueued; +} + + +/** + This function delivers the received datagrams to the specified instance. + + @param[in] Instance Pointer to the instance context data. + +**/ +VOID +Udp6InstanceDeliverDgram ( + IN UDP6_INSTANCE_DATA *Instance + ) +{ + UDP6_RXDATA_WRAP *Wrap; + EFI_UDP6_COMPLETION_TOKEN *Token; + NET_BUF *Dup; + EFI_UDP6_RECEIVE_DATA *RxData; + EFI_TPL OldTpl; + + if (!IsListEmpty (&Instance->RcvdDgramQue) && + !NetMapIsEmpty (&Instance->RxTokens) + ) { + + Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP6_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_UDP6_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL); + + // + // Build the FragmentTable and set the FragmentCount in RxData. + // + RxData = &Wrap->RxData; + RxData->FragmentCount = Wrap->Packet->BlockOpNum; + + NetbufBuildExt ( + Wrap->Packet, + (NET_FRAGMENT *) RxData->FragmentTable, + &RxData->FragmentCount + ); + + Token->Status = EFI_SUCCESS; + Token->Packet.RxData = &Wrap->RxData; + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Instance->DeliveredDgramQue, &Wrap->Link); + gBS->RestoreTPL (OldTpl); + + gBS->SignalEvent (Token->Event); + } +} + + +/** + This function delivers the datagrams enqueued in the instances. + + @param[in] Udp6Service Pointer to the udp service context data. + +**/ +VOID +Udp6DeliverDgram ( + IN UDP6_SERVICE_DATA *Udp6Service + ) +{ + LIST_ENTRY *Entry; + UDP6_INSTANCE_DATA *Instance; + + NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) { + // + // Iterate the instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link); + + if (!Instance->Configured) { + continue; + } + + // + // Deliver the datagrams of this instance. + // + Udp6InstanceDeliverDgram (Instance); + } +} + + +/** + This function demultiplexes the received udp datagram to the appropriate instances. + + @param[in] Udp6Service Pointer to the udp service context data. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstrated from + the received datagram. + @param[in] Packet Pointer to the buffer containing the received udp + datagram. + +**/ +VOID +Udp6Demultiplex ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN EFI_NET_SESSION_DATA *NetSession, + IN NET_BUF *Packet + ) +{ + EFI_UDP_HEADER *Udp6Header; + UINT16 HeadSum; + EFI_UDP6_RECEIVE_DATA RxData; + EFI_UDP6_SESSION_DATA *Udp6Session; + UINTN Enqueued; + + // + // Get the datagram header from the packet buffer. + // + Udp6Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL); + ASSERT (Udp6Header != NULL); + + if (Udp6Header->Checksum != 0) { + // + // check the checksum. + // + HeadSum = NetIp6PseudoHeadChecksum ( + &NetSession->Source.v6, + &NetSession->Dest.v6, + EFI_IP_PROTO_UDP, + 0 + ); + + if (Udp6Checksum (Packet, HeadSum) != 0) { + // + // Wrong checksum. + // + return; + } + } + + gRT->GetTime (&RxData.TimeStamp, NULL); + + Udp6Session = &RxData.UdpSession; + Udp6Session->SourcePort = NTOHS (Udp6Header->SrcPort); + Udp6Session->DestinationPort = NTOHS (Udp6Header->DstPort); + + IP6_COPY_ADDRESS (&Udp6Session->SourceAddress, &NetSession->Source); + IP6_COPY_ADDRESS (&Udp6Session->DestinationAddress, &NetSession->Dest); + + // + // Trim the UDP header. + // + NetbufTrim (Packet, UDP6_HEADER_SIZE, TRUE); + + RxData.DataLength = (UINT32) Packet->TotalSize; + + // + // Try to enqueue this datagram into the instances. + // + Enqueued = Udp6EnqueueDgram (Udp6Service, Packet, &RxData); + + if (Enqueued == 0) { + // + // Send the port unreachable ICMP packet before we free this NET_BUF + // + Udp6SendPortUnreach (Udp6Service->IpIo, NetSession, Udp6Header); + } + + // + // Try to free the packet before deliver it. + // + NetbufFree (Packet); + + if (Enqueued > 0) { + // + // Deliver the datagram. + // + Udp6DeliverDgram (Udp6Service); + } +} + + +/** + This function builds and sends out a icmp port unreachable message. + + @param[in] IpIo Pointer to the IP_IO instance. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet + causes this icmp error message. + @param[in] Udp6Header Pointer to the udp header of the datagram causes + this icmp error message. + +**/ +VOID +Udp6SendPortUnreach ( + IN IP_IO *IpIo, + IN EFI_NET_SESSION_DATA *NetSession, + IN VOID *Udp6Header + ) +{ + NET_BUF *Packet; + UINT32 Len; + IP6_ICMP_ERROR_HEAD *IcmpErrHdr; + UINT8 *Ptr; + IP_IO_OVERRIDE Override; + IP_IO_IP_INFO *IpSender; + EFI_IP6_MODE_DATA *Ip6ModeData; + EFI_STATUS Status; + EFI_IP6_PROTOCOL *Ip6Protocol; + + Ip6ModeData = NULL; + + // + // An ICMPv6 error message MUST NOT be originated as A packet destined to + // 1) an IPv6 multicast address 2) The IPv6 Unspecified Address + // + if (NetSession->IpVersion == IP_VERSION_6) { + if (NetIp6IsUnspecifiedAddr (&NetSession->Dest.v6) || + IP6_IS_MULTICAST (&NetSession->Dest.v6) + ) { + goto EXIT; + } + } + + + IpSender = IpIoFindSender (&IpIo, NetSession->IpVersion, &NetSession->Dest); + + // + // Get the Ipv6 Mode Data. + // + Ip6ModeData = AllocateZeroPool (sizeof (EFI_IP6_MODE_DATA)); + ASSERT (Ip6ModeData != NULL); + + // + // If not finding the related IpSender use the default IpIo to send out + // the port unreachable ICMP message. + // + if (IpSender == NULL) { + Ip6Protocol = IpIo->Ip.Ip6; + } else { + Ip6Protocol = IpSender->Ip.Ip6; + } + + Status = Ip6Protocol->GetModeData ( + Ip6Protocol, + Ip6ModeData, + NULL, + NULL + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + // + // The ICMP6 packet length, includes whole invoking packet and ICMP6 error header. + // + Len = NetSession->IpHdrLen + + NTOHS(((EFI_UDP_HEADER *) Udp6Header)->Length) + + sizeof (IP6_ICMP_ERROR_HEAD); + + // + // If the ICMP6 packet length larger than IP MTU, adjust its length to MTU. + // + if (Ip6ModeData->MaxPacketSize < Len) { + Len = Ip6ModeData->MaxPacketSize; + } + + // + // Allocate buffer for the icmp error message. + // + Packet = NetbufAlloc (Len); + if (Packet == NULL) { + goto EXIT; + } + + // + // Allocate space for the IP6_ICMP_ERROR_HEAD. + // + IcmpErrHdr = (IP6_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE); + ASSERT (IcmpErrHdr != NULL); + + // + // Set the required fields for the icmp port unreachable message. + // + IcmpErrHdr->Head.Type = ICMP_V6_DEST_UNREACHABLE; + IcmpErrHdr->Head.Code = ICMP_V6_PORT_UNREACHABLE; + IcmpErrHdr->Head.Checksum = 0; + IcmpErrHdr->Fourth = 0; + + // + // Copy as much of invoking Packet as possible without the ICMPv6 packet + // exceeding the minimum Ipv6 MTU. The length of IP6_ICMP_ERROR_HEAD contains + // the length of EFI_IP6_HEADER, so when using the length of IP6_ICMP_ERROR_HEAD + // for pointer movement that fact should be considered. + // + Ptr = (VOID *) &IcmpErrHdr->Head; + Ptr = (UINT8 *) (UINTN) ((UINTN) Ptr + sizeof (IP6_ICMP_ERROR_HEAD) - sizeof (EFI_IP6_HEADER)); + CopyMem (Ptr, NetSession->IpHdr.Ip6Hdr, NetSession->IpHdrLen); + CopyMem ( + Ptr + NetSession->IpHdrLen, + Udp6Header, + Len - NetSession->IpHdrLen - sizeof (IP6_ICMP_ERROR_HEAD) + sizeof (EFI_IP6_HEADER) + ); + + // + // Set the checksum as zero, and IP6 driver will calcuate it with pseudo header. + // + IcmpErrHdr->Head.Checksum = 0; + + // + // Fill the override data. + // + Override.Ip6OverrideData.FlowLabel = 0; + Override.Ip6OverrideData.HopLimit = 255; + Override.Ip6OverrideData.Protocol = IP6_ICMP; + + // + // Send out this icmp packet. + // + IpIoSend (IpIo, Packet, IpSender, NULL, NULL, &NetSession->Source, &Override); + + NetbufFree (Packet); + +EXIT: + if (Ip6ModeData != NULL) { + FreePool (Ip6ModeData); + } +} + + +/** + This function handles the received Icmp Error message and de-multiplexes it to the + instance. + + @param[in] Udp6Service Pointer to the udp service context data. + @param[in] IcmpError The icmp error code. + @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted + from the received Icmp Error packet. + @param[in, out] Packet Pointer to the Icmp Error packet. + +**/ +VOID +Udp6IcmpHandler ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN UINT8 IcmpError, + IN EFI_NET_SESSION_DATA *NetSession, + IN OUT NET_BUF *Packet + ) +{ + EFI_UDP_HEADER *Udp6Header; + EFI_UDP6_SESSION_DATA Udp6Session; + LIST_ENTRY *Entry; + UDP6_INSTANCE_DATA *Instance; + + Udp6Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL); + ASSERT (Udp6Header != NULL); + + IP6_COPY_ADDRESS (&Udp6Session.SourceAddress, &NetSession->Source); + IP6_COPY_ADDRESS (&Udp6Session.DestinationAddress, &NetSession->Dest); + + Udp6Session.SourcePort = NTOHS (Udp6Header->DstPort); + Udp6Session.DestinationPort = NTOHS (Udp6Header->SrcPort); + + NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) { + // + // Iterate all the instances. + // + Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link); + + if (!Instance->Configured) { + continue; + } + + if (Udp6MatchDgram (Instance, &Udp6Session)) { + // + // Translate the Icmp Error code according to the udp spec. + // + Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, IP_VERSION_6, NULL, NULL); + + if (IcmpError > ICMP_ERR_UNREACH_PORT) { + Instance->IcmpError = EFI_ICMP_ERROR; + } + + // + // Notify the instance with the received Icmp Error. + // + Udp6ReportIcmpError (Instance); + + break; + } + } + + NetbufFree (Packet); +} + + +/** + This function reports the received ICMP error. + + @param[in] Instance Pointer to the udp instance context data. + +**/ +VOID +Udp6ReportIcmpError ( + IN UDP6_INSTANCE_DATA *Instance + ) +{ + EFI_UDP6_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_UDP6_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL); + + if (Token != NULL) { + // + // Report the error through the Token. + // + Token->Status = Instance->IcmpError; + gBS->SignalEvent (Token->Event); + + // + // Clear the IcmpError. + // + Instance->IcmpError = EFI_SUCCESS; + } + } +} + + +/** + This function is a dummy ext-free function for the NET_BUF created for the output + udp datagram. + + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp6NetVectorExtFree ( + IN VOID *Context + ) +{ +} + + +/** + Set the Udp6 variable data. + + @param[in] Udp6Service Udp6 service data. + + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the + variable. + @retval other Set variable failed. + +**/ +EFI_STATUS +Udp6SetVariableData ( + IN UDP6_SERVICE_DATA *Udp6Service + ) +{ + UINT32 NumConfiguredInstance; + LIST_ENTRY *Entry; + UINTN VariableDataSize; + EFI_UDP6_VARIABLE_DATA *Udp6VariableData; + EFI_UDP6_SERVICE_POINT *Udp6ServicePoint; + UDP6_INSTANCE_DATA *Udp6Instance; + CHAR16 *NewMacString; + EFI_STATUS Status; + + NumConfiguredInstance = 0; + + // + // Go through the children list to count the configured children. + // + NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) { + Udp6Instance = NET_LIST_USER_STRUCT_S ( + Entry, + UDP6_INSTANCE_DATA, + Link, + UDP6_INSTANCE_DATA_SIGNATURE + ); + + if (Udp6Instance->Configured) { + NumConfiguredInstance++; + } + } + + // + // Calculate the size of the Udp6VariableData. As there may be no Udp6 child, + // we should add extra buffer for the service points only if the number of configured + // children is more than 1. + // + VariableDataSize = sizeof (EFI_UDP6_VARIABLE_DATA); + + if (NumConfiguredInstance > 1) { + VariableDataSize += sizeof (EFI_UDP6_SERVICE_POINT) * (NumConfiguredInstance - 1); + } + + Udp6VariableData = AllocateZeroPool (VariableDataSize); + if (Udp6VariableData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Udp6VariableData->DriverHandle = Udp6Service->ImageHandle; + Udp6VariableData->ServiceCount = NumConfiguredInstance; + + Udp6ServicePoint = &Udp6VariableData->Services[0]; + + // + // Go through the children list to fill the configured children's address pairs. + // + NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) { + Udp6Instance = NET_LIST_USER_STRUCT_S ( + Entry, + UDP6_INSTANCE_DATA, + Link, + UDP6_INSTANCE_DATA_SIGNATURE + ); + + if (Udp6Instance->Configured) { + Udp6ServicePoint->InstanceHandle = Udp6Instance->ChildHandle; + Udp6ServicePoint->LocalPort = Udp6Instance->ConfigData.StationPort; + Udp6ServicePoint->RemotePort = Udp6Instance->ConfigData.RemotePort; + + IP6_COPY_ADDRESS ( + &Udp6ServicePoint->LocalAddress, + &Udp6Instance->ConfigData.StationAddress + ); + IP6_COPY_ADDRESS ( + &Udp6ServicePoint->RemoteAddress, + &Udp6Instance->ConfigData.RemoteAddress + ); + Udp6ServicePoint++; + } + } + + // + // Get the MAC string. + // + Status = NetLibGetMacString ( + Udp6Service->ControllerHandle, + Udp6Service->ImageHandle, + &NewMacString + ); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + if (Udp6Service->MacString != NULL) { + // + // The variable is set already, we're going to update it. + // + if (StrCmp (Udp6Service->MacString, NewMacString) != 0) { + // + // The MAC address is changed, delete the previous variable first. + // + gRT->SetVariable ( + Udp6Service->MacString, + &gEfiUdp6ServiceBindingProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, + NULL + ); + } + + FreePool (Udp6Service->MacString); + } + + Udp6Service->MacString = NewMacString; + + Status = gRT->SetVariable ( + Udp6Service->MacString, + &gEfiUdp6ServiceBindingProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + VariableDataSize, + (VOID *) Udp6VariableData + ); + +EXIT: + + FreePool (Udp6VariableData); + + return Status; +} + + +/** + Clear the variable and free the resource. + + @param[in, out] Udp6Service Udp6 service data. + +**/ +VOID +Udp6ClearVariableData ( + IN OUT UDP6_SERVICE_DATA *Udp6Service + ) +{ + ASSERT (Udp6Service->MacString != NULL); + + gRT->SetVariable ( + Udp6Service->MacString, + &gEfiUdp6ServiceBindingProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, + NULL + ); + + FreePool (Udp6Service->MacString); + Udp6Service->MacString = NULL; +} + + +/** + Find the key in the netmap. + + @param[in] Map The netmap to search within. + @param[in] Key The key to search. + + @return The point to the item contains the Key, or NULL, if Key isn't in the map. + +**/ +NET_MAP_ITEM * +Udp6MapMultiCastAddr ( + IN NET_MAP *Map, + IN VOID *Key + ) +{ + LIST_ENTRY *Entry; + NET_MAP_ITEM *Item; + EFI_IPv6_ADDRESS *Addr; + + ASSERT (Map != NULL); + NET_LIST_FOR_EACH (Entry, &Map->Used) { + Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link); + Addr = (EFI_IPv6_ADDRESS *) Item->Key; + if (EFI_IP6_EQUAL (Addr, Key)) { + return Item; + } + } + return NULL; +} + diff --git a/NetworkPkg/Udp6Dxe/Udp6Impl.h b/NetworkPkg/Udp6Dxe/Udp6Impl.h new file mode 100644 index 0000000000..108e30b71c --- /dev/null +++ b/NetworkPkg/Udp6Dxe/Udp6Impl.h @@ -0,0 +1,673 @@ +/** @file + Udp6 driver's whole implementation and internal data structures. + + Copyright (c) 2009 - 2010, 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. + +**/ + +#ifndef _UDP6_IMPL_H_ +#define _UDP6_IMPL_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Udp6Driver.h" + +extern EFI_COMPONENT_NAME2_PROTOCOL gUdp6ComponentName2; +extern EFI_COMPONENT_NAME_PROTOCOL gUdp6ComponentName; +extern EFI_SERVICE_BINDING_PROTOCOL mUdp6ServiceBinding; +extern EFI_UDP6_PROTOCOL mUdp6Protocol; +extern UINT16 mUdp6RandomPort; + +// +// Define time out 50 milliseconds +// +#define UDP6_TIMEOUT_INTERVAL (50 * TICKS_PER_MS) +#define UDP6_HEADER_SIZE sizeof (EFI_UDP_HEADER) +#define UDP6_MAX_DATA_SIZE 65507 +#define UDP6_PORT_KNOWN 1024 + +#define UDP6_SERVICE_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'p', '6') +#define UDP6_INSTANCE_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'p', 'S') + +#define UDP6_SERVICE_DATA_FROM_THIS(a) \ + CR ( \ + (a), \ + UDP6_SERVICE_DATA, \ + ServiceBinding, \ + UDP6_SERVICE_DATA_SIGNATURE \ + ) + +#define UDP6_INSTANCE_DATA_FROM_THIS(a) \ + CR ( \ + (a), \ + UDP6_INSTANCE_DATA, \ + Udp6Proto, \ + UDP6_INSTANCE_DATA_SIGNATURE \ + ) +// +// Udp6 service contest data +// +typedef struct _UDP6_SERVICE_DATA { + UINT32 Signature; + EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; + EFI_HANDLE ImageHandle; + EFI_HANDLE ControllerHandle; + LIST_ENTRY ChildrenList; + UINTN ChildrenNumber; + IP_IO *IpIo; + EFI_EVENT TimeoutEvent; + CHAR16 *MacString; +} UDP6_SERVICE_DATA; + +typedef struct _UDP6_INSTANCE_DATA { + UINT32 Signature; + LIST_ENTRY Link; + UDP6_SERVICE_DATA *Udp6Service; + EFI_UDP6_PROTOCOL Udp6Proto; + EFI_UDP6_CONFIG_DATA ConfigData; + EFI_HANDLE ChildHandle; + BOOLEAN Configured; + BOOLEAN IsNoMapping; + NET_MAP TxTokens; + NET_MAP RxTokens; + NET_MAP McastIps; + LIST_ENTRY RcvdDgramQue; + LIST_ENTRY DeliveredDgramQue; + UINT16 HeadSum; + EFI_STATUS IcmpError; + IP_IO_IP_INFO *IpInfo; + BOOLEAN Destroyed; +} UDP6_INSTANCE_DATA; + +typedef struct _UDP6_RXDATA_WRAP { + LIST_ENTRY Link; + NET_BUF *Packet; + UINT32 TimeoutTick; + EFI_UDP6_RECEIVE_DATA RxData; +} UDP6_RXDATA_WRAP; + +/** + Clean the Udp service context data. + + @param[in, out] Udp6Service Pointer to the UDP6_SERVICE_DATA. + +**/ +VOID +Udp6CleanService ( + IN OUT UDP6_SERVICE_DATA *Udp6Service + ); + +/** + Create the Udp service context data. + + @param[in] Udp6Service Pointer to the UDP6_SERVICE_DATA. + @param[in] ImageHandle The image handle of this udp6 driver. + @param[in] ControllerHandle The controller handle this udp6 driver binds on. + + @retval EFI_SUCCESS The udp6 service context data was created and + initialized. + @retval EFI_OUT_OF_RESOURCES Cannot allocate memory. + @retval Others An error condition occurred. + +**/ +EFI_STATUS +Udp6CreateService ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle + ); + +/** + Set the Udp6 variable data. + + @param[in] Udp6Service Udp6 service data. + + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the + variable. + @retval other Set variable failed. + +**/ +EFI_STATUS +Udp6SetVariableData ( + IN UDP6_SERVICE_DATA *Udp6Service + ); + +/** + This function cleans the udp instance. + + @param[in, out] Instance Pointer to the UDP6_INSTANCE_DATA to clean. + +**/ +VOID +Udp6CleanInstance ( + IN OUT UDP6_INSTANCE_DATA *Instance + ); + +/** + Clear the variable and free the resource. + + @param[in, out] Udp6Service Udp6 service data. + +**/ +VOID +Udp6ClearVariableData ( + IN OUT UDP6_SERVICE_DATA *Udp6Service + ); + +/** + This function intializes the new created udp instance. + + @param[in] Udp6Service Pointer to the UDP6_SERVICE_DATA. + @param[in, out] Instance Pointer to the un-initialized UDP6_INSTANCE_DATA. + +**/ +VOID +Udp6InitInstance ( + IN UDP6_SERVICE_DATA *Udp6Service, + IN OUT UDP6_INSTANCE_DATA *Instance + ); + +/** + This function reports the received ICMP error. + + @param[in] Instance Pointer to the udp instance context data. + +**/ +VOID +Udp6ReportIcmpError ( + IN UDP6_INSTANCE_DATA *Instance + ); + +/** + This function copies the current operational settings of this EFI UDPv6 Protocol + instance into user-supplied buffers. This function is used optionally to retrieve + the operational mode data of underlying networks or drivers. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[out] Udp6ConfigData The buffer in which the current UDP configuration + data is returned. This parameter is optional and + may be NULL. + @param[out] Ip6ModeData The buffer in which the current EFI IPv6 Protocol + mode data is returned. This parameter is optional + and may be NULL. + @param[out] MnpConfigData The buffer in which the current managed network + configuration data is returned. This parameter + is optional and may be NULL. + @param[out] SnpModeData The buffer in which the simple network mode data + is returned. This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED When Udp6ConfigData is queried, no configuration + data is available because this instance has not + been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +EFI_STATUS +EFIAPI +Udp6GetModeData ( + IN EFI_UDP6_PROTOCOL *This, + OUT EFI_UDP6_CONFIG_DATA *Udp6ConfigData OPTIONAL, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + This function is used to do the following: + Initialize and start this instance of the EFI UDPv6 Protocol. + Change the filtering rules and operational parameters. + Reset this instance of the EFI UDPv6 Protocol. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] UdpConfigData Pointer to the buffer to set the configuration + data. This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The configuration settings were set, changed, or + reset successfully. + @retval EFI_NO_MAPPING When the UdpConifgData.UseAnyStationAddress is set + to true and there is no address available for IP6 + driver to binding source address to this + instance. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + This is NULL. + UdpConfigData.StationAddress is not a valid + unicast IPv6 address. + UdpConfigData.RemoteAddress is not a valid unicast + IPv6 address, if it is not zero. + @retval EFI_ALREADY_STARTED The EFI UDPv6 Protocol instance is already + started/configured and must be stopped/reset + before it can be reconfigured. Only TrafficClass, + HopLimit, ReceiveTimeout, and TransmitTimeout can + be reconfigured without stopping the current + instance of the EFI UDPv6 Protocol. + @retval EFI_ACCESS_DENIED UdpConfigData.AllowDuplicatePort is FALSE, and + UdpConfigData.StationPort is already used by another + instance. + @retval EFI_OUT_OF_RESOURCES The EFI UDPv6 Protocol driver cannot allocate + memory for this EFI UDPv6 Protocol instance. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred, and + this instance was not opened. + +**/ +EFI_STATUS +EFIAPI +Udp6Configure ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL + ); + +/** + This function places a sending request to this instance of the EFI UDPv6 Protocol, + alongside the transmit data that was filled by the user. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to the completion token that will be + placed into the transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI UDPv6 Protocol instance has not been + started. + @retval EFI_NO_MAPPING The under-layer IPv6 driver was responsible for + choosing a source address for this instance, but + no source address was available for use. + @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. + One or more of the + Token.Packet.TxData.UdpSessionData. + DestinationAddres are not valid unicast IPv6 + addresses, if the UdpSessionData is not NULL. + Token.Packet.TxData.UdpSessionData. + DestinationAddres is NULL + Token.Packet.TxData.UdpSessionData. + DestinatioPort is zero. + Token.Packet.TxData.UdpSessionData is + NULL and this instance's + UdpConfigData.RemoteAddress is unspecified. + @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 +Udp6Transmit ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +/** + This function places a completion token into the receive packet queue. This function + is always asynchronous. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] 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 UDPv6 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 UDPv6 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 +Udp6Receive ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +/** + This function is used to abort a pending transmit or receive request. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_UDP6_PROTOCOL.Transmit() or + EFI_UDP6_PROTOCOL.Receive(). This parameter is + optional and may be NULL. + + @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 either completed or was not issued by + Transmit() or Receive(). + +**/ +EFI_STATUS +EFIAPI +Udp6Cancel ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + 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. + + @param[in] This Pointer to the EFI_UDP6_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 +Udp6Poll ( + IN EFI_UDP6_PROTOCOL *This + ); + +/** + This function is used to enable and disable the multicast group filtering. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] JoinFlag Set to TRUE to join a multicast group. Set to + FALSE to leave one or all multicast groups. + @param[in] MulticastAddress Pointer to multicast group address to join or + leave. This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv6 Protocol instance has not been + started. + @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 +Udp6Groups ( + IN EFI_UDP6_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv6_ADDRESS *MulticastAddress OPTIONAL + ); + +/** + This function tries to bind the udp instance according to the configured port + allocation stragety. + + @param[in] InstanceList Pointer to the head of the list linking the udp + instances. + @param[in] ConfigData Pointer to the ConfigData of the instance to be + bound. + + @retval EFI_SUCCESS The bound operation completed successfully. + @retval EFI_ACCESS_DENIED The specified by the ConfigData is + already used by another instance. + @retval EFI_OUT_OF_RESOURCES No available port resources. + +**/ +EFI_STATUS +Udp6Bind ( + IN LIST_ENTRY *InstanceList, + IN EFI_UDP6_CONFIG_DATA *ConfigData + ); + +/** + This function builds the Ip6 configdata from the Udp6ConfigData. + + @param[in] Udp6ConfigData Pointer to the EFI_UDP6_CONFIG_DATA. + @param[in, out] Ip6ConfigData Pointer to the EFI_IP6_CONFIG_DATA. + +**/ +VOID +Udp6BuildIp6ConfigData ( + IN EFI_UDP6_CONFIG_DATA *Udp6ConfigData, + IN OUT EFI_IP6_CONFIG_DATA *Ip6ConfigData + ); + +/** + This function checks whether the specified Token duplicates with the one in the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM contain the pointer to + the Token. + @param[in] Context Pointer to the Token to be checked. + + @retval EFI_SUCCESS The Token specified by Context differs from the + one in the Item. + @retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item. + +**/ +EFI_STATUS +EFIAPI +Udp6TokenExist ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Context + ); + +/** + This function removes the specified Token from the TokenMap. + + @param[in] TokenMap Pointer to the NET_MAP containing the tokens. + @param[in] Token Pointer to the Token to be removed. + + @retval EFI_SUCCESS The specified Token is removed from the TokenMap. + @retval EFI_NOT_FOUND The specified Token is not found in the TokenMap. + +**/ +EFI_STATUS +Udp6RemoveToken ( + IN NET_MAP *TokenMap, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +/** + This function is used to check whether the NewConfigData has any un-reconfigurable + parameters changed compared to the OldConfigData. + + @param[in] OldConfigData Pointer to the current ConfigData the udp instance + uses. + @param[in] NewConfigData Pointer to the new ConfigData. + + @retval TRUE The instance is reconfigurable according to NewConfigData. + @retval FALSE The instance is not reconfigurable according to NewConfigData. + +**/ +BOOLEAN +Udp6IsReconfigurable ( + IN EFI_UDP6_CONFIG_DATA *OldConfigData, + IN EFI_UDP6_CONFIG_DATA *NewConfigData + ); + +/** + This function removes the multicast group specified by Arg from the Map. + + @param[in] Map Pointer to the NET_MAP. + @param[in] Item Pointer to the NET_MAP_ITEM. + @param[in] Arg Pointer to the Arg. It is the pointer to a + multicast IPv6 Address. This parameter is + optional and may be NULL. + + @retval EFI_SUCCESS The multicast address is removed. + @retval EFI_ABORTED The specified multicast address is removed, and the + Arg is not NULL. + +**/ +EFI_STATUS +EFIAPI +Udp6LeaveGroup ( + IN NET_MAP *Map, + IN NET_MAP_ITEM *Item, + IN VOID *Arg OPTIONAL + ); + +/** + This function validates the TxToken, it returns the error code according to the spec. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] TxToken Pointer to the token to be checked. + + @retval EFI_SUCCESS The TxToken is valid. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 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. + UdpSessionData.DestinationAddress are not valid + unicast IPv6 addresses if the UdpSessionData is + not NULL. + UdpSessionData.DestinationPort and + ConfigData.RemotePort are all zero if the + UdpSessionData is not NULL. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP + packet size. + +**/ +EFI_STATUS +Udp6ValidateTxToken ( + IN UDP6_INSTANCE_DATA *Instance, + IN EFI_UDP6_COMPLETION_TOKEN *TxToken + ); + +/** + This function is a dummy ext-free function for the NET_BUF created for the output + udp datagram. + + @param[in] Context Pointer to the context data. + +**/ +VOID +EFIAPI +Udp6NetVectorExtFree ( + IN VOID *Context + ); + +/** + This function calculates the checksum for the Packet, utilizing the pre-calculated + pseudo header to reduce overhead. + + @param[in] Packet Pointer to the NET_BUF contains the udp datagram. + @param[in] HeadSum Checksum of the pseudo header execpt the length + field. + + @return The 16-bit checksum of this udp datagram. + +**/ +UINT16 +Udp6Checksum ( + IN NET_BUF *Packet, + IN UINT16 HeadSum + ); + +/** + This function delivers the received datagrams to the specified instance. + + @param[in] Instance Pointer to the instance context data. + +**/ +VOID +Udp6InstanceDeliverDgram ( + IN UDP6_INSTANCE_DATA *Instance + ); + +/** + Cancel Udp6 tokens from the Udp6 instance. + + @param[in] Instance Pointer to the udp instance context data. + @param[in] Token Pointer to the token to be canceled. If NULL, all + tokens in this instance will be cancelled. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The Token is cancelled. + @retval EFI_NOT_FOUND The Token is not found. + +**/ +EFI_STATUS +Udp6InstanceCancelToken ( + IN UDP6_INSTANCE_DATA *Instance, + IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + This function removes all the Wrap datas in the RcvdDgramQue. + + @param[in] Instance Pointer to the Udp6 Instance. + +**/ +VOID +Udp6FlushRcvdDgram ( + IN UDP6_INSTANCE_DATA *Instance + ); + +#endif + diff --git a/NetworkPkg/Udp6Dxe/Udp6Main.c b/NetworkPkg/Udp6Dxe/Udp6Main.c new file mode 100644 index 0000000000..0cad596276 --- /dev/null +++ b/NetworkPkg/Udp6Dxe/Udp6Main.c @@ -0,0 +1,855 @@ +/** @file + Contains all EFI_UDP6_PROTOCOL interfaces. + + Copyright (c) 2009 - 2010, 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. + +**/ + +#include "Udp6Impl.h" + +EFI_UDP6_PROTOCOL mUdp6Protocol = { + Udp6GetModeData, + Udp6Configure, + Udp6Groups, + Udp6Transmit, + Udp6Receive, + Udp6Cancel, + Udp6Poll +}; + + +/** + This function copies the current operational settings of this EFI UDPv6 Protocol + instance into user-supplied buffers. This function is used optionally to retrieve + the operational mode data of underlying networks or drivers. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[out] Udp6ConfigData The buffer in which the current UDP configuration + data is returned. This parameter is optional and + may be NULL. + @param[out] Ip6ModeData The buffer in which the current EFI IPv6 Protocol + mode data is returned. This parameter is optional + and may be NULL. + @param[out] MnpConfigData The buffer in which the current managed network + configuration data is returned. This parameter is + optional and may be NULL. + @param[out] SnpModeData The buffer in which the simple network mode data + is returned. This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED When Udp6ConfigData is queried, no configuration + data is available because this instance has not + been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +EFI_STATUS +EFIAPI +Udp6GetModeData ( + IN EFI_UDP6_PROTOCOL *This, + OUT EFI_UDP6_CONFIG_DATA *Udp6ConfigData OPTIONAL, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ) +{ + UDP6_INSTANCE_DATA *Instance; + EFI_IP6_PROTOCOL *Ip; + EFI_TPL OldTpl; + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured && (Udp6ConfigData != NULL)) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (Udp6ConfigData != NULL) { + // + // Set the Udp6ConfigData. + // + CopyMem (Udp6ConfigData, &Instance->ConfigData, sizeof (EFI_UDP6_CONFIG_DATA)); + } + + Ip = Instance->IpInfo->Ip.Ip6; + + // + // Get the underlying Ip6ModeData, MnpConfigData and SnpModeData. + // + Status = Ip->GetModeData (Ip, Ip6ModeData, MnpConfigData, SnpModeData); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + This function is used to do the following: + Initialize and start this instance of the EFI UDPv6 Protocol. + Change the filtering rules and operational parameters. + Reset this instance of the EFI UDPv6 Protocol. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] UdpConfigData Pointer to the buffer to set the configuration + data. This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The configuration settings were set, changed, or + reset successfully. + @retval EFI_NO_MAPPING When the UdpConifgData.UseAnyStationAddress is set + to true and there is no address available for the IP6 + driver to bind a source address to this instance. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + This is NULL. + UdpConfigData.StationAddress is not a valid + unicast IPv6 address. + UdpConfigData.RemoteAddress is not a valid unicast + IPv6 address if it is not zero. + @retval EFI_ALREADY_STARTED The EFI UDPv6 Protocol instance is already + started/configured and must be stopped/reset + before it can be reconfigured. Only TrafficClass, + HopLimit, ReceiveTimeout, and TransmitTimeout can + be reconfigured without stopping the current + instance of the EFI UDPv6 Protocol. + @retval EFI_ACCESS_DENIED UdpConfigData.AllowDuplicatePort is FALSE and + UdpConfigData.StationPort is already used by another + instance. + @retval EFI_OUT_OF_RESOURCES The EFI UDPv6 Protocol driver cannot allocate + memory for this EFI UDPv6 Protocol instance. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred, and + this instance was not opened. + +**/ +EFI_STATUS +EFIAPI +Udp6Configure ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL + ) +{ + EFI_STATUS Status; + UDP6_INSTANCE_DATA *Instance; + UDP6_SERVICE_DATA *Udp6Service; + EFI_TPL OldTpl; + EFI_IPv6_ADDRESS StationAddress; + EFI_IPv6_ADDRESS RemoteAddress; + EFI_IP6_CONFIG_DATA Ip6ConfigData; + EFI_IPv6_ADDRESS LocalAddr; + EFI_IPv6_ADDRESS RemoteAddr; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured && (UdpConfigData == NULL)) { + return EFI_SUCCESS; + } + + Udp6Service = Instance->Udp6Service; + Status = EFI_SUCCESS; + ASSERT (Udp6Service != NULL); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (UdpConfigData != NULL) { + + IP6_COPY_ADDRESS (&StationAddress, &UdpConfigData->StationAddress); + IP6_COPY_ADDRESS (&RemoteAddress, &UdpConfigData->RemoteAddress); + + if ((!NetIp6IsUnspecifiedAddr (&StationAddress) && !NetIp6IsValidUnicast (&StationAddress)) || + (!NetIp6IsUnspecifiedAddr (&RemoteAddress) && !NetIp6IsValidUnicast (&RemoteAddress)) + ){ + // + // If not use default address, and StationAddress is not a valid unicast + // if it is not IPv6 address or RemoteAddress is not a valid unicast IPv6 + // 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 (!Udp6IsReconfigurable (&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.TrafficClass = UdpConfigData->TrafficClass; + Instance->ConfigData.HopLimit = UdpConfigData->HopLimit; + Instance->ConfigData.ReceiveTimeout = UdpConfigData->ReceiveTimeout; + Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout; + } else { + // + // Construct the Ip configuration data from the UdpConfigData. + // + Udp6BuildIp6ConfigData (UdpConfigData, &Ip6ConfigData); + + // + // Configure the Ip instance wrapped in the IpInfo. + // + Status = IpIoConfigIp (Instance->IpInfo, &Ip6ConfigData); + if (EFI_ERROR (Status)) { + if (Status == EFI_NO_MAPPING) { + Instance->IsNoMapping = TRUE; + } + + goto ON_EXIT; + } + + Instance->IsNoMapping = FALSE; + + // + // Save the configuration data. + // + CopyMem ( + &Instance->ConfigData, + UdpConfigData, + sizeof (EFI_UDP6_CONFIG_DATA) + ); + IP6_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip6ConfigData.StationAddress); + // + // Try to allocate the required port resource. + // + Status = Udp6Bind (&Udp6Service->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. + // + IP6_COPY_ADDRESS (&LocalAddr, &Instance->ConfigData.StationAddress); + IP6_COPY_ADDRESS (&RemoteAddr, &Instance->ConfigData.RemoteAddress); + + Instance->HeadSum = NetIp6PseudoHeadChecksum ( + &LocalAddr, + &RemoteAddr, + EFI_IP_PROTO_UDP, + 0 + ); + + Instance->Configured = TRUE; + } + } else { + // + // UdpConfigData is NULL, reset the instance. + // + Instance->Configured = FALSE; + Instance->IsNoMapping = FALSE; + + // + // Reset the Ip instance wrapped in the IpInfo. + // + IpIoConfigIp (Instance->IpInfo, NULL); + + // + // Cancel all the user tokens. + // + Status = Instance->Udp6Proto.Cancel (&Instance->Udp6Proto, NULL); + + // + // Remove the buffered RxData for this instance. + // + Udp6FlushRcvdDgram (Instance); + + ASSERT (IsListEmpty (&Instance->DeliveredDgramQue)); + } + + Status = Udp6SetVariableData (Instance->Udp6Service); + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + This function is used to enable and disable the multicast group filtering. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] JoinFlag Set to TRUE to join a multicast group. Set to + FALSE to leave one or all multicast groups. + @param[in] MulticastAddress Pointer to multicast group address to join or + leave. This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv6 Protocol instance has not been + started. + @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 +Udp6Groups ( + IN EFI_UDP6_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv6_ADDRESS *MulticastAddress OPTIONAL + ) +{ + EFI_STATUS Status; + UDP6_INSTANCE_DATA *Instance; + EFI_IP6_PROTOCOL *Ip; + EFI_TPL OldTpl; + EFI_IPv6_ADDRESS *McastIp; + + if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) { + return EFI_INVALID_PARAMETER; + } + + McastIp = NULL; + + if (JoinFlag) { + if (!IP6_IS_MULTICAST (MulticastAddress)) { + return EFI_INVALID_PARAMETER; + } + + McastIp = AllocateCopyPool (sizeof (EFI_IPv6_ADDRESS), MulticastAddress); + if (McastIp == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + Ip = Instance->IpInfo->Ip.Ip6; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Invoke the Ip instance the Udp6 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) { + + Status = NetMapInsertTail (&Instance->McastIps, (VOID *) McastIp, NULL); + } else { + + NetMapIterate (&Instance->McastIps, Udp6LeaveGroup, MulticastAddress); + } + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + if (EFI_ERROR (Status)) { + if (McastIp != NULL) { + FreePool (McastIp); + } + } + + return Status; +} + + + +/** + This function places a sending request to this instance of the EFI UDPv6 Protocol, + alongside the transmit data that was filled by the user. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to the completion token that will be + placed into the transmit queue. + + @retval EFI_SUCCESS The data was queued for transmission. + @retval EFI_NOT_STARTED This EFI UDPv6 Protocol instance has not been + started. + @retval EFI_NO_MAPPING The under-layer IPv6 driver was responsible for + choosing a source address for this instance, but + no source address was available for use. + @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. One or more of the + Token.Packet.TxData.UdpSessionData.DestinationAddres + are not valid unicast IPv6 + addresses if the UdpSessionData is not NULL. + Token.Packet.TxData.UdpSessionData. + DestinationAddress is NULL + Token.Packet.TxData.UdpSessionData. + DestinatioPort + is zero. + Token.Packet.TxData.UdpSessionData is NULL and this + instance's UdpConfigData.RemoteAddress is unspecified. + @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 +Udp6Transmit ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + UDP6_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + NET_BUF *Packet; + EFI_UDP_HEADER *Udp6Header; + EFI_UDP6_CONFIG_DATA *ConfigData; + EFI_IPv6_ADDRESS Source; + EFI_IPv6_ADDRESS Destination; + EFI_UDP6_TRANSMIT_DATA *TxData; + EFI_UDP6_SESSION_DATA *UdpSessionData; + UDP6_SERVICE_DATA *Udp6Service; + IP_IO_OVERRIDE Override; + UINT16 HeadSum; + EFI_IP_ADDRESS IpDestAddr; + + if ((This == NULL) || (Token == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Validate the Token, if the token is invalid return the error code. + // + Status = Udp6ValidateTxToken (Instance, Token); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token)) || + EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, 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, + UDP6_HEADER_SIZE, + 0, + Udp6NetVectorExtFree, + NULL + ); + if (Packet == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Store the IpIo in ProtoData. + // + Udp6Service = Instance->Udp6Service; + *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp6Service->IpIo); + + Udp6Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP6_HEADER_SIZE, TRUE); + ASSERT (Udp6Header != NULL); + ConfigData = &Instance->ConfigData; + + // + // Fill the udp header. + // + Udp6Header->SrcPort = HTONS (ConfigData->StationPort); + Udp6Header->DstPort = HTONS (ConfigData->RemotePort); + Udp6Header->Length = HTONS ((UINT16) Packet->TotalSize); + Udp6Header->Checksum = 0; + // + // Set the UDP Header in NET_BUF, this UDP header is for IP6 can fast get the + // Udp header for pseudoHeadCheckSum. + // + Packet->Udp = Udp6Header; + UdpSessionData = TxData->UdpSessionData; + + if (UdpSessionData != NULL) { + // + // Set the Destination according to the specified + // UdpSessionData. + // + + if (UdpSessionData->DestinationPort != 0) { + Udp6Header->DstPort = HTONS (UdpSessionData->DestinationPort); + } + + IP6_COPY_ADDRESS (&Source, &ConfigData->StationAddress); + if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress)) { + IP6_COPY_ADDRESS (&Destination, &UdpSessionData->DestinationAddress); + } else { + IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress); + } + + // + //Calculate the pseudo head checksum using the overridden parameters. + // + if (!NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress)) { + HeadSum = NetIp6PseudoHeadChecksum ( + &Source, + &Destination, + EFI_IP_PROTO_UDP, + 0 + ); + + // + // calculate the checksum. + // + Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum); + if (Udp6Header->Checksum == 0) { + // + // If the calculated checksum is 0, fill the Checksum field with all ones. + // + Udp6Header->Checksum = 0XFFFF; + } + } else { + // + // Set the checksum is zero if the ConfigData->StationAddress is unspcified + // and the Ipv6 will fill the correct value of this checksum. + // + Udp6Header->Checksum = 0; + + } + } else { + // + // UdpSessionData is NULL, use the address and port information previously configured. + // + IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress); + + HeadSum = Instance->HeadSum; + // + // calculate the checksum. + // + Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum); + if (Udp6Header->Checksum == 0) { + // + // If the calculated checksum is 0, fill the Checksum field with all ones. + // + Udp6Header->Checksum = 0xffff; + } + } + + + + // + // Fill the IpIo Override data. + // + Override.Ip6OverrideData.Protocol = EFI_IP_PROTO_UDP; + Override.Ip6OverrideData.HopLimit = ConfigData->HopLimit; + Override.Ip6OverrideData.FlowLabel = 0; + + // + // 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. + // + if (UdpSessionData != NULL){ + IP6_COPY_ADDRESS (&(IpDestAddr.v6), &Destination); + } else { + ZeroMem (&IpDestAddr.v6, sizeof (EFI_IPv6_ADDRESS)); + } + + Status = IpIoSend ( + Udp6Service->IpIo, + Packet, + Instance->IpInfo, + Instance, + Token, + &IpDestAddr, + &Override + ); + if (EFI_ERROR (Status)) { + // + // Remove this token from the TxTokens. + // + Udp6RemoveToken (&Instance->TxTokens, Token); + } + +FREE_PACKET: + + NetbufFree (Packet); + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + This function places a completion token into the receive packet queue. This function + is always asynchronous. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to a token that is associated with the + receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI UDPv6 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 UDPv6 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 +Udp6Receive ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ) +{ + EFI_STATUS Status; + UDP6_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + + if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token)) || + EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token)) + ){ + // + // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or + // RxTokens map. + // + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + Token->Packet.RxData = NULL; + + // + // Save the token into the RxTokens map. + // + Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_READY; + goto ON_EXIT; + } + + // + // If there is an icmp error, report it. + // + Udp6ReportIcmpError (Instance); + + // + // Try to delivered the received datagrams. + // + Udp6InstanceDeliverDgram (Instance); + + // + // Dispatch the DPC queued by the NotifyFunction of Token->Event. + // + DispatchDpc (); + +ON_EXIT: + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + This function is used to abort a pending transmit or receive request. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_UDP6_PROTOCOL.Transmit() or + EFI_UDP6_PROTOCOL.Receive(). This parameter is + optional and may be NULL. + + @retval EFI_SUCCESS The asynchronous I/O request was aborted, and + Token.Event was signaled. When Token is NULL, all + pending requests are aborted and their events are + signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration + (DHCP, BOOTP, RARP, etc.) is not finished yet. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O + request is not found in the transmit or receive + queue. It is either completed or not issued by + Transmit() or Receive(). + +**/ +EFI_STATUS +EFIAPI +Udp6Cancel ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL + ) +{ + EFI_STATUS Status; + UDP6_INSTANCE_DATA *Instance; + EFI_TPL OldTpl; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + + if (!Instance->Configured) { + return EFI_NOT_STARTED; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Cancle the tokens specified by Token for this instance. + // + Status = Udp6InstanceCancelToken (Instance, Token); + + // + // Dispatch the DPC queued by the NotifyFunction of the canceled token's events. + // + DispatchDpc (); + + gBS->RestoreTPL (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. + + @param[in] This Pointer to the EFI_UDP6_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 +Udp6Poll ( + IN EFI_UDP6_PROTOCOL *This + ) +{ + UDP6_INSTANCE_DATA *Instance; + EFI_IP6_PROTOCOL *Ip; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance = UDP6_INSTANCE_DATA_FROM_THIS (This); + Ip = Instance->IpInfo->Ip.Ip6; + + // + // Invode the Ip instance consumed by the udp instance to do the poll operation. + // + return Ip->Poll (Ip); +} -- cgit v1.2.3