summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/Udp6Dxe
diff options
context:
space:
mode:
authorhhtian <hhtian@6f19259b-4bc3-4df7-8a09-765794883524>2010-11-01 06:13:54 +0000
committerhhtian <hhtian@6f19259b-4bc3-4df7-8a09-765794883524>2010-11-01 06:13:54 +0000
commita3bcde70e6dc69000f85cc5deee98101d2ae200a (patch)
tree693709a5293f80b320931693b34b2d6983cfcf4b /NetworkPkg/Udp6Dxe
parent12873d57666d0beff41959a1fb8f9062016f0983 (diff)
downloadedk2-a3bcde70e6dc69000f85cc5deee98101d2ae200a.tar.gz
edk2-a3bcde70e6dc69000f85cc5deee98101d2ae200a.tar.bz2
edk2-a3bcde70e6dc69000f85cc5deee98101d2ae200a.zip
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
Diffstat (limited to 'NetworkPkg/Udp6Dxe')
-rw-r--r--NetworkPkg/Udp6Dxe/ComponentName.c313
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Driver.c556
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Driver.h182
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Dxe.inf63
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Impl.c2131
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Impl.h673
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Main.c855
7 files changed, 4773 insertions, 0 deletions
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.<BR>
+
+ 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.<BR>
+
+ 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.<BR>
+
+ 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 <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/DevicePath.h>
+
+/**
+ 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.<BR>
+#
+# 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.<BR>
+
+ 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 <Address, Port> 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 <Address, Port> 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 <Address, Port> 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 <Address, Port> 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 <Address, Port> 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.<BR>
+
+ 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 <Uefi.h>
+
+#include <Protocol/Ip6.h>
+#include <Protocol/Udp6.h>
+
+#include <Library/IpIoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DpcLib.h>
+
+#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 <Address, Port> 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.<BR>
+
+ 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);
+}