summaryrefslogtreecommitdiff
path: root/NetworkPkg/Mtftp6Dxe
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/Mtftp6Dxe
parent12873d57666d0beff41959a1fb8f9062016f0983 (diff)
downloadedk2-platforms-a3bcde70e6dc69000f85cc5deee98101d2ae200a.tar.xz
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/Mtftp6Dxe')
-rw-r--r--NetworkPkg/Mtftp6Dxe/ComponentName.c308
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Driver.c703
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Driver.h151
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf69
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Impl.c634
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h469
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Option.c416
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Option.h148
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c900
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Support.c1189
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Support.h359
-rw-r--r--NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c602
12 files changed, 5948 insertions, 0 deletions
diff --git a/NetworkPkg/Mtftp6Dxe/ComponentName.c b/NetworkPkg/Mtftp6Dxe/ComponentName.c
new file mode 100644
index 0000000000..0f91b64c44
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/ComponentName.c
@@ -0,0 +1,308 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Mtftp6 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 "Mtftp6Impl.h"
+
+
+/**
+ 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
+Mtftp6ComponentNameGetDriverName (
+ 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 bus drivers
+ attempting to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that attempts 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
+Mtftp6ComponentNameGetControllerName (
+ 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 gMtftp6ComponentName = {
+ Mtftp6ComponentNameGetDriverName,
+ Mtftp6ComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMtftp6ComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Mtftp6ComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Mtftp6ComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mMtftp6DriverNameTable[] = {
+ {
+ "eng;en",
+ L"MTFTP6 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
+Mtftp6ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mMtftp6DriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gMtftp6ComponentName)
+ );
+}
+
+/**
+ 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
+ attempting to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that attempts 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
+Mtftp6ComponentNameGetControllerName (
+ 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/Mtftp6Dxe/Mtftp6Driver.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Driver.c
new file mode 100644
index 0000000000..d448c78a34
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Driver.c
@@ -0,0 +1,703 @@
+/** @file
+ Driver Binding functions and Service Binding functions
+ implementation for Mtftp6 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 "Mtftp6Impl.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gMtftp6DriverBinding = {
+ Mtftp6DriverBindingSupported,
+ Mtftp6DriverBindingStart,
+ Mtftp6DriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_SERVICE_BINDING_PROTOCOL gMtftp6ServiceBindingTemplate = {
+ Mtftp6ServiceBindingCreateChild,
+ Mtftp6ServiceBindingDestroyChild
+};
+
+
+/**
+ Destory the MTFTP6 service. The MTFTP6 service may be partly initialized,
+ or partly destroyed. If a resource is destroyed, it is marked as such in
+ case the destroy failed and is called again later.
+
+ @param[in] Service The MTFTP6 service to be destroyed.
+
+**/
+VOID
+Mtftp6DestroyService (
+ IN MTFTP6_SERVICE *Service
+ )
+{
+ //
+ // Make sure all children instances have been already destoryed.
+ //
+ ASSERT (Service->ChildrenNum == 0);
+
+ if (Service->DummyUdpIo != NULL) {
+ UdpIoFreeIo (Service->DummyUdpIo);
+ }
+
+ if (Service->Timer != NULL) {
+ gBS->CloseEvent (Service->Timer);
+ }
+
+ FreePool (Service);
+}
+
+
+/**
+ Create then initialize a MTFTP6 service binding instance.
+
+ @param[in] Controller The controller to install the MTFTP6 service
+ binding on.
+ @param[in] Image The driver binding image of the MTFTP6 driver.
+ @param[out] Service The variable to receive the created service
+ binding instance.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to create the instance
+ @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep connection with UDP.
+ @retval EFI_SUCCESS The service instance is created for the controller.
+
+**/
+EFI_STATUS
+Mtftp6CreateService (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Image,
+ OUT MTFTP6_SERVICE **Service
+ )
+{
+ MTFTP6_SERVICE *Mtftp6Srv;
+ EFI_STATUS Status;
+
+ ASSERT (Service != NULL);
+
+ *Service = NULL;
+ Mtftp6Srv = AllocateZeroPool (sizeof (MTFTP6_SERVICE));
+
+ if (Mtftp6Srv == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mtftp6Srv->Signature = MTFTP6_SERVICE_SIGNATURE;
+ Mtftp6Srv->Controller = Controller;
+ Mtftp6Srv->Image = Image;
+ Mtftp6Srv->InDestory = FALSE;
+ Mtftp6Srv->ChildrenNum = 0;
+
+ CopyMem (
+ &Mtftp6Srv->ServiceBinding,
+ &gMtftp6ServiceBindingTemplate,
+ sizeof (EFI_SERVICE_BINDING_PROTOCOL)
+ );
+
+ InitializeListHead (&Mtftp6Srv->Children);
+
+ //
+ // Create a internal timer for all instances.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,
+ TPL_CALLBACK,
+ Mtftp6OnTimerTick,
+ Mtftp6Srv,
+ &Mtftp6Srv->Timer
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Mtftp6Srv);
+ return Status;
+ }
+
+ //
+ // Create a dummy Udp6Io to build parent-child relationship between Udp6 driver
+ // and Mtftp6 driver.
+ //
+ Mtftp6Srv->DummyUdpIo = UdpIoCreateIo (
+ Controller,
+ Image,
+ Mtftp6ConfigDummyUdpIo,
+ UDP_IO_UDP6_VERSION,
+ NULL
+ );
+
+ if (Mtftp6Srv->DummyUdpIo == NULL) {
+ gBS->CloseEvent (Mtftp6Srv->Timer);
+ FreePool (Mtftp6Srv);
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Service = Mtftp6Srv;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Destroy the MTFTP6 instance and recycle the resources.
+
+ @param[in] Instance The pointer to the MTFTP6 instance.
+
+**/
+VOID
+Mtftp6DestroyInstance (
+ IN MTFTP6_INSTANCE *Instance
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ MTFTP6_BLOCK_RANGE *Block;
+
+ if (Instance->Config != NULL) {
+ FreePool (Instance->Config);
+ }
+
+ if (Instance->Token != NULL && Instance->Token->Event != NULL) {
+ gBS->SignalEvent (Instance->Token->Event);
+ }
+
+ if (Instance->LastPacket != NULL) {
+ NetbufFree (Instance->LastPacket);
+ }
+
+ if (Instance->UdpIo!= NULL) {
+ UdpIoFreeIo (Instance->UdpIo);
+ }
+
+ if (Instance->McastUdpIo != NULL) {
+ UdpIoFreeIo (Instance->McastUdpIo);
+ }
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->BlkList) {
+ Block = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
+ RemoveEntryList (Entry);
+ FreePool (Block);
+ }
+
+ FreePool (Instance);
+}
+
+
+/**
+ Create the MTFTP6 instance and initialize it.
+
+ @param[in] Service The pointer to the MTFTP6 service.
+ @param[out] Instance The pointer to the MTFTP6 instance.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+ @retval EFI_SUCCESS The MTFTP6 instance is created.
+
+**/
+EFI_STATUS
+Mtftp6CreateInstance (
+ IN MTFTP6_SERVICE *Service,
+ OUT MTFTP6_INSTANCE **Instance
+ )
+{
+ MTFTP6_INSTANCE *Mtftp6Ins;
+
+ *Instance = NULL;
+ Mtftp6Ins = AllocateZeroPool (sizeof (MTFTP6_INSTANCE));
+
+ if (Mtftp6Ins == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mtftp6Ins->Signature = MTFTP6_INSTANCE_SIGNATURE;
+ Mtftp6Ins->InDestory = FALSE;
+ Mtftp6Ins->Service = Service;
+
+ CopyMem (
+ &Mtftp6Ins->Mtftp6,
+ &gMtftp6ProtocolTemplate,
+ sizeof (EFI_MTFTP6_PROTOCOL)
+ );
+
+ InitializeListHead (&Mtftp6Ins->Link);
+ InitializeListHead (&Mtftp6Ins->BlkList);
+
+ *Instance = Mtftp6Ins;
+
+ 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.
+
+ Entry point of the MTFTP6 driver to install various protocols.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.
+ @param[in] SystemTable The 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
+Mtftp6DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gMtftp6DriverBinding,
+ ImageHandle,
+ &gMtftp6ComponentName,
+ &gMtftp6ComponentName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. This service
+ is called by the EFI boot service ConnectController(). In
+ order to make drivers as small as possible, there are calling
+ restrictions for this service. ConnectController() must
+ follow these calling restrictions. If any other agent wishes to call
+ Supported(), it must also follow these calling restrictions.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child.
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval Others This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ return gBS->OpenProtocol (
+ Controller,
+ &gEfiUdp6ServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+}
+
+
+/**
+ 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 calling restrictions for
+ this service. ConnectController() must follow these
+ calling restrictions. If any other agent wishes to call Start() it
+ must also follow these calling restrictions.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval Others This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ MTFTP6_SERVICE *Service;
+ EFI_STATUS Status;
+
+ //
+ // Directly return if driver is already running on this Nic handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiMtftp6ServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create Mtftp6 service for this Nic handle
+ //
+ Status = Mtftp6CreateService (
+ Controller,
+ This->DriverBindingHandle,
+ &Service
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (Service != NULL);
+
+ //
+ // Start the internal timer to track the packet retransmission.
+ //
+ Status = gBS->SetTimer (
+ Service->Timer,
+ TimerPeriodic,
+ TICKS_PER_SECOND
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Install the Mtftp6 service on the Nic handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiMtftp6ServiceBindingProtocolGuid,
+ &Service->ServiceBinding,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ Mtftp6DestroyService (Service);
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle. This service is called by the
+ EFI boot service DisconnectController(). In order to
+ make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController()
+ must follow these calling restrictions. If any other agent wishes
+ to call Stop() it must also follow these calling restrictions.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to stop driver on
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero, stop the entire bus driver.
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle.
+ @retval EFI_DEVICE_ERROR An unexpected error.
+ @retval Others This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ MTFTP6_SERVICE *Service;
+ MTFTP6_INSTANCE *Instance;
+ EFI_HANDLE NicHandle;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Locate the Nic handle to retrieve the Mtftp6 private data.
+ //
+ NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp6ProtocolGuid);
+
+ if (NicHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ NicHandle,
+ &gEfiMtftp6ServiceBindingProtocolGuid,
+ (VOID **) &ServiceBinding,
+ This->DriverBindingHandle,
+ NicHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Service = MTFTP6_SERVICE_FROM_THIS (ServiceBinding);
+
+ if (Service->InDestory) {
+ return EFI_SUCCESS;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (NumberOfChildren == 0) {
+ //
+ // Destory the Mtftp6 service if there is no Mtftp6 child instance left.
+ //
+ Service->InDestory = TRUE;
+
+ gBS->UninstallProtocolInterface (
+ NicHandle,
+ &gEfiMtftp6ServiceBindingProtocolGuid,
+ ServiceBinding
+ );
+
+ Mtftp6DestroyService (Service);
+
+ } else {
+ //
+ // Destory the Mtftp6 child instance one by one.
+ //
+ while (!IsListEmpty (&Service->Children)) {
+ Instance = NET_LIST_HEAD (&Service->Children, MTFTP6_INSTANCE, Link);
+ Mtftp6ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
+ }
+
+ if (Service->ChildrenNum != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ 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 ChildHandle is NULL.
+ @retval Others The child handle was not created.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ )
+{
+ MTFTP6_SERVICE *Service;
+ MTFTP6_INSTANCE *Instance;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ VOID *Udp6;
+
+ if (This == NULL || ChildHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Service = MTFTP6_SERVICE_FROM_THIS (This);
+
+ Status = Mtftp6CreateInstance (Service, &Instance);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (Instance != NULL);
+
+ //
+ // Install the Mtftp6 protocol on the new child handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiMtftp6ProtocolGuid,
+ &Instance->Mtftp6,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Instance->Handle = *ChildHandle;
+
+ //
+ // Open the Udp6 protocol by child.
+ //
+ Status = gBS->OpenProtocol (
+ Service->DummyUdpIo->UdpHandle,
+ &gEfiUdp6ProtocolGuid,
+ (VOID **) &Udp6,
+ gMtftp6DriverBinding.DriverBindingHandle,
+ Instance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Instance->Handle,
+ &gEfiMtftp6ProtocolGuid,
+ &Instance->Mtftp6,
+ NULL
+ );
+
+ goto ON_ERROR;
+ }
+
+ //
+ // Add the new Mtftp6 instance into the children list of Mtftp6 service.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ InsertTailList (&Service->Children, &Instance->Link);
+ Service->ChildrenNum++;
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ Mtftp6DestroyInstance (Instance);
+ return Status;
+}
+
+
+/**
+ Destroys a child handle with a protocol installed on it.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+ last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param[in] ChildHandle Handle of the child to destroy.
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
+ @retval Others The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ MTFTP6_SERVICE *Service;
+ MTFTP6_INSTANCE *Instance;
+ EFI_MTFTP6_PROTOCOL *Mtftp6;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || ChildHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Locate the Nic handle to retrieve the Mtftp6 private data.
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiMtftp6ProtocolGuid,
+ (VOID **) &Mtftp6,
+ gMtftp6DriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Instance = MTFTP6_INSTANCE_FROM_THIS (Mtftp6);
+ Service = MTFTP6_SERVICE_FROM_THIS (This);
+
+ if (Instance->Service != Service) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the instance already in destory state.
+ //
+ if (Instance->InDestory) {
+ return EFI_SUCCESS;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Instance->InDestory = TRUE;
+
+ gBS->CloseProtocol (
+ Service->DummyUdpIo->UdpHandle,
+ &gEfiUdp6ProtocolGuid,
+ gMtftp6DriverBinding.DriverBindingHandle,
+ ChildHandle
+ );
+
+ //
+ // Uninstall the MTFTP6 protocol first to enable a top down destruction.
+ //
+ Status = gBS->UninstallProtocolInterface (
+ ChildHandle,
+ &gEfiMtftp6ProtocolGuid,
+ Mtftp6
+ );
+
+ if (EFI_ERROR (Status)) {
+ Instance->InDestory = FALSE;
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+ }
+
+ //
+ // Remove the Mtftp6 instance from the children list of Mtftp6 service.
+ //
+ RemoveEntryList (&Instance->Link);
+ Service->ChildrenNum --;
+
+ Mtftp6DestroyInstance (Instance);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Driver.h b/NetworkPkg/Mtftp6Dxe/Mtftp6Driver.h
new file mode 100644
index 0000000000..94f73a80a9
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Driver.h
@@ -0,0 +1,151 @@
+/** @file
+ Driver Binding functions and Service Binding functions
+ declaration for Mtftp6 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.
+
+**/
+
+#ifndef __EFI_MTFTP6_DRIVER_H__
+#define __EFI_MTFTP6_DRIVER_H__
+
+#include <Protocol/ServiceBinding.h>
+
+extern EFI_COMPONENT_NAME_PROTOCOL gMtftp6ComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gMtftp6ComponentName2;
+
+/**
+ Test to see if this driver supports ControllerHandle. This service
+ is called by the EFI boot service ConnectController(). In
+ order to make drivers as small as possible, there are a few calling
+ restrictions for this service. ConnectController() must
+ follow these calling restrictions. If any other agent wishes to call
+ Supported(), it must also follow these calling restrictions.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval Others This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ 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 calling restrictions for
+ this service. ConnectController() must follow these
+ calling restrictions. If any other agent wishes to call Start() it
+ must also follow these calling restrictions.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval Others This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ 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 calling
+ restrictions for this service. DisconnectController()
+ must follow these calling restrictions. If any other agent wishes
+ to call Stop(), it must also follow these calling restrictions.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to stop driver on
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero, stop the entire bus driver.
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle.
+ @retval EFI_DEVICE_ERROR An unexpected error.
+ @retval Others This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Creates a child handle and installs a protocol.
+
+ The CreateChild() function installs a protocol on ChildHandle.
+ If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+ If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+ @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param[in, 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 ChildHandle is NULL.
+ @retval Others The child handle was not created.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ );
+
+/**
+ Destroys a child handle with a protocol installed on it.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+ last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param[in] ChildHandle Handle of the child to destroy.
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
+ @retval Others The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf b/NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf
new file mode 100644
index 0000000000..ecf1f7cf0d
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf
@@ -0,0 +1,69 @@
+## @file
+# Component description file for Mtftp6 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 = Mtftp6Dxe
+ FILE_GUID = 99F03B99-98D8-49dd-A8D3-3219D0FFE41E
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Mtftp6DriverEntryPoint
+ UNLOAD_IMAGE = NetLibDefaultUnload
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gMtftp6DriverBinding
+# COMPONENT_NAME = gMtftp6ComponentName
+# COMPONENT_NAME2 = gMtftp6ComponentName2
+#
+
+[Sources]
+ Mtftp6Driver.c
+ Mtftp6Driver.h
+ Mtftp6Impl.c
+ Mtftp6Impl.h
+ Mtftp6Option.c
+ Mtftp6Option.h
+ Mtftp6Support.h
+ Mtftp6Support.c
+ Mtftp6Rrq.c
+ Mtftp6Wrq.c
+ ComponentName.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+ NetLib
+ UdpIoLib
+
+
+[Protocols]
+ gEfiUdp6ServiceBindingProtocolGuid
+ gEfiUdp6ProtocolGuid
+ gEfiMtftp6ServiceBindingProtocolGuid
+ gEfiMtftp6ProtocolGuid
+
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.c
new file mode 100644
index 0000000000..fcbbf11134
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.c
@@ -0,0 +1,634 @@
+/** @file
+ This EFI_MTFTP6_PROTOCOL interface implementation.
+
+ It supports the following RFCs:
+ RFC1350 - THE TFTP PROTOCOL (REVISION 2)
+ RFC2090 - TFTP Multicast Option
+ RFC2347 - TFTP Option Extension
+ RFC2348 - TFTP Blocksize Option
+ RFC2349 - TFTP Timeout Interval and Transfer Size Options
+
+ 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 "Mtftp6Impl.h"
+
+EFI_MTFTP6_PROTOCOL gMtftp6ProtocolTemplate = {
+ EfiMtftp6GetModeData,
+ EfiMtftp6Configure,
+ EfiMtftp6GetInfo,
+ EfiMtftp6ParseOptions,
+ EfiMtftp6ReadFile,
+ EfiMtftp6WriteFile,
+ EfiMtftp6ReadDirectory,
+ EfiMtftp6Poll
+ };
+
+/**
+ Returns the current operating mode data for the MTFTP6 instance.
+
+ The GetModeData() function returns the current operating mode and
+ cached data packet for the MTFTP6 instance.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[out] ModeData The buffer in which the EFI MTFTPv6 Protocol driver mode
+ data is returned.
+
+ @retval EFI_SUCCESS The configuration data was returned successfully.
+ @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
+ @retval EFI_INVALID_PARAMETER This is NULL or ModeData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6GetModeData (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ OUT EFI_MTFTP6_MODE_DATA *ModeData
+ )
+{
+ MTFTP6_INSTANCE *Instance;
+ EFI_TPL OldTpl;
+
+ if (This == NULL || ModeData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance = MTFTP6_INSTANCE_FROM_THIS (This);
+
+ //
+ // Copy back the configure data if the instance already configured.
+ //
+ if (Instance->Config != NULL) {
+ CopyMem (
+ &ModeData->ConfigData,
+ Instance->Config,
+ sizeof (EFI_MTFTP6_CONFIG_DATA)
+ );
+ } else {
+ ZeroMem (
+ &ModeData->ConfigData,
+ sizeof (EFI_MTFTP6_CONFIG_DATA)
+ );
+ }
+
+ //
+ // Set the current support options in mode data.
+ //
+ ModeData->SupportedOptionCount = MTFTP6_SUPPORTED_OPTIONS_NUM;
+ ModeData->SupportedOptions = (UINT8 **) mMtftp6SupportedOptions;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initializes, changes, or resets the default operational setting for
+ this EFI MTFTPv6 Protocol driver instance.
+
+ The Configure() function is used to set and change the configuration
+ data for this EFI MTFTPv6 Protocol driver instance. The configuration
+ data can be reset to startup defaults by calling Configure() with
+ MtftpConfigData set to NULL. Whenever the instance is reset, any
+ pending operation is aborted. By changing the EFI MTFTPv6 Protocol
+ driver instance configuration data, the client can connect to
+ different MTFTPv6 servers. The configuration parameters in
+ MtftpConfigData are used as the default parameters in later MTFTPv6
+ operations and can be overridden in later operations.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] MtftpConfigData Pointer to the configuration data structure.
+
+ @retval EFI_SUCCESS The EFI MTFTPv6 Protocol instance was configured successfully.
+ @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
+ - This is NULL.
+ - MtftpConfigData.StationIp is neither zero nor one
+ of the configured IP addresses in the underlying IPv6 driver.
+ - MtftpCofigData.ServerIp is not a valid IPv6 unicast address.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_ACCESS_DENIED - The configuration could not be changed at this time because there
+ is some MTFTP background operation in progress.
+ - MtftpCofigData.LocalPort is already in use.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_OUT_OF_RESOURCES The EFI MTFTPv6 Protocol driver instance data could not be
+ allocated.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI
+ MTFTPv6 Protocol driver instance is not configured.
+ Note: It is not defined in the UEFI 2.3 Specification.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6Configure (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_CONFIG_DATA *MtftpConfigData OPTIONAL
+ )
+{
+ MTFTP6_SERVICE *Service;
+ MTFTP6_INSTANCE *Instance;
+ EFI_UDP6_PROTOCOL *Udp6;
+ EFI_UDP6_CONFIG_DATA Udp6Cfg;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MtftpConfigData != NULL && !NetIp6IsValidUnicast (&MtftpConfigData->ServerIp)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance = MTFTP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+ Status = EFI_SUCCESS;
+
+ if (MtftpConfigData == NULL) {
+ //
+ // Configure the instance as NULL to abort the current session.
+ //
+ Mtftp6OperationClean (Instance, EFI_ABORTED);
+ FreePool (Instance->Config);
+ Instance->Config = NULL;
+ } else {
+ //
+ // It's not allowed to configure one instance twice without configure null.
+ //
+ if (Instance->Config != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+ //
+ // Allocate the configure buffer of the instance and store the user's data.
+ //
+ Instance->Config = AllocateZeroPool (sizeof (EFI_MTFTP6_CONFIG_DATA));
+
+ if (Instance->Config == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ CopyMem (Instance->Config, MtftpConfigData, sizeof (EFI_MTFTP6_CONFIG_DATA));
+
+ //
+ // Don't configure the udpio here because each operation might override
+ // the configuration, so delay udpio configuration in each operation.
+ //
+ Instance->UdpIo = UdpIoCreateIo (
+ Service->Controller,
+ Service->Image,
+ Mtftp6ConfigDummyUdpIo,
+ UDP_IO_UDP6_VERSION,
+ NULL
+ );
+
+ if (Instance->UdpIo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Continue to configure the downside Udp6 instance by user's data.
+ //
+ ZeroMem (&Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
+
+ Udp6Cfg.AcceptPromiscuous = FALSE;
+ Udp6Cfg.AcceptAnyPort = FALSE;
+ Udp6Cfg.AllowDuplicatePort = FALSE;
+ Udp6Cfg.TrafficClass = 0;
+ Udp6Cfg.HopLimit = 128;
+ Udp6Cfg.ReceiveTimeout = 0;
+ Udp6Cfg.TransmitTimeout = 0;
+ Udp6Cfg.StationPort = Instance->Config->LocalPort;
+ Udp6Cfg.RemotePort = Instance->Config->InitialServerPort;
+
+ CopyMem (
+ &Udp6Cfg.StationAddress,
+ &Instance->Config->StationIp,
+ sizeof(EFI_IPv6_ADDRESS)
+ );
+
+ CopyMem (
+ &Udp6Cfg.RemoteAddress,
+ &Instance->Config->ServerIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ Udp6 = Instance->UdpIo->Protocol.Udp6;
+ Status = Udp6->Configure (Udp6, &Udp6Cfg);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ON_EXIT:
+ if (EFI_ERROR (Status)) {
+ if (Instance->Config != NULL) {
+ FreePool (Instance->Config);
+ Instance->Config = NULL;
+ }
+ if (Instance->UdpIo != NULL) {
+ UdpIoFreeIo (Instance->UdpIo);
+ Instance->UdpIo = NULL;
+ }
+ }
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Get the information of the download from the server.
+
+ The GetInfo() function assembles an MTFTPv6 request packet
+ with options, sends it to the MTFTPv6 server, and may return
+ an MTFTPv6 OACK, MTFTPv6 ERROR, or ICMP ERROR packet. Retries
+ occur only if no response packets are received from the MTFTPv6
+ server before the timeout expires.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] OverrideData Data that is used to override the existing parameters. If NULL, the
+ default parameters that were set in the EFI_MTFTP6_PROTOCOL.Configure()
+ function are used.
+ @param[in] Filename Pointer to ASCIIZ file name string.
+ @param[in] ModeStr Pointer to ASCIIZ mode string. If NULL, octet will be used.
+ @param[in] OptionCount Number of option/value string pairs in OptionList.
+ @param[in] OptionList Pointer to array of option/value string pairs. Ignored if
+ OptionCount is zero.
+ @param[out] PacketLength The number of bytes in the returned packet.
+ @param[out] Packet The pointer to the received packet. This buffer must be freed by
+ the caller.
+
+ @retval EFI_SUCCESS An MTFTPv6 OACK packet was received and is in the Packet.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Filename is NULL.
+ - OptionCount is not zero and OptionList is NULL.
+ - One or more options in OptionList have wrong format.
+ - PacketLength is NULL.
+ - OverrideData.ServerIp is not valid unicast IPv6 addresses.
+ @retval EFI_UNSUPPORTED One or more options in the OptionList are unsupported by
+ this implementation.
+ @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_ACCESS_DENIED The previous operation has not completed yet.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_TFTP_ERROR An MTFTPv6 ERROR packet was received and is in the Packet.
+ @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received and the Packet is set to NULL.
+ Note: It is not defined in UEFI 2.3 Specification.
+ @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received and the Packet is set to NULL.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received and the Packet is set to NULL.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received and the Packet is set to NULL.
+ @retval EFI_ICMP_ERROR Some other ICMP ERROR packet was received and the Packet is set to NULL.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv6 packet was received and is in the Packet.
+ @retval EFI_TIMEOUT No responses were received from the MTFTPv6 server.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+ @retval EFI_NO_MEDIA There was a media error.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6GetInfo (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_OVERRIDE_DATA *OverrideData OPTIONAL,
+ IN UINT8 *Filename,
+ IN UINT8 *ModeStr OPTIONAL,
+ IN UINT8 OptionCount,
+ IN EFI_MTFTP6_OPTION *OptionList OPTIONAL,
+ OUT UINT32 *PacketLength,
+ OUT EFI_MTFTP6_PACKET **Packet OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_MTFTP6_TOKEN Token;
+ MTFTP6_GETINFO_CONTEXT Context;
+
+ if (This == NULL ||
+ Filename == NULL ||
+ PacketLength == NULL ||
+ (OptionCount != 0 && OptionList == NULL) ||
+ (OverrideData != NULL && !NetIp6IsValidUnicast (&OverrideData->ServerIp))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Packet != NULL) {
+ *Packet = NULL;
+ }
+
+ *PacketLength = 0;
+
+ Context.Packet = Packet;
+ Context.PacketLen = PacketLength;
+ Context.Status = EFI_SUCCESS;
+
+ //
+ // Fill fields of the Token for GetInfo operation.
+ //
+ Token.Status = EFI_SUCCESS;
+ Token.Event = NULL;
+ Token.OverrideData = OverrideData;
+ Token.Filename = Filename;
+ Token.ModeStr = ModeStr;
+ Token.OptionCount = OptionCount;
+ Token.OptionList = OptionList;
+ Token.BufferSize = 0;
+ Token.Buffer = NULL;
+ Token.Context = &Context;
+ Token.CheckPacket = Mtftp6CheckPacket;
+ Token.TimeoutCallback = NULL;
+ Token.PacketNeeded = NULL;
+
+ //
+ // Start the GetInfo operation by issue the Token.
+ //
+ Status = Mtftp6OperationStart (This, &Token, EFI_MTFTP6_OPCODE_RRQ);
+
+ if (Status == EFI_ABORTED) {
+ //
+ // Return the status if failed to issue.
+ //
+ return Context.Status;
+ }
+
+ return Status;
+}
+
+
+/**
+ Parse the options in an MTFTPv6 OACK packet.
+
+ The ParseOptions() function parses the option fields in an MTFTPv6 OACK
+ packet and returns the number of options that were found, and optionally,
+ a list of pointers to the options in the packet. If one or more of the
+ option fields are not valid, then EFI_PROTOCOL_ERROR is returned and
+ *OptionCount and *OptionList stop at the last valid option.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] PacketLen Length of the OACK packet to be parsed.
+ @param[in] Packet Pointer to the OACK packet to be parsed.
+ @param[out] OptionCount Pointer to the number of options in the following OptionList.
+ @param[out] OptionList Pointer to EFI_MTFTP6_OPTION storage. Each pointer in the
+ OptionList points to the corresponding MTFTP option buffer
+ in the Packet. Call the EFI Boot Service FreePool() to
+ release the OptionList if the options in this OptionList
+ are not needed anymore.
+
+ @retval EFI_SUCCESS The OACK packet was valid and the OptionCount and
+ OptionList parameters have been updated.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - PacketLen is 0.
+ - Packet is NULL or Packet is not a valid MTFTPv6 packet.
+ - OptionCount is NULL.
+ @retval EFI_NOT_FOUND No options were found in the OACK packet.
+ @retval EFI_OUT_OF_RESOURCES Storage for the OptionList array can not be allocated.
+ @retval EFI_PROTOCOL_ERROR One or more of the option fields is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6ParseOptions (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN UINT32 PacketLen,
+ IN EFI_MTFTP6_PACKET *Packet,
+ OUT UINT32 *OptionCount,
+ OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL
+ )
+{
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Mtftp6ParseStart (Packet, PacketLen, OptionCount, OptionList);
+}
+
+
+/**
+ Download a file from an MTFTPv6 server.
+
+ The ReadFile() function is used to initialize and start an MTFTPv6 download
+ process, and optionally, wait for completion. When the download operation
+ completes, whether successfully or not, the Token.Status field is updated
+ by the EFI MTFTPv6 Protocol driver, and then Token.Event is signaled if it
+ is not NULL.
+ Data can be downloaded from the MTFTPv6 server into either of the following
+ locations:
+ - A fixed buffer that is pointed to by Token.Buffer
+ - A download service function that is pointed to by Token.CheckPacket.
+ If both Token.Buffer and Token.CheckPacket are used, then Token.CheckPacket
+ will be called first. If the call is successful, the packet will be stored
+ in Token.Buffer.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] Token Pointer to the token structure to provide the parameters that are
+ used in this operation.
+
+ @retval EFI_SUCCESS The data file has been transferred successfully.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is not zero but not large enough to hold the
+ downloaded data in downloading process.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_ABORTED Current operation is aborted by user.
+ @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_ICMP_ERROR An ICMP ERROR packet was received.
+ @retval EFI_TIMEOUT No responses were received from the MTFTPv6 server.
+ @retval EFI_TFTP_ERROR An MTFTPv6 ERROR packet was received.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+ @retval EFI_NO_MEDIA There was a media error.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6ReadFile (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token
+ )
+{
+ return Mtftp6OperationStart (This, Token, EFI_MTFTP6_OPCODE_RRQ);
+}
+
+
+/**
+ Send a file to an MTFTPv6 server.
+
+ The WriteFile() function is used to initialize an uploading operation
+ with the given option list and optionally wait for completion. If one
+ or more of the options is not supported by the server, the unsupported
+ options are ignored and a standard TFTP process starts instead. When
+ the upload process completes, whether successfully or not, Token.Event
+ is signaled, and the EFI MTFTPv6 Protocol driver updates Token.Status.
+ The caller can supply the data to be uploaded in the following two modes:
+ - Through the user-provided buffer
+ - Through a callback function
+ With the user-provided buffer, the Token.BufferSize field indicates
+ the length of the buffer, and the driver will upload the data in the
+ buffer. With an EFI_MTFTP6_PACKET_NEEDED callback function, the driver
+ will call this callback function to get more data from the user to upload.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] Token Pointer to the token structure to provide the parameters that are
+ used in this operation.
+
+ @retval EFI_SUCCESS The upload session has started.
+ @retval EFI_UNSUPPORTED The operation is not supported by this implementation.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Token is NULL.
+ - Token.Filename is NULL.
+ - Token.OptionCount is not zero and Token.OptionList is NULL.
+ - One or more options in Token.OptionList have wrong format.
+ - Token.Buffer and Token.PacketNeeded are both NULL.
+ - Token.OverrideData.ServerIp is not a valid unicast IPv6 address.
+ @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are not
+ supported by this implementation.
+ @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv6 session.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_ACCESS_DENIED The previous operation has not completed yet.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6WriteFile (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token
+ )
+{
+ return Mtftp6OperationStart (This, Token, EFI_MTFTP6_OPCODE_WRQ);
+}
+
+
+/**
+ Download a data file directory from an MTFTPv6 server.
+
+ The ReadDirectory() function is used to return a list of files on the
+ MTFTPv6 server that are logically (or operationally) related to
+ Token.Filename. The directory request packet that is sent to the server
+ is built with the option list that was provided by the caller, if present.
+ The file information that the server returns is put into either of
+ the following locations:
+ - A fixed buffer that is pointed to by Token.Buffer.
+ - A download service function that is pointed to by Token.CheckPacket.
+ If both Token.Buffer and Token.CheckPacket are used, then Token.CheckPacket
+ will be called first. If the call is successful, the packet will be stored
+ in Token.Buffer.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] Token Pointer to the token structure to provide the parameters that are
+ used in this operation.
+
+ @retval EFI_SUCCESS The MTFTPv6 related file "directory" has been downloaded.
+ @retval EFI_UNSUPPORTED The EFI MTFTPv6 Protocol driver does not support this function.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Token is NULL.
+ - Token.Filename is NULL.
+ - Token.OptionCount is not zero and Token.OptionList is NULL.
+ - One or more options in Token.OptionList have wrong format.
+ - Token.Buffer and Token.CheckPacket are both NULL.
+ - Token.OverrideData.ServerIp is not valid unicast IPv6 addresses.
+ @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are not
+ supported by this implementation.
+ @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv6 session.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_ACCESS_DENIED The previous operation has not completed yet.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6ReadDirectory (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token
+ )
+{
+ return Mtftp6OperationStart (This, Token, EFI_MTFTP6_OPCODE_DIR);
+}
+
+
+/**
+ Polls for incoming data packets and processes outgoing data packets.
+
+ The Poll() function can be used by network drivers and applications
+ to increase the rate that data packets are moved between the
+ communications device and the transmit and receive queues. In some
+ systems, the periodic timer event in the managed network driver may
+ not poll the underlying communications device fast enough to transmit
+ and/or receive all data packets without missing incoming packets or
+ dropping outgoing packets. Drivers and applications that are
+ experiencing packet loss should try calling the Poll() function
+ more often.
+
+ @param[in] This The MTFTP6 protocol instance.
+
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_NOT_STARTED This EFI MTFTPv6 Protocol instance has not been started.
+ @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.
+ Consider increasing the polling rate.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6Poll (
+ IN EFI_MTFTP6_PROTOCOL *This
+ )
+{
+ MTFTP6_INSTANCE *Instance;
+ EFI_UDP6_PROTOCOL *Udp6;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = MTFTP6_INSTANCE_FROM_THIS (This);
+
+ //
+ // Check the instance whether configured or in destory.
+ //
+ if (Instance->Config == NULL) {
+ return EFI_NOT_STARTED;
+ } else if (Instance->InDestory) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Udp6 = Instance->UdpIo->Protocol.Udp6;
+
+ return Udp6->Poll (Udp6);
+}
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
new file mode 100644
index 0000000000..bf924a980c
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
@@ -0,0 +1,469 @@
+/** @file
+ Mtftp6 internal data structure and definition declaration.
+
+ 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 __EFI_MTFTP6_IMPL_H__
+#define __EFI_MTFTP6_IMPL_H__
+
+#include <Uefi.h>
+
+#include <Protocol/Udp6.h>
+#include <Protocol/Mtftp6.h>
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/DriverBinding.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/NetLib.h>
+
+typedef struct _MTFTP6_SERVICE MTFTP6_SERVICE;
+typedef struct _MTFTP6_INSTANCE MTFTP6_INSTANCE;
+
+#include "Mtftp6Driver.h"
+#include "Mtftp6Option.h"
+#include "Mtftp6Support.h"
+
+#define MTFTP6_SERVICE_SIGNATURE SIGNATURE_32 ('M', 'F', '6', 'S')
+#define MTFTP6_INSTANCE_SIGNATURE SIGNATURE_32 ('M', 'F', '6', 'I')
+
+#define MTFTP6_DEFAULT_SERVER_CMD_PORT 69
+#define MTFTP6_DEFAULT_TIMEOUT 3
+#define MTFTP6_GET_MAPPING_TIMEOUT 3
+#define MTFTP6_DEFAULT_MAX_RETRY 5
+#define MTFTP6_DEFAULT_BLK_SIZE 512
+#define MTFTP6_TICK_PER_SECOND 10000000U
+
+#define MTFTP6_SERVICE_FROM_THIS(a) CR (a, MTFTP6_SERVICE, ServiceBinding, MTFTP6_SERVICE_SIGNATURE)
+#define MTFTP6_INSTANCE_FROM_THIS(a) CR (a, MTFTP6_INSTANCE, Mtftp6, MTFTP6_INSTANCE_SIGNATURE)
+
+extern EFI_MTFTP6_PROTOCOL gMtftp6ProtocolTemplate;
+
+typedef struct _MTFTP6_GETINFO_CONTEXT{
+ EFI_MTFTP6_PACKET **Packet;
+ UINT32 *PacketLen;
+ EFI_STATUS Status;
+} MTFTP6_GETINFO_CONTEXT;
+
+//
+// Control block for MTFTP6 instance, it's per configuration data.
+//
+struct _MTFTP6_INSTANCE {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ LIST_ENTRY Link;
+ EFI_MTFTP6_PROTOCOL Mtftp6;
+ MTFTP6_SERVICE *Service;
+ EFI_MTFTP6_CONFIG_DATA *Config;
+
+ EFI_MTFTP6_TOKEN *Token;
+ MTFTP6_EXT_OPTION_INFO ExtInfo;
+
+ UINT16 BlkSize;
+ UINT16 LastBlk;
+ LIST_ENTRY BlkList;
+
+ EFI_IPv6_ADDRESS ServerIp;
+ UINT16 ServerCmdPort;
+ UINT16 ServerDataPort;
+ UDP_IO *UdpIo;
+
+ EFI_IPv6_ADDRESS McastIp;
+ UINT16 McastPort;
+ UDP_IO *McastUdpIo;
+
+ NET_BUF *LastPacket;
+ UINT32 CurRetry;
+ UINT32 MaxRetry;
+ UINT32 PacketToLive;
+ UINT32 Timeout;
+
+ EFI_TPL OldTpl;
+ BOOLEAN IsTransmitted;
+ BOOLEAN IsMaster;
+ BOOLEAN InDestory;
+};
+
+//
+// Control block for MTFTP6 service, it's per Nic handle.
+//
+struct _MTFTP6_SERVICE {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ EFI_HANDLE Controller;
+ EFI_HANDLE Image;
+
+ UINT16 ChildrenNum;
+ LIST_ENTRY Children;
+ //
+ // It is used to be as internal calculagraph for all instances.
+ //
+ EFI_EVENT Timer;
+ //
+ // It is used to maintain the parent-child relationship between
+ // mtftp driver and udp driver.
+ //
+ UDP_IO *DummyUdpIo;
+ BOOLEAN InDestory;
+};
+
+/**
+ Returns the current operating mode data for the MTFTP6 instance.
+
+ The GetModeData() function returns the current operating mode and
+ cached data packet for the MTFTP6 instance.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[out] ModeData The buffer in which the EFI MTFTPv6 Protocol driver mode
+ data is returned.
+
+ @retval EFI_SUCCESS The configuration data was returned successfully.
+ @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
+ @retval EFI_INVALID_PARAMETER This is NULL, or ModeData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6GetModeData (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ OUT EFI_MTFTP6_MODE_DATA *ModeData
+ );
+
+/**
+ Initializes, changes, or resets the default operational setting for
+ this EFI MTFTPv6 Protocol driver instance.
+
+ The Configure() function is used to set and change the configuration
+ data for this EFI MTFTPv6 Protocol driver instance. The configuration
+ data can be reset to startup defaults by calling Configure() with
+ MtftpConfigData set to NULL. Whenever the instance is reset, any
+ pending operation is aborted. By changing the EFI MTFTPv6 Protocol
+ driver instance configuration data, the client can connect to
+ different MTFTPv6 servers. The configuration parameters in
+ MtftpConfigData are used as the default parameters in later MTFTPv6
+ operations and can be overridden in later operations.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] MtftpConfigData Pointer to the configuration data structure.
+
+ @retval EFI_SUCCESS The EFI MTFTPv6 Protocol instance was configured successfully.
+ @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
+ - This is NULL.
+ - MtftpConfigData.StationIp is neither zero nor one
+ of the configured IP addresses in the underlying IPv6 driver.
+ - MtftpCofigData.ServerIp is not a valid IPv6 unicast address.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_ACCESS_DENIED - The configuration could not be changed at this time because there
+ is some MTFTP background operation in progress.
+ - MtftpCofigData.LocalPort is already in use.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_OUT_OF_RESOURCES The EFI MTFTPv6 Protocol driver instance data could not be
+ allocated.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI
+ MTFTPv6 Protocol driver instance is not configured.
+ Note: It is not defined in the UEFI 2.3 Specification.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6Configure (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_CONFIG_DATA *MtftpConfigData OPTIONAL
+ );
+
+/**
+ Get the information of the download from the server.
+
+ The GetInfo() function assembles an MTFTPv6 request packet
+ with options, sends it to the MTFTPv6 server, and may return
+ an MTFTPv6 OACK, MTFTPv6 ERROR, or ICMP ERROR packet. Retries
+ occur only if no response packets are received from the MTFTPv6
+ server before the timeout expires.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] OverrideData Data that is used to override the existing parameters. If NULL, the
+ default parameters that were set in the EFI_MTFTP6_PROTOCOL.Configure()
+ function are used.
+ @param[in] Filename Pointer to ASCIIZ file name string.
+ @param[in] ModeStr Pointer to ASCIIZ mode string. If NULL, octet will be used
+ @param[in] OptionCount Number of option/value string pairs in OptionList.
+ @param[in] OptionList Pointer to array of option/value string pairs. Ignored if
+ OptionCount is zero.
+ @param[out] PacketLength The number of bytes in the returned packet.
+ @param[out] Packet The pointer to the received packet. This buffer must be freed by
+ the caller.
+
+ @retval EFI_SUCCESS An MTFTPv6 OACK packet was received and is in the Packet.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Filename is NULL.
+ - OptionCount is not zero and OptionList is NULL.
+ - One or more options in OptionList have wrong format.
+ - PacketLength is NULL.
+ - OverrideData.ServerIp is not a valid unicast IPv6 address.
+ @retval EFI_UNSUPPORTED One or more options in the OptionList are unsupported by
+ this implementation.
+ @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_ACCESS_DENIED The previous operation has not completed yet.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_TFTP_ERROR An MTFTPv6 ERROR packet was received and is in the Packet.
+ @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received, and the Packet is set to NULL.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received, and the Packet is set to NULL.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received, and the Packet is set to NULL.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received, and the Packet is set to NULL.
+ @retval EFI_ICMP_ERROR Some other ICMP ERROR packet was received, and the Packet is set to NULL.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv6 packet was received and is in the Packet.
+ @retval EFI_TIMEOUT No responses were received from the MTFTPv6 server.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6GetInfo (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_OVERRIDE_DATA *OverrideData OPTIONAL,
+ IN UINT8 *Filename,
+ IN UINT8 *ModeStr OPTIONAL,
+ IN UINT8 OptionCount,
+ IN EFI_MTFTP6_OPTION *OptionList OPTIONAL,
+ OUT UINT32 *PacketLength,
+ OUT EFI_MTFTP6_PACKET **Packet OPTIONAL
+ );
+
+/**
+ Parse the options in an MTFTPv6 OACK packet.
+
+ The ParseOptions() function parses the option fields in an MTFTPv6 OACK
+ packet and returns the number of options that were found, and optionally,
+ a list of pointers to the options in the packet. If one or more of the
+ option fields are not valid, then EFI_PROTOCOL_ERROR is returned and
+ *OptionCount and *OptionList stop at the last valid option.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] PacketLen Length of the OACK packet to be parsed.
+ @param[in] Packet Pointer to the OACK packet to be parsed.
+ @param[out] OptionCount Pointer to the number of options in the following OptionList.
+ @param[out] OptionList Pointer to EFI_MTFTP6_OPTION storage. Each pointer in the
+ OptionList points to the corresponding MTFTP option buffer
+ in the Packet. Call the EFI Boot Service FreePool() to
+ release the OptionList if the options in this OptionList
+ are not needed any more.
+
+ @retval EFI_SUCCESS The OACK packet was valid and the OptionCount, and
+ OptionList parameters have been updated.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - PacketLen is 0.
+ - Packet is NULL or Packet is not a valid MTFTPv6 packet.
+ - OptionCount is NULL.
+ @retval EFI_NOT_FOUND No options were found in the OACK packet.
+ @retval EFI_OUT_OF_RESOURCES Storage for the OptionList array can not be allocated.
+ @retval EFI_PROTOCOL_ERROR One or more of the option fields is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6ParseOptions (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN UINT32 PacketLen,
+ IN EFI_MTFTP6_PACKET *Packet,
+ OUT UINT32 *OptionCount,
+ OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL
+ );
+
+/**
+ Download a file from an MTFTPv6 server.
+
+ The ReadFile() function is used to initialize and start an MTFTPv6 download
+ process and optionally wait for completion. When the download operation
+ completes, whether successfully or not, the Token.Status field is updated
+ by the EFI MTFTPv6 Protocol driver, and then Token.Event is signaled if it
+ is not NULL.
+ Data can be downloaded from the MTFTPv6 server into either of the following
+ locations:
+ - A fixed buffer that is pointed to by Token.Buffer.
+ - A download service function that is pointed to by Token.CheckPacket.
+ If both Token.Buffer and Token.CheckPacket are used, then Token.CheckPacket
+ will be called first. If the call is successful, the packet will be stored
+ in Token.Buffer.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] Token Pointer to the token structure to provide the parameters that are
+ used in this operation.
+
+ @retval EFI_SUCCESS The data file has been transferred successfully.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_BUFFER_TOO_SMALL BufferSize is not zero but not large enough to hold the
+ downloaded data in downloading process.
+ Note: It does not match the UEFI 2.3 Specification.
+ @retval EFI_ABORTED Current operation is aborted by user.
+ @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received.
+ Note: It is not defined in the UEFI 2.3 Specification.
+ @retval EFI_ICMP_ERROR An ICMP ERROR packet was received.
+ @retval EFI_TIMEOUT No responses were received from the MTFTPv6 server.
+ @retval EFI_TFTP_ERROR An MTFTPv6 ERROR packet was received.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6ReadFile (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token
+ );
+
+/**
+ Send a file to an MTFTPv6 server.
+
+ The WriteFile() function is used to initialize an uploading operation
+ with the given option list, and optionally, wait for completion. If one
+ or more of the options is not supported by the server, the unsupported
+ options are ignored and a standard TFTP process starts instead. When
+ the upload process completes, whether successfully or not, Token.Event
+ is signaled, and the EFI MTFTPv6 Protocol driver updates Token.Status.
+ The caller can supply the data to be uploaded in the following two modes:
+ - Through the user-provided buffer.
+ - Through a callback function.
+ With the user-provided buffer, the Token.BufferSize field indicates
+ the length of the buffer, and the driver will upload the data in the
+ buffer. With an EFI_MTFTP6_PACKET_NEEDED callback function, the driver
+ will call this callback function to get more data from the user to upload.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] Token Pointer to the token structure to provide the parameters that are
+ used in this operation.
+
+ @retval EFI_SUCCESS The upload session has started.
+ @retval EFI_UNSUPPORTED The operation is not supported by this implementation.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Token is NULL.
+ - Token.Filename is NULL.
+ - Token.OptionCount is not zero and Token.OptionList is NULL.
+ - One or more options in Token.OptionList have wrong format.
+ - Token.Buffer and Token.PacketNeeded are both NULL.
+ - Token.OverrideData.ServerIp is not valid unicast IPv6 addresses.
+ @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are not
+ supported by this implementation.
+ @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv6 session.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_ACCESS_DENIED The previous operation has not completed yet.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6WriteFile (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token
+ );
+
+/**
+ Download a data file directory from an MTFTPv6 server.
+
+ The ReadDirectory() function is used to return a list of files on the
+ MTFTPv6 server that are logically (or operationally) related to
+ Token.Filename. The directory request packet that is sent to the server
+ is built with the option list that was provided by caller, if present.
+ The file information that the server returns is put into either of
+ the following locations:
+ - A fixed buffer that is pointed to by Token.Buffer.
+ - A download service function that is pointed to by Token.CheckPacket.
+ If both Token.Buffer and Token.CheckPacket are used, then Token.CheckPacket
+ will be called first. If the call is successful, the packet will be stored
+ in Token.Buffer.
+
+ @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance.
+ @param[in] Token Pointer to the token structure to provide the parameters that are
+ used in this operation.
+
+ @retval EFI_SUCCESS The MTFTPv6 related file "directory" has been downloaded.
+ @retval EFI_UNSUPPORTED The EFI MTFTPv6 Protocol driver does not support this function.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Token is NULL.
+ - Token.Filename is NULL.
+ - Token.OptionCount is not zero and Token.OptionList is NULL.
+ - One or more options in Token.OptionList have wrong format.
+ - Token.Buffer and Token.CheckPacket are both NULL.
+ - Token.OverrideData.ServerIp is not valid unicast IPv6 addresses.
+ @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are not
+ supported by this implementation.
+ @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started.
+ @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
+ address for this instance, but no source address was available for use.
+ @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv6 session.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_ACCESS_DENIED The previous operation has not completed yet.
+ @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6ReadDirectory (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token
+ );
+
+/**
+ Polls for incoming data packets and processes outgoing data packets.
+
+ The Poll() function can be used by network drivers and applications
+ to increase the rate that data packets are moved between the
+ communications device and the transmit and receive queues.In some
+ systems, the periodic timer event in the managed network driver may
+ not poll the underlying communications device fast enough to transmit
+ and/or receive all data packets without missing incoming packets or
+ dropping outgoing packets. Drivers and applications that are
+ experiencing packet loss should try calling the Poll() function
+ more often.
+
+ @param[in] This The MTFTP6 protocol instance.
+
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_NOT_STARTED This EFI MTFTPv6 Protocol instance has not been started.
+ @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.
+ Consider increasing the polling rate.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiMtftp6Poll (
+ IN EFI_MTFTP6_PROTOCOL *This
+ );
+
+#endif
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
new file mode 100644
index 0000000000..0dcf546fa8
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
@@ -0,0 +1,416 @@
+/** @file
+ Mtftp6 option parse functions 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 "Mtftp6Impl.h"
+
+CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = {
+ "blksize",
+ "timeout",
+ "tsize",
+ "multicast"
+};
+
+
+/**
+ Parse the NULL terminated ASCII string of multicast option.
+
+ @param[in] Str The pointer to the Ascii string of multicast option.
+ @param[in] ExtInfo The pointer to the option information to be filled.
+
+ @retval EFI_SUCCESS Parse the multicast option successfully.
+ @retval EFI_INVALID_PARAMETER The string is malformatted.
+ @retval EFI_OUT_OF_RESOURCES Failed to perform the operation due to lack of
+ resources.
+
+**/
+EFI_STATUS
+Mtftp6ParseMcastOption (
+ IN UINT8 *Str,
+ IN MTFTP6_EXT_OPTION_INFO *ExtInfo
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Num;
+ CHAR8 *Ip6Str;
+ CHAR8 *TempStr;
+
+ //
+ // The multicast option is formated like "addr,port,mc"
+ // The server can also omit the ip and port, use ",,1"
+ //
+ if (*Str == ',') {
+
+ ZeroMem (&ExtInfo->McastIp, sizeof (EFI_IPv6_ADDRESS));
+ } else {
+
+ Ip6Str = (CHAR8 *) AllocateCopyPool (AsciiStrSize ((CHAR8 *) Str), Str);
+ if (Ip6Str == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // The IPv6 address locates before comma in the input Str.
+ //
+ TempStr = Ip6Str;
+ while ((*TempStr != '\0') && (*TempStr != ',')) {
+ TempStr++;
+ }
+
+ *TempStr = '\0';
+
+ Status = NetLibAsciiStrToIp6 (Ip6Str, &ExtInfo->McastIp);
+ FreePool (Ip6Str);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while ((*Str != '\0') && (*Str != ',')) {
+ Str++;
+ }
+ }
+
+ if (*Str != ',') {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Str++;
+
+ //
+ // Convert the port setting. the server can send us a port number or
+ // empty string. such as the port in ",,1"
+ //
+ if (*Str == ',') {
+
+ ExtInfo->McastPort = 0;
+ } else {
+
+ Num = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Str);
+
+ if (Num > 65535) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExtInfo->McastPort = (UINT16) Num;
+
+ while (NET_IS_DIGIT (*Str)) {
+ Str++;
+ }
+ }
+
+ if (*Str != ',') {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Str++;
+
+ //
+ // Check the master/slave setting, 1 for master, 0 for slave.
+ //
+ Num = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Str);
+
+ if (Num != 0 && Num != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExtInfo->IsMaster = (BOOLEAN) (Num == 1);
+
+ while (NET_IS_DIGIT (*Str)) {
+ Str++;
+ }
+
+ if (*Str != '\0') {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Parse the MTFTP6 extesion options.
+
+ @param[in] Options The pointer to the extension options list.
+ @param[in] Count The num of the extension options.
+ @param[in] IsRequest If FALSE, the extension options is included
+ by a request packet.
+ @param[in] ExtInfo The pointer to the option information to be filled.
+
+ @retval EFI_SUCCESS Parse the multicast option successfully.
+ @retval EFI_INVALID_PARAMETER There is one option is malformatted at least.
+ @retval EFI_UNSUPPORTED There is one option is not supported at least.
+
+**/
+EFI_STATUS
+Mtftp6ParseExtensionOption (
+ IN EFI_MTFTP6_OPTION *Options,
+ IN UINT32 Count,
+ IN BOOLEAN IsRequest,
+ IN MTFTP6_EXT_OPTION_INFO *ExtInfo
+ )
+{
+ EFI_STATUS Status;
+ EFI_MTFTP6_OPTION *Opt;
+ UINT32 Index;
+ UINT32 Value;
+
+ ExtInfo->BitMap = 0;
+
+ for (Index = 0; Index < Count; Index++) {
+
+ Opt = Options + Index;
+
+ if (Opt->OptionStr == NULL || Opt->ValueStr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "blksize") == 0) {
+ //
+ // block size option, valid value is between [8, 65464]
+ //
+ Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
+
+ if ((Value < 8) || (Value > 65464)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExtInfo->BlkSize = (UINT16) Value;
+ ExtInfo->BitMap |= MTFTP6_OPT_BLKSIZE_BIT;
+
+ } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "timeout") == 0) {
+ //
+ // timeout option, valid value is between [1, 255]
+ //
+ Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
+
+ if (Value < 1 || Value > 255) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExtInfo->Timeout = (UINT8) Value;
+ ExtInfo->BitMap |= MTFTP6_OPT_TIMEOUT_BIT;
+
+ } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "tsize") == 0) {
+ //
+ // tsize option, the biggest transfer supported is 4GB with block size option
+ //
+ ExtInfo->Tsize = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
+ ExtInfo->BitMap |= MTFTP6_OPT_TSIZE_BIT;
+
+ } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "multicast") == 0) {
+ //
+ // Multicast option, if it is a request, the value must be a zero string,
+ // otherwise, it must be like "addr,port,mc" string, mc indicates master.
+ //
+ if (!IsRequest) {
+
+ Status = Mtftp6ParseMcastOption (Opt->ValueStr, ExtInfo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (*(Opt->ValueStr) != '\0') {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;
+
+ } else if (IsRequest) {
+ //
+ // If it's a request, unsupported; else if it's a reply, ignore.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Go through the packet to fill the options array with the start
+ addresses of each MTFTP option name/value pair.
+
+ @param[in] Packet The packet to be checked.
+ @param[in] PacketLen The length of the packet.
+ @param[in, out] Count The num of the Options on input.
+ The actual one on output.
+ @param[in] Options The option array to be filled.
+ It is optional.
+
+ @retval EFI_SUCCESS The packet has been parsed successfully.
+ @retval EFI_INVALID_PARAMETER The packet is malformatted.
+ @retval EFI_BUFFER_TOO_SMALL The Options array is too small.
+ @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv6 packet was received.
+
+**/
+EFI_STATUS
+Mtftp6ParsePacketOption (
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 PacketLen,
+ IN OUT UINT32 *Count,
+ IN EFI_MTFTP6_OPTION *Options OPTIONAL
+ )
+{
+ UINT8 *Cur;
+ UINT8 *Last;
+ UINT8 Num;
+ UINT8 *Name;
+ UINT8 *Value;
+
+ Num = 0;
+ Cur = (UINT8 *) Packet + MTFTP6_OPCODE_LEN;
+ Last = (UINT8 *) Packet + PacketLen - 1;
+
+ //
+ // process option name and value pairs.
+ // The last byte is always zero.
+ //
+ while (Cur < Last) {
+ Name = Cur;
+
+ while (*Cur != 0) {
+ Cur++;
+ }
+
+ if (Cur == Last) {
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ Value = ++Cur;
+
+ while (*Cur != 0) {
+ Cur++;
+ }
+
+ Num++;
+
+ if (Options != NULL && Num <= *Count) {
+ Options[Num - 1].OptionStr = Name;
+ Options[Num - 1].ValueStr = Value;
+ }
+
+ Cur++;
+ }
+
+ //
+ // Return buffer too small if the buffer passed-in isn't enough.
+ //
+ if (*Count < Num || Options == NULL) {
+ *Count = Num;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Count = Num;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Go through the packet, generate option list array and fill it
+ by the result of parse options.
+
+ @param[in] Packet The packet to be checked.
+ @param[in] PacketLen The length of the packet.
+ @param[in, out] OptionCount The num of the Options on input.
+ The actual one on output.
+ @param[out] OptionList The option list array to be generated
+ and filled. It is optional.
+
+ @retval EFI_SUCCESS The packet has been parsed successfully.
+ @retval EFI_INVALID_PARAMETER The packet is malformatted.
+ @retval EFI_PROTOCOL_ERROR There is one option is malformatted at least.
+ @retval EFI_NOT_FOUND The packet has no options.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array.
+ @retval EFI_BUFFER_TOO_SMALL The size of option list array is too small.
+
+**/
+EFI_STATUS
+Mtftp6ParseStart (
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 PacketLen,
+ IN OUT UINT32 *OptionCount,
+ OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (PacketLen == 0 || Packet == NULL || OptionCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *OptionCount = 0;
+
+ if (OptionList != NULL) {
+ *OptionList = NULL;
+ }
+
+ if (NTOHS (Packet->OpCode) != EFI_MTFTP6_OPCODE_OACK) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The last byte must be zero to terminate the options.
+ //
+ if (*((UINT8 *) Packet + PacketLen - 1) != 0) {
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Parse packet with NULL buffer for the first time to get the number
+ // of options in the packet.
+ //
+ Status = Mtftp6ParsePacketOption (Packet, PacketLen, OptionCount, NULL);
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ //
+ // Return not found if there is no option parsed.
+ //
+ if (*OptionCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Only need parse out the number of options.
+ //
+ if (OptionList == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Allocate the buffer according to the option number parsed before.
+ //
+ *OptionList = AllocateZeroPool (*OptionCount * sizeof (EFI_MTFTP6_OPTION));
+
+ if (*OptionList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Parse packet with allocated buffer for the second time to fill the pointer array
+ // of the options in the packet.
+ //
+ Status = Mtftp6ParsePacketOption (Packet, PacketLen, OptionCount, *OptionList);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
new file mode 100644
index 0000000000..8e2671fa21
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
@@ -0,0 +1,148 @@
+/** @file
+ Mtftp6 option parse functions declaration.
+
+ 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 __EFI_MTFTP6_OPTION_H__
+#define __EFI_MTFTP6_OPTION_H__
+
+#include <Uefi.h>
+
+#include <Protocol/ServiceBinding.h>
+
+#include <Library/NetLib.h>
+#include <Library/UdpIoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#define MTFTP6_SUPPORTED_OPTIONS_NUM 4
+#define MTFTP6_OPCODE_LEN 2
+#define MTFTP6_ERRCODE_LEN 2
+#define MTFTP6_BLKNO_LEN 2
+#define MTFTP6_DATA_HEAD_LEN 4
+
+//
+// The bit map definition for Mtftp6 extension options.
+//
+#define MTFTP6_OPT_BLKSIZE_BIT 0x01
+#define MTFTP6_OPT_TIMEOUT_BIT 0x02
+#define MTFTP6_OPT_TSIZE_BIT 0x04
+#define MTFTP6_OPT_MCAST_BIT 0x08
+
+extern CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM];
+
+typedef struct {
+ UINT16 BlkSize;
+ UINT8 Timeout;
+ UINT32 Tsize;
+ EFI_IPv6_ADDRESS McastIp;
+ UINT16 McastPort;
+ BOOLEAN IsMaster;
+ UINT32 BitMap;
+} MTFTP6_EXT_OPTION_INFO;
+
+/**
+ Parse the Ascii string of multi-cast option.
+
+ @param[in] Str The pointer to the Ascii string of multi-cast option.
+ @param[in] ExtInfo The pointer to the option information to be filled.
+
+ @retval EFI_SUCCESS Parse the multicast option successfully.
+ @retval EFI_INVALID_PARAMETER The string is malformatted.
+
+**/
+EFI_STATUS
+Mtftp6ParseMcastOption (
+ IN UINT8 *Str,
+ IN MTFTP6_EXT_OPTION_INFO *ExtInfo
+ );
+
+
+/**
+ Parse the MTFTP6 extesion options.
+
+ @param[in] Options The pointer to the extension options list.
+ @param[in] Count The num of the extension options.
+ @param[in] IsRequest If FALSE, the extension options is included
+ by a request packet.
+ @param[in] ExtInfo The pointer to the option information to be filled.
+
+ @retval EFI_SUCCESS Parse the multi-cast option successfully.
+ @retval EFI_INVALID_PARAMETER An option is malformatted.
+ @retval EFI_UNSUPPORTED An option is not supported.
+
+**/
+EFI_STATUS
+Mtftp6ParseExtensionOption (
+ IN EFI_MTFTP6_OPTION *Options,
+ IN UINT32 Count,
+ IN BOOLEAN IsRequest,
+ IN MTFTP6_EXT_OPTION_INFO *ExtInfo
+ );
+
+
+/**
+ Go through the packet to fill the options array with the start
+ addresses of each MTFTP option name/value pair.
+
+ @param[in] Packet The packet to be checked.
+ @param[in] PacketLen The length of the packet.
+ @param[in, out] Count The num of the Options on input.
+ The actual one on output.
+ @param[in] Options The option array to be filled
+ it's optional.
+
+ @retval EFI_SUCCESS The packet has been parsed successfully.
+ @retval EFI_INVALID_PARAMETER The packet is malformatted
+ @retval EFI_BUFFER_TOO_SMALL The Options array is too small
+ @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv6 packet was received.
+
+**/
+EFI_STATUS
+Mtftp6ParsePacketOption (
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 PacketLen,
+ IN OUT UINT32 *Count,
+ IN EFI_MTFTP6_OPTION *Options OPTIONAL
+ );
+
+
+/**
+ Go through the packet, generate option list array and fill it
+ by the result of parse options.
+
+ @param[in] Packet The packet to be checked.
+ @param[in] PacketLen The length of the packet.
+ @param[in, out] OptionCount The num of the Options on input.
+ The actual one on output.
+ @param[out] OptionList The option list array to be generated
+ and filled. It is optional.
+
+ @retval EFI_SUCCESS The packet has been parsed successfully.
+ @retval EFI_INVALID_PARAMETER The packet is malformatted.
+ @retval EFI_PROTOCOL_ERROR An option is malformatted.
+ @retval EFI_NOT_FOUND The packet has no options.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array.
+ @retval EFI_BUFFER_TOO_SMALL The size of option list array is too small.
+
+**/
+EFI_STATUS
+Mtftp6ParseStart (
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 PacketLen,
+ IN OUT UINT32 *OptionCount,
+ OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL
+ );
+
+#endif
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
new file mode 100644
index 0000000000..da364329fc
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
@@ -0,0 +1,900 @@
+/** @file
+ Mtftp6 Rrq process functions 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 "Mtftp6Impl.h"
+
+
+/**
+ Build and send a ACK packet for download.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] BlockNum The block number to be acked.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
+ @retval EFI_SUCCESS The ACK has been sent.
+ @retval Others Failed to send the ACK.
+
+**/
+EFI_STATUS
+Mtftp6RrqSendAck (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 BlockNum
+ )
+{
+ EFI_MTFTP6_PACKET *Ack;
+ NET_BUF *Packet;
+
+ //
+ // Allocate net buffer to create ack packet.
+ //
+ Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
+
+ if (Packet == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ack = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
+ Packet,
+ sizeof (EFI_MTFTP6_ACK_HEADER),
+ FALSE
+ );
+ ASSERT (Ack != NULL);
+
+ Ack->Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
+ Ack->Ack.Block[0] = HTONS (BlockNum);
+
+ //
+ // Reset current retry count of the instance.
+ //
+ Instance->CurRetry = 0;
+
+ return Mtftp6TransmitPacket (Instance, Packet);
+}
+
+
+/**
+ Deliver the received data block to the user, which can be saved
+ in the user provide buffer or through the CheckPacket callback.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the received packet.
+ @param[in] Len The packet length.
+ @param[out] UdpPacket The net buf of the received packet.
+
+ @retval EFI_SUCCESS The data was saved successfully.
+ @retval EFI_ABORTED The user tells to abort by return an error through
+ CheckPacket.
+ @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small, and buffer length is
+ updated to the actual buffer size needed.
+
+**/
+EFI_STATUS
+Mtftp6RrqSaveBlock (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 Len,
+ OUT NET_BUF **UdpPacket
+ )
+{
+ EFI_MTFTP6_TOKEN *Token;
+ EFI_STATUS Status;
+ UINT16 Block;
+ UINT64 Start;
+ UINT32 DataLen;
+ UINT64 TotalBlock;
+ BOOLEAN Completed;
+
+ Completed = FALSE;
+ Token = Instance->Token;
+ Block = NTOHS (Packet->Data.Block);
+ DataLen = Len - MTFTP6_DATA_HEAD_LEN;
+
+ //
+ // This is the last block, save the block num
+ //
+ if (DataLen < Instance->BlkSize) {
+ Completed = TRUE;
+ Instance->LastBlk = Block;
+ Mtftp6SetLastBlockNum (&Instance->BlkList, Block);
+ }
+
+ //
+ // Remove this block number from the file hole. If Mtftp6RemoveBlockNum
+ // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
+ // Note that : For bigger files, allowing the block counter to roll over
+ // to accept transfers of unlimited size. So TotalBlock is memorised as
+ // continuous block counter.
+ //
+ Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, &TotalBlock);
+
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_SUCCESS;
+ } else if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Token->CheckPacket != NULL) {
+ //
+ // Callback to the check packet routine with the received packet.
+ //
+ Status = Token->CheckPacket (&Instance->Mtftp6, Token, (UINT16) Len, Packet);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the Udp6Io might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if user aborted the current session.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
+ (UINT8 *) "User aborted download"
+ );
+
+ return EFI_ABORTED;
+ }
+ }
+
+ if (Token->Buffer != NULL) {
+
+ Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize);
+ if (Start + DataLen <= Token->BufferSize) {
+ CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
+ //
+ // Update the file size when received the last block
+ //
+ if ((Instance->LastBlk == Block) && Completed) {
+ Token->BufferSize = Start + DataLen;
+ }
+ } else if (Instance->LastBlk != 0) {
+ //
+ // Don't save the data if the buffer is too small, return
+ // EFI_BUFFER_TOO_SMALL if received the last packet. This
+ // will give a accurate file length.
+ //
+ Token->BufferSize = Start + DataLen;
+
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if no enough buffer.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_DISK_FULL,
+ (UINT8 *) "User provided memory block is too small"
+ );
+
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Process the received data packets. It will save the block
+ then send back an ACK if it is active.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the received packet.
+ @param[in] Len The length of the packet.
+ @param[out] UdpPacket The net buf of received packet.
+ @param[out] IsCompleted If TRUE, the download has been completed.
+ Otherwise, the download has not been completed.
+
+ @retval EFI_SUCCESS The data packet was successfully processed.
+ @retval EFI_ABORTED The download was aborted by the user.
+ @retval EFI_BUFFER_TOO_SMALL The user-provided buffer is too small.
+
+**/
+EFI_STATUS
+Mtftp6RrqHandleData (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 Len,
+ OUT NET_BUF **UdpPacket,
+ OUT BOOLEAN *IsCompleted
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BlockNum;
+ INTN Expected;
+
+ *IsCompleted = FALSE;
+ BlockNum = NTOHS (Packet->Data.Block);
+ Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
+
+ ASSERT (Expected >= 0);
+
+ //
+ // If we are active and received an unexpected packet, retransmit
+ // the last ACK then restart receiving. If we are passive, save
+ // the block.
+ //
+ if (Instance->IsMaster && (Expected != BlockNum)) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+
+ Mtftp6TransmitPacket (Instance, Instance->LastPacket);
+ return EFI_SUCCESS;
+ }
+
+ Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Reset the passive client's timer whenever it received a valid data packet.
+ //
+ if (!Instance->IsMaster) {
+ Instance->PacketToLive = Instance->Timeout * 2;
+ }
+
+ //
+ // Check whether we have received all the blocks. Send the ACK if we
+ // are active (unicast client or master client for multicast download).
+ // If we have received all the blocks, send an ACK even if we are passive
+ // to tell the server that we are done.
+ //
+ Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
+
+ if (Instance->IsMaster || Expected < 0) {
+ if (Expected < 0) {
+ //
+ // If we are passive client, then the just received Block maybe
+ // isn't the last block. We need to send an ACK to the last block
+ // to inform the server that we are done. If we are active client,
+ // the Block == Instance->LastBlock.
+ //
+ BlockNum = Instance->LastBlk;
+ *IsCompleted = TRUE;
+
+ } else {
+ BlockNum = (UINT16) (Expected - 1);
+ }
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+
+ Mtftp6RrqSendAck (Instance, BlockNum);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Validate whether the options received in the server's OACK packet is valid.
+ The options are valid only if:
+ 1. The server doesn't include options not requested by us.
+ 2. The server can only use smaller blksize than that is requested.
+ 3. The server can only use the same timeout as requested.
+ 4. The server doesn't change its multicast channel.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] ReplyInfo The pointer to options information in reply packet.
+ @param[in] RequestInfo The pointer to requested options info.
+
+ @retval TRUE If the option in the OACK is valid.
+ @retval FALSE If the option is invalid.
+
+**/
+BOOLEAN
+Mtftp6RrqOackValid (
+ IN MTFTP6_INSTANCE *Instance,
+ IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,
+ IN MTFTP6_EXT_OPTION_INFO *RequestInfo
+ )
+{
+ //
+ // It is invalid for server to return options we don't request
+ //
+ if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
+ return FALSE;
+ }
+
+ //
+ // Server can only specify a smaller block size to be used and
+ // return the timeout matches that requested.
+ //
+ if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
+ (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
+ ) {
+ return FALSE;
+ }
+
+ //
+ // The server can send ",,master" to client to change its master
+ // setting. But if it use the specific multicast channel, it can't
+ // change the setting.
+ //
+ if (((ReplyInfo->BitMap & MTFTP6_OPT_MCAST_BIT) != 0) && !NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
+
+ if (!NetIp6IsUnspecifiedAddr (&ReplyInfo->McastIp) && CompareMem (
+ &ReplyInfo->McastIp,
+ &Instance->McastIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ ) != 0) {
+ return FALSE;
+ }
+
+ if ((ReplyInfo->McastPort != 0) && (ReplyInfo->McastPort != Instance->McastPort)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Configure Udp6Io to receive a packet from a multicast address.
+
+ @param[in] McastIo The pointer to the mcast Udp6Io.
+ @param[in] Context The pointer to the context.
+
+ @retval EFI_SUCCESS The mcast Udp6Io was successfully configured.
+ @retval Others Failed to configure the Udp6Io.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6RrqConfigMcastUdpIo (
+ IN UDP_IO *McastIo,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_UDP6_PROTOCOL *Udp6;
+ EFI_UDP6_CONFIG_DATA *Udp6Cfg;
+ EFI_IPv6_ADDRESS Group;
+ MTFTP6_INSTANCE *Instance;
+
+ Udp6 = McastIo->Protocol.Udp6;
+ Udp6Cfg = &(McastIo->Config.Udp6);
+ Instance = (MTFTP6_INSTANCE *) Context;
+
+ //
+ // Set the configure data for the mcast Udp6Io.
+ //
+ ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
+
+ Udp6Cfg->AcceptPromiscuous = FALSE;
+ Udp6Cfg->AcceptAnyPort = FALSE;
+ Udp6Cfg->AllowDuplicatePort = FALSE;
+ Udp6Cfg->TrafficClass = 0;
+ Udp6Cfg->HopLimit = 128;
+ Udp6Cfg->ReceiveTimeout = 0;
+ Udp6Cfg->TransmitTimeout = 0;
+ Udp6Cfg->StationPort = Instance->McastPort;
+ Udp6Cfg->RemotePort = 0;
+
+ CopyMem (
+ &Udp6Cfg->RemoteAddress,
+ &Instance->ServerIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ //
+ // Configure the mcast Udp6Io.
+ //
+ Status = Udp6->Configure (Udp6, Udp6Cfg);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Join the multicast group
+ //
+ CopyMem (&Group, &Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
+
+ return Udp6->Groups (Udp6, TRUE, &Group);
+}
+
+
+/**
+ Process the OACK packet for Rrq.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the received packet.
+ @param[in] Len The length of the packet.
+ @param[out] UdpPacket The net buf of received packet.
+ @param[out] IsCompleted If TRUE, the download has been completed.
+ Otherwise, the download has not been completed.
+
+ @retval EFI_DEVICE_ERROR Failed to create/start a multicast Udp6 child.
+ @retval EFI_TFTP_ERROR An error happened during the process.
+ @retval EFI_SUCCESS The OACK packet successfully processed.
+
+**/
+EFI_STATUS
+Mtftp6RrqHandleOack (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 Len,
+ OUT NET_BUF **UdpPacket,
+ OUT BOOLEAN *IsCompleted
+ )
+{
+ EFI_MTFTP6_OPTION *Options;
+ UINT32 Count;
+ MTFTP6_EXT_OPTION_INFO ExtInfo;
+ EFI_STATUS Status;
+ INTN Expected;
+
+ *IsCompleted = FALSE;
+
+ //
+ // If already started the master download, don't change the
+ // setting. Master download always succeeds.
+ //
+ Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
+ ASSERT (Expected != -1);
+
+ if (Instance->IsMaster && Expected != 1) {
+ return EFI_SUCCESS;
+ }
+
+ ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
+
+ //
+ // Parse the options in the packet.
+ //
+ Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Parse the extensive options in the packet.
+ //
+ Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
+
+ if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
+ //
+ // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
+ //
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if invalid packet.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
+ (UINT8 *) "Mal-formated OACK packet"
+ );
+ }
+
+ return EFI_TFTP_ERROR;
+ }
+
+ if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {
+
+ //
+ // Save the multicast info. Always update the Master, only update the
+ // multicast IP address, block size, timeoute at the first time. If IP
+ // address is updated, create a UDP child to receive the multicast.
+ //
+ Instance->IsMaster = ExtInfo.IsMaster;
+
+ if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
+ if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || ExtInfo.McastPort == 0) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if invalid multi-cast setting.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
+ (UINT8 *) "Illegal multicast setting"
+ );
+
+ return EFI_TFTP_ERROR;
+ }
+
+ //
+ // Create a UDP child then start receive the multicast from it.
+ //
+ CopyMem (
+ &Instance->McastIp,
+ &ExtInfo.McastIp,
+ sizeof (EFI_IP_ADDRESS)
+ );
+
+ Instance->McastPort = ExtInfo.McastPort;
+ Instance->McastUdpIo = UdpIoCreateIo (
+ Instance->Service->Controller,
+ Instance->Service->Image,
+ Mtftp6RrqConfigMcastUdpIo,
+ UDP_IO_UDP6_VERSION,
+ Instance
+ );
+
+ if (Instance->McastUdpIo == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = UdpIoRecvDatagram (
+ Instance->McastUdpIo,
+ Mtftp6RrqInput,
+ Instance,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if failed to create Udp6Io to receive.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION,
+ (UINT8 *) "Failed to create socket to receive multicast packet"
+ );
+
+ return Status;
+ }
+
+ //
+ // Update the parameters used.
+ //
+ if (ExtInfo.BlkSize != 0) {
+ Instance->BlkSize = ExtInfo.BlkSize;
+ }
+
+ if (ExtInfo.Timeout != 0) {
+ Instance->Timeout = ExtInfo.Timeout;
+ }
+ }
+
+ } else {
+
+ Instance->IsMaster = TRUE;
+
+ if (ExtInfo.BlkSize != 0) {
+ Instance->BlkSize = ExtInfo.BlkSize;
+ }
+
+ if (ExtInfo.Timeout != 0) {
+ Instance->Timeout = ExtInfo.Timeout;
+ }
+ }
+
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send an ACK to (Expected - 1) which is 0 for unicast download,
+ // or tell the server we want to receive the Expected block.
+ //
+ return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
+}
+
+
+/**
+ The packet process callback for Mtftp6 download.
+
+ @param[in] UdpPacket The pointer to the packet received.
+ @param[in] UdpEpt The pointer to the Udp6 access point.
+ @param[in] IoStatus The status from Udp6 instance.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6RrqInput (
+ IN NET_BUF *UdpPacket,
+ IN UDP_END_POINT *UdpEpt,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ )
+{
+ MTFTP6_INSTANCE *Instance;
+ EFI_MTFTP6_PACKET *Packet;
+ BOOLEAN IsCompleted;
+ BOOLEAN IsMcast;
+ EFI_STATUS Status;
+ UINT16 Opcode;
+ UINT32 TotalNum;
+ UINT32 Len;
+
+ Instance = (MTFTP6_INSTANCE *) Context;
+
+ NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
+
+ Status = EFI_SUCCESS;
+ Packet = NULL;
+ IsCompleted = FALSE;
+ IsMcast = FALSE;
+ TotalNum = 0;
+
+ //
+ // Return error status if Udp6 instance failed to receive.
+ //
+ if (EFI_ERROR (IoStatus)) {
+ Status = IoStatus;
+ goto ON_EXIT;
+ }
+
+ ASSERT (UdpPacket != NULL);
+
+ if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Find the port this packet is from to restart receive correctly.
+ //
+ if (CompareMem (
+ Ip6Swap128 (&UdpEpt->LocalAddr.v6),
+ &Instance->McastIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ ) == 0) {
+ IsMcast = TRUE;
+ } else {
+ IsMcast = FALSE;
+ }
+
+ //
+ // Client send initial request to server's listening port. Server
+ // will select a UDP port to communicate with the client. The server
+ // is required to use the same port as RemotePort to multicast the
+ // data.
+ //
+ if (UdpEpt->RemotePort != Instance->ServerDataPort) {
+ if (Instance->ServerDataPort != 0) {
+ goto ON_EXIT;
+ } else {
+ //
+ // For the subsequent exchange of requests, reconfigure the udpio as
+ // (serverip, serverport, localip, localport).
+ // Ususally, the client set serverport as 0 to receive and reset it
+ // once the first packet arrives to send ack.
+ //
+ Instance->ServerDataPort = UdpEpt->RemotePort;
+ }
+ }
+
+ //
+ // Copy the MTFTP packet to a continuous buffer if it isn't already so.
+ //
+ Len = UdpPacket->TotalSize;
+ TotalNum = UdpPacket->BlockOpNum;
+
+ if (TotalNum > 1) {
+ Packet = AllocateZeroPool (Len);
+
+ if (Packet == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
+
+ } else {
+ Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
+ ASSERT (Packet != NULL);
+ }
+
+ Opcode = NTOHS (Packet->OpCode);
+
+ //
+ // Callback to the user's CheckPacket if provided. Abort the transmission
+ // if CheckPacket returns an EFI_ERROR code.
+ //
+ if ((Instance->Token->CheckPacket != NULL) &&
+ (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR)
+ ) {
+
+ Status = Instance->Token->CheckPacket (
+ &Instance->Mtftp6,
+ Instance->Token,
+ (UINT16) Len,
+ Packet
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Send an error message to the server to inform it
+ //
+ if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (UdpPacket);
+ UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if user aborted the current session.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
+ (UINT8 *) "User aborted the transfer"
+ );
+ }
+
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Switch the process routines by the operation code.
+ //
+ switch (Opcode) {
+ case EFI_MTFTP6_OPCODE_DATA:
+ if ((Len > (UINT32) (MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32) MTFTP6_DATA_HEAD_LEN)) {
+ goto ON_EXIT;
+ }
+ //
+ // Handle the data packet of Rrq.
+ //
+ Status = Mtftp6RrqHandleData (
+ Instance,
+ Packet,
+ Len,
+ &UdpPacket,
+ &IsCompleted
+ );
+ break;
+
+ case EFI_MTFTP6_OPCODE_OACK:
+ if (IsMcast || Len <= MTFTP6_OPCODE_LEN) {
+ goto ON_EXIT;
+ }
+ //
+ // Handle the Oack packet of Rrq.
+ //
+ Status = Mtftp6RrqHandleOack (
+ Instance,
+ Packet,
+ Len,
+ &UdpPacket,
+ &IsCompleted
+ );
+ break;
+
+ default:
+ //
+ // Drop and return eror if received error message.
+ //
+ Status = EFI_TFTP_ERROR;
+ break;
+ }
+
+ON_EXIT:
+ //
+ // Free the resources, then if !EFI_ERROR (Status), restart the
+ // receive, otherwise end the session.
+ //
+ if (Packet != NULL && TotalNum > 1) {
+ FreePool (Packet);
+ }
+ if (UdpPacket != NULL) {
+ NetbufFree (UdpPacket);
+ }
+ if (!EFI_ERROR (Status) && !IsCompleted) {
+ if (IsMcast) {
+ Status = UdpIoRecvDatagram (
+ Instance->McastUdpIo,
+ Mtftp6RrqInput,
+ Instance,
+ 0
+ );
+ } else {
+ Status = UdpIoRecvDatagram (
+ Instance->UdpIo,
+ Mtftp6RrqInput,
+ Instance,
+ 0
+ );
+ }
+ }
+ //
+ // Clean up the current session if failed to continue.
+ //
+ if (EFI_ERROR (Status) || IsCompleted) {
+ Mtftp6OperationClean (Instance, Status);
+ }
+}
+
+
+/**
+ Start the Mtftp6 instance to download. It first initializes some
+ of the internal states, then builds and sends an RRQ reqeuest packet.
+ Finally, it starts receive for the downloading.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Operation The operation code of current packet.
+
+ @retval EFI_SUCCESS The Mtftp6 is started to download.
+ @retval Others Failed to start to download.
+
+**/
+EFI_STATUS
+Mtftp6RrqStart (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 Operation
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // The valid block number range are [1, 0xffff]. For example:
+ // the client sends an RRQ request to the server, the server
+ // transfers the DATA1 block. If option negoitation is ongoing,
+ // the server will send back an OACK, then client will send ACK0.
+ //
+ Status = Mtftp6InitBlockRange (&Instance->BlkList, 1, 0xffff);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Mtftp6SendRequest (Instance, Operation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return UdpIoRecvDatagram (
+ Instance->UdpIo,
+ Mtftp6RrqInput,
+ Instance,
+ 0
+ );
+}
+
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
new file mode 100644
index 0000000000..24ce0e85ba
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
@@ -0,0 +1,1189 @@
+/** @file
+ Mtftp6 support functions 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 "Mtftp6Impl.h"
+
+
+/**
+ Allocate a MTFTP block range, then init it to the range of [Start, End].
+
+ @param[in] Start The start block number.
+ @param[in] End The last block number in the range.
+
+ @return Range The range of the allocated block buffer.
+
+**/
+MTFTP6_BLOCK_RANGE *
+Mtftp6AllocateRange (
+ IN UINT16 Start,
+ IN UINT16 End
+ )
+{
+ MTFTP6_BLOCK_RANGE *Range;
+
+ Range = AllocateZeroPool (sizeof (MTFTP6_BLOCK_RANGE));
+
+ if (Range == NULL) {
+ return NULL;
+ }
+
+ InitializeListHead (&Range->Link);
+ Range->Start = Start;
+ Range->End = End;
+ Range->Bound = End;
+
+ return Range;
+}
+
+
+/**
+ Initialize the block range for either RRQ or WRQ. RRQ and WRQ have
+ different requirements for Start and End. For example, during startup,
+ WRQ initializes its whole valid block range to [0, 0xffff]. This
+ is bacause the server will send an ACK0 to inform the user to start the
+ upload. When the client receives an ACK0, it will remove 0 from the range,
+ get the next block number, which is 1, then upload the BLOCK1. For RRQ
+ without option negotiation, the server will directly send the BLOCK1
+ in response to the client's RRQ. When received BLOCK1, the client will
+ remove it from the block range and send an ACK. It also works if there
+ is option negotiation.
+
+ @param[in] Head The block range head to initialize.
+ @param[in] Start The Start block number.
+ @param[in] End The last block number.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range.
+ @retval EFI_SUCCESS The initial block range is created.
+
+**/
+EFI_STATUS
+Mtftp6InitBlockRange (
+ IN LIST_ENTRY *Head,
+ IN UINT16 Start,
+ IN UINT16 End
+ )
+{
+ MTFTP6_BLOCK_RANGE *Range;
+
+ Range = Mtftp6AllocateRange (Start, End);
+
+ if (Range == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InsertTailList (Head, &Range->Link);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the first valid block number on the range list.
+
+ @param[in] Head The block range head.
+
+ @retval ==-1 If the block range is empty.
+ @retval >-1 The first valid block number.
+
+**/
+INTN
+Mtftp6GetNextBlockNum (
+ IN LIST_ENTRY *Head
+ )
+{
+ MTFTP6_BLOCK_RANGE *Range;
+
+ if (IsListEmpty (Head)) {
+ return -1;
+ }
+
+ Range = NET_LIST_HEAD (Head, MTFTP6_BLOCK_RANGE, Link);
+ return Range->Start;
+}
+
+
+/**
+ Set the last block number of the block range list. It
+ removes all the blocks after the Last. MTFTP initialize the
+ block range to the maximum possible range, such as [0, 0xffff]
+ for WRQ. When it gets the last block number, it calls
+ this function to set the last block number.
+
+ @param[in] Head The block range list.
+ @param[in] Last The last block number.
+
+**/
+VOID
+Mtftp6SetLastBlockNum (
+ IN LIST_ENTRY *Head,
+ IN UINT16 Last
+ )
+{
+ MTFTP6_BLOCK_RANGE *Range;
+
+ //
+ // Iterate from the tail to head to remove the block number
+ // after the last.
+ //
+ while (!IsListEmpty (Head)) {
+ Range = NET_LIST_TAIL (Head, MTFTP6_BLOCK_RANGE, Link);
+
+ if (Range->Start > Last) {
+ RemoveEntryList (&Range->Link);
+ FreePool (Range);
+ continue;
+ }
+
+ if (Range->End > Last) {
+ Range->End = Last;
+ }
+ return ;
+ }
+}
+
+
+/**
+ Remove the block number from the block range list.
+
+ @param[in] Head The block range list to remove from.
+ @param[in] Num The block number to remove.
+ @param[in] Completed Whether Num is the last block number
+ @param[out] TotalBlock The continuous block number in all
+
+ @retval EFI_NOT_FOUND The block number isn't in the block range list.
+ @retval EFI_SUCCESS The block number has been removed from the list.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+Mtftp6RemoveBlockNum (
+ IN LIST_ENTRY *Head,
+ IN UINT16 Num,
+ IN BOOLEAN Completed,
+ OUT UINT64 *TotalBlock
+ )
+{
+ MTFTP6_BLOCK_RANGE *Range;
+ MTFTP6_BLOCK_RANGE *NewRange;
+ LIST_ENTRY *Entry;
+
+ NET_LIST_FOR_EACH (Entry, Head) {
+
+ //
+ // Each block represents a hole [Start, End] in the file,
+ // skip to the first range with End >= Num
+ //
+ Range = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
+
+ if (Range->End < Num) {
+ continue;
+ }
+
+ //
+ // There are three different cases for Start
+ // 1. (Start > Num) && (End >= Num):
+ // because all the holes before this one has the condition of
+ // End < Num, so this block number has been removed.
+ //
+ // 2. (Start == Num) && (End >= Num):
+ // Need to increase the Start by one, and if End == Num, this
+ // hole has been removed completely, remove it.
+ //
+ // 3. (Start < Num) && (End >= Num):
+ // if End == Num, only need to decrease the End by one because
+ // we have (Start < Num) && (Num == End), so (Start <= End - 1).
+ // if (End > Num), the hold is splited into two holes, with
+ // [Start, Num - 1] and [Num + 1, End].
+ //
+ if (Range->Start > Num) {
+ return EFI_NOT_FOUND;
+
+ } else if (Range->Start == Num) {
+ Range->Start++;
+
+ //
+ // Note that: RFC 1350 does not mention block counter roll-over,
+ // but several TFTP hosts implement the roll-over be able to accept
+ // transfers of unlimited size. There is no consensus, however, whether
+ // the counter should wrap around to zero or to one. Many implementations
+ // wrap to zero, because this is the simplest to implement. Here we choose
+ // this solution.
+ //
+ *TotalBlock = Num;
+
+ if (Range->Round > 0) {
+ *TotalBlock += Range->Bound + MultU64x32 ((UINT64) (Range->Round -1), (UINT32)(Range->Bound + 1)) + 1;
+ }
+
+ if (Range->Start > Range->Bound) {
+ Range->Start = 0;
+ Range->Round ++;
+ }
+
+ if ((Range->Start > Range->End) || Completed) {
+ RemoveEntryList (&Range->Link);
+ FreePool (Range);
+ }
+
+ return EFI_SUCCESS;
+
+ } else {
+ if (Range->End == Num) {
+ Range->End--;
+ } else {
+ NewRange = Mtftp6AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);
+
+ if (NewRange == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Range->End = Num - 1;
+ NetListInsertAfter (&Range->Link, &NewRange->Link);
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Configure the opened Udp6 instance until the corresponding Ip6 instance
+ has been configured.
+
+ @param[in] UdpIo The pointer to the Udp6 Io.
+ @param[in] UdpCfgData The pointer to the Udp6 configure data.
+
+ @retval EFI_SUCCESS Configure the Udp6 instance successfully.
+ @retval EFI_NO_MAPPING The corresponding Ip6 instance has not
+ been configured yet.
+
+**/
+EFI_STATUS
+Mtftp6GetMapping (
+ IN UDP_IO *UdpIo,
+ IN EFI_UDP6_CONFIG_DATA *UdpCfgData
+ )
+{
+ EFI_IP6_MODE_DATA Ip6Mode;
+ EFI_UDP6_PROTOCOL *Udp6;
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Event = NULL;
+ Udp6 = UdpIo->Protocol.Udp6;
+
+ //
+ // Create a timer to check whether the Ip6 instance configured or not.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = gBS->SetTimer (
+ Event,
+ TimerRelative,
+ MTFTP6_GET_MAPPING_TIMEOUT * MTFTP6_TICK_PER_SECOND
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Check the Ip6 mode data till timeout.
+ //
+ while (EFI_ERROR (gBS->CheckEvent (Event))) {
+
+ Udp6->Poll (Udp6);
+
+ Status = Udp6->GetModeData (Udp6, NULL, &Ip6Mode, NULL, NULL);
+
+ if (!EFI_ERROR (Status)) {
+
+ if (Ip6Mode.IsConfigured) {
+ //
+ // Continue to configure the Udp6 instance.
+ //
+ Status = Udp6->Configure (Udp6, UdpCfgData);
+ } else {
+ Status = EFI_NO_MAPPING;
+ }
+ }
+ }
+
+ON_EXIT:
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ return Status;
+}
+
+
+/**
+ The dummy configure routine for create a new Udp6 Io.
+
+ @param[in] UdpIo The pointer to the Udp6 Io.
+ @param[in] Context The pointer to the context.
+
+ @retval EFI_SUCCESS This value is always returned.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6ConfigDummyUdpIo (
+ IN UDP_IO *UdpIo,
+ IN VOID *Context
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The configure routine for Mtftp6 instance to transmit/receive.
+
+ @param[in] UdpIo The pointer to the Udp6 Io.
+ @param[in] ServerIp The pointer to the server address.
+ @param[in] ServerPort The pointer to the server port.
+ @param[in] LocalIp The pointer to the local address.
+ @param[in] LocalPort The pointer to the local port.
+
+ @retval EFI_SUCCESS Configured the Udp6 Io for Mtftp6 successfully.
+ @retval EFI_NO_MAPPING The corresponding Ip6 instance has not been
+ configured yet.
+
+**/
+EFI_STATUS
+Mtftp6ConfigUdpIo (
+ IN UDP_IO *UdpIo,
+ IN EFI_IPv6_ADDRESS *ServerIp,
+ IN UINT16 ServerPort,
+ IN EFI_IPv6_ADDRESS *LocalIp,
+ IN UINT16 LocalPort
+ )
+{
+ EFI_STATUS Status;
+ EFI_UDP6_PROTOCOL *Udp6;
+ EFI_UDP6_CONFIG_DATA *Udp6Cfg;
+
+ Udp6 = UdpIo->Protocol.Udp6;
+ Udp6Cfg = &(UdpIo->Config.Udp6);
+
+ ZeroMem (Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
+
+ //
+ // Set the Udp6 Io configure data.
+ //
+ Udp6Cfg->AcceptPromiscuous = FALSE;
+ Udp6Cfg->AcceptAnyPort = FALSE;
+ Udp6Cfg->AllowDuplicatePort = FALSE;
+ Udp6Cfg->TrafficClass = 0;
+ Udp6Cfg->HopLimit = 128;
+ Udp6Cfg->ReceiveTimeout = 0;
+ Udp6Cfg->TransmitTimeout = 0;
+ Udp6Cfg->StationPort = LocalPort;
+ Udp6Cfg->RemotePort = ServerPort;
+
+ CopyMem (
+ &Udp6Cfg->StationAddress,
+ LocalIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ CopyMem (
+ &Udp6Cfg->RemoteAddress,
+ ServerIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ //
+ // Configure the Udp6 instance with current configure data.
+ //
+ Status = Udp6->Configure (Udp6, Udp6Cfg);
+
+ if (Status == EFI_NO_MAPPING) {
+
+ return Mtftp6GetMapping (UdpIo, Udp6Cfg);
+ }
+
+ return Status;
+}
+
+
+/**
+ Build and transmit the request packet for the Mtftp6 instance.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Operation The operation code of this packet.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request.
+ @retval EFI_SUCCESS The request is built and sent.
+ @retval Others Failed to transmit the packet.
+
+**/
+EFI_STATUS
+Mtftp6SendRequest (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 Operation
+ )
+{
+ EFI_MTFTP6_PACKET *Packet;
+ EFI_MTFTP6_OPTION *Options;
+ EFI_MTFTP6_TOKEN *Token;
+ NET_BUF *Nbuf;
+ UINT8 *Mode;
+ UINT8 *Cur;
+ UINT32 Len1;
+ UINT32 Len2;
+ UINT32 Len;
+ UINTN Index;
+
+ Token = Instance->Token;
+ Options = Token->OptionList;
+ Mode = Token->ModeStr;
+
+ if (Mode == NULL) {
+ Mode = (UINT8 *) "octet";
+ }
+
+ //
+ // The header format of RRQ/WRQ packet is:
+ //
+ // 2 bytes string 1 byte string 1 byte
+ // ------------------------------------------------
+ // | Opcode | Filename | 0 | Mode | 0 |
+ // ------------------------------------------------
+ //
+ // The common option format is:
+ //
+ // string 1 byte string 1 byte
+ // ---------------------------------------
+ // | OptionStr | 0 | ValueStr | 0 |
+ // ---------------------------------------
+ //
+
+ //
+ // Compute the size of new Mtftp6 packet.
+ //
+ Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Token->Filename);
+ Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Mode);
+ Len = Len1 + Len2 + 4;
+
+ for (Index = 0; Index < Token->OptionCount; Index++) {
+ Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
+ Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
+ Len += Len1 + Len2 + 2;
+ }
+
+ //
+ // Allocate a packet then copy the data.
+ //
+ if ((Nbuf = NetbufAlloc (Len)) == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy the opcode, filename and mode into packet.
+ //
+ Packet = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
+ ASSERT (Packet != NULL);
+
+ Packet->OpCode = HTONS (Operation);
+ Cur = Packet->Rrq.Filename;
+ Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Token->Filename);
+ Cur += AsciiStrLen ((CHAR8 *) Token->Filename) + 1;
+ Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Mode);
+ Cur += AsciiStrLen ((CHAR8 *) Mode) + 1;
+
+ //
+ // Copy all the extension options into the packet.
+ //
+ for (Index = 0; Index < Token->OptionCount; ++Index) {
+ Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].OptionStr);
+ Cur += AsciiStrLen ((CHAR8 *) Options[Index].OptionStr) + 1;
+ Cur = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].ValueStr);
+ Cur += AsciiStrLen ((CHAR8 *) (CHAR8 *) Options[Index].ValueStr) + 1;
+ }
+
+ //
+ // Save the packet buf for retransmit
+ //
+ if (Instance->LastPacket != NULL) {
+ NetbufFree (Instance->LastPacket);
+ }
+
+ Instance->LastPacket = Nbuf;
+ Instance->CurRetry = 0;
+
+ return Mtftp6TransmitPacket (Instance, Nbuf);
+}
+
+
+/**
+ Build and send an error packet.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] ErrCode The error code in the packet.
+ @param[in] ErrInfo The error message in the packet.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet.
+ @retval EFI_SUCCESS The error packet is transmitted.
+ @retval Others Failed to transmit the packet.
+
+**/
+EFI_STATUS
+Mtftp6SendError (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 ErrCode,
+ IN UINT8* ErrInfo
+ )
+{
+ NET_BUF *Nbuf;
+ EFI_MTFTP6_PACKET *TftpError;
+ UINT32 Len;
+
+ //
+ // Allocate a packet then copy the data.
+ //
+ Len = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP6_ERROR_HEADER));
+ Nbuf = NetbufAlloc (Len);
+
+ if (Nbuf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TftpError = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
+
+ if (TftpError == NULL) {
+ NetbufFree (Nbuf);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TftpError->OpCode = HTONS (EFI_MTFTP6_OPCODE_ERROR);
+ TftpError->Error.ErrorCode = HTONS (ErrCode);
+
+ AsciiStrCpy ((CHAR8 *) TftpError->Error.ErrorMessage, (CHAR8 *) ErrInfo);
+
+ //
+ // Save the packet buf for retransmit
+ //
+ if (Instance->LastPacket != NULL) {
+ NetbufFree (Instance->LastPacket);
+ }
+
+ Instance->LastPacket = Nbuf;
+ Instance->CurRetry = 0;
+
+ return Mtftp6TransmitPacket (Instance, Nbuf);
+}
+
+
+/**
+ The callback function called when the packet is transmitted.
+
+ @param[in] Packet The pointer to the packet.
+ @param[in] UdpEpt The pointer to the Udp6 access point.
+ @param[in] IoStatus The result of the transmission.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6OnPacketSent (
+ IN NET_BUF *Packet,
+ IN UDP_END_POINT *UdpEpt,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ )
+{
+ NetbufFree (Packet);
+ *(BOOLEAN *) Context = TRUE;
+}
+
+
+/**
+ Send the packet for the Mtftp6 instance.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the packet to be sent.
+
+ @retval EFI_SUCCESS The packet was sent out
+ @retval Others Failed to transmit the packet.
+
+**/
+EFI_STATUS
+Mtftp6TransmitPacket (
+ IN MTFTP6_INSTANCE *Instance,
+ IN NET_BUF *Packet
+ )
+{
+ EFI_UDP6_PROTOCOL *Udp6;
+ EFI_UDP6_CONFIG_DATA Udp6CfgData;
+ EFI_STATUS Status;
+ UINT16 *Temp;
+ UINT16 Value;
+ UINT16 OpCode;
+
+ ZeroMem (&Udp6CfgData, sizeof(EFI_UDP6_CONFIG_DATA));
+ Udp6 = Instance->UdpIo->Protocol.Udp6;
+
+ //
+ // Set the live time of the packet.
+ //
+ Instance->PacketToLive = Instance->IsMaster ? Instance->Timeout : (Instance->Timeout * 2);
+
+ Temp = (UINT16 *) NetbufGetByte (Packet, 0, NULL);
+ ASSERT (Temp != NULL);
+
+ Value = *Temp;
+ OpCode = NTOHS (Value);
+
+ if (OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR || OpCode == EFI_MTFTP6_OPCODE_WRQ) {
+ //
+ // For the Rrq, Dir, Wrq requests of the operation, configure the Udp6Io as
+ // (serverip, 69, localip, localport) to send.
+ // Usually local address and local port are both default as zero.
+ //
+ Status = Udp6->Configure (Udp6, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Mtftp6ConfigUdpIo (
+ Instance->UdpIo,
+ &Instance->ServerIp,
+ Instance->ServerCmdPort,
+ &Instance->Config->StationIp,
+ Instance->Config->LocalPort
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the current local address and port by get Udp6 mode data.
+ //
+ Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ NET_GET_REF (Packet);
+
+ Instance->IsTransmitted = FALSE;
+
+ Status = UdpIoSendDatagram (
+ Instance->UdpIo,
+ Packet,
+ NULL,
+ NULL,
+ Mtftp6OnPacketSent,
+ &Instance->IsTransmitted
+ );
+
+ if (EFI_ERROR (Status)) {
+ NET_PUT_REF (Packet);
+ return Status;
+ }
+
+ //
+ // Poll till the packet sent out from the ip6 queue.
+ //
+ gBS->RestoreTPL (Instance->OldTpl);
+
+ while (!Instance->IsTransmitted) {
+ Udp6->Poll (Udp6);
+ }
+
+ Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // For the subsequent exchange of such requests, reconfigure the Udp6Io as
+ // (serverip, 0, localip, localport) to receive.
+ // Currently local address and local port are specified by Udp6 mode data.
+ //
+ Status = Udp6->Configure (Udp6, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Mtftp6ConfigUdpIo (
+ Instance->UdpIo,
+ &Instance->ServerIp,
+ Instance->ServerDataPort,
+ &Udp6CfgData.StationAddress,
+ Udp6CfgData.StationPort
+ );
+ } else {
+ //
+ // For the data exchange, configure the Udp6Io as (serverip, dataport,
+ // localip, localport) to send/receive.
+ // Currently local address and local port are specified by Udp6 mode data.
+ //
+ Status = Udp6->GetModeData (Udp6, &Udp6CfgData, NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Udp6CfgData.RemotePort != Instance->ServerDataPort) {
+
+ Status = Udp6->Configure (Udp6, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Mtftp6ConfigUdpIo (
+ Instance->UdpIo,
+ &Instance->ServerIp,
+ Instance->ServerDataPort,
+ &Udp6CfgData.StationAddress,
+ Udp6CfgData.StationPort
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ NET_GET_REF (Packet);
+
+ Instance->IsTransmitted = FALSE;
+
+ Status = UdpIoSendDatagram (
+ Instance->UdpIo,
+ Packet,
+ NULL,
+ NULL,
+ Mtftp6OnPacketSent,
+ &Instance->IsTransmitted
+ );
+
+ if (EFI_ERROR (Status)) {
+ NET_PUT_REF (Packet);
+ }
+
+ //
+ // Poll till the packet sent out from the ip6 queue.
+ //
+ gBS->RestoreTPL (Instance->OldTpl);
+
+ while (!Instance->IsTransmitted) {
+ Udp6->Poll (Udp6);
+ }
+
+ Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ }
+
+ return Status;
+}
+
+
+/**
+ Check packet for GetInfo callback routine.
+
+ GetInfo is implemented with EfiMtftp6ReadFile. It's used to inspect
+ the first packet from server, then abort the session.
+
+ @param[in] This The pointer to the Mtftp6 protocol.
+ @param[in] Token The pointer to the Mtftp6 token.
+ @param[in] PacketLen The length of the packet.
+ @param[in] Packet The pointer to the received packet.
+
+ @retval EFI_ABORTED Abort the Mtftp6 operation.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6CheckPacket (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token,
+ IN UINT16 PacketLen,
+ IN EFI_MTFTP6_PACKET *Packet
+ )
+{
+ MTFTP6_GETINFO_CONTEXT *Context;
+ UINT16 OpCode;
+
+ Context = (MTFTP6_GETINFO_CONTEXT *) Token->Context;
+ OpCode = NTOHS (Packet->OpCode);
+
+ //
+ // Set the GetInfo's return status according to the OpCode.
+ //
+ switch (OpCode) {
+ case EFI_MTFTP6_OPCODE_ERROR:
+ Context->Status = EFI_TFTP_ERROR;
+ break;
+
+ case EFI_MTFTP6_OPCODE_OACK:
+ Context->Status = EFI_SUCCESS;
+ break;
+
+ default:
+ Context->Status = EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Allocate buffer then copy the packet over. Use gBS->AllocatePool
+ // in case NetAllocatePool will implements something tricky.
+ //
+ *(Context->Packet) = AllocateZeroPool (PacketLen);
+
+ if (*(Context->Packet) == NULL) {
+ Context->Status = EFI_OUT_OF_RESOURCES;
+ return EFI_ABORTED;
+ }
+
+ *(Context->PacketLen) = PacketLen;
+ CopyMem (*(Context->Packet), Packet, PacketLen);
+
+ return EFI_ABORTED;
+}
+
+
+/**
+ Clean up the current Mtftp6 operation.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Result The result to be returned to the user.
+
+**/
+VOID
+Mtftp6OperationClean (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_STATUS Result
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ MTFTP6_BLOCK_RANGE *Block;
+
+ //
+ // Clean up the current token and event.
+ //
+ if (Instance->Token != NULL) {
+ Instance->Token->Status = Result;
+ if (Instance->Token->Event != NULL) {
+ gBS->SignalEvent (Instance->Token->Event);
+ }
+ Instance->Token = NULL;
+ }
+
+ //
+ // Clean up the corresponding Udp6Io.
+ //
+ if (Instance->UdpIo != NULL) {
+ UdpIoCleanIo (Instance->UdpIo);
+ }
+
+ if (Instance->McastUdpIo != NULL) {
+ UdpIoFreeIo (Instance->McastUdpIo);
+ Instance->McastUdpIo = NULL;
+ }
+
+ //
+ // Clean up the stored last packet.
+ //
+ if (Instance->LastPacket != NULL) {
+ NetbufFree (Instance->LastPacket);
+ Instance->LastPacket = NULL;
+ }
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->BlkList) {
+ Block = NET_LIST_USER_STRUCT (Entry, MTFTP6_BLOCK_RANGE, Link);
+ RemoveEntryList (Entry);
+ FreePool (Block);
+ }
+
+ //
+ // Reinitialize the corresponding fields of the Mtftp6 operation.
+ //
+ ZeroMem (&Instance->ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
+ ZeroMem (&Instance->ServerIp, sizeof (EFI_IPv6_ADDRESS));
+ ZeroMem (&Instance->McastIp, sizeof (EFI_IPv6_ADDRESS));
+
+ Instance->ServerCmdPort = 0;
+ Instance->ServerDataPort = 0;
+ Instance->McastPort = 0;
+ Instance->BlkSize = 0;
+ Instance->LastBlk = 0;
+ Instance->PacketToLive = 0;
+ Instance->MaxRetry = 0;
+ Instance->CurRetry = 0;
+ Instance->Timeout = 0;
+ Instance->IsMaster = TRUE;
+}
+
+
+/**
+ Start the Mtftp6 instance to perform the operation, such as read file,
+ write file, and read directory.
+
+ @param[in] This The MTFTP session.
+ @param[in] Token The token than encapsues the user's request.
+ @param[in] OpCode The operation to perform.
+
+ @retval EFI_INVALID_PARAMETER Some of the parameters are invalid.
+ @retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
+ @retval EFI_ALREADY_STARTED There is pending operation for the session.
+ @retval EFI_SUCCESS The operation is successfully started.
+
+**/
+EFI_STATUS
+Mtftp6OperationStart (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token,
+ IN UINT16 OpCode
+ )
+{
+ MTFTP6_INSTANCE *Instance;
+ EFI_STATUS Status;
+
+ if (This == NULL ||
+ Token == NULL ||
+ Token->Filename == NULL ||
+ (Token->OptionCount != 0 && Token->OptionList == NULL) ||
+ (Token->OverrideData != NULL && !NetIp6IsValidUnicast (&Token->OverrideData->ServerIp))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // At least define one method to collect the data for download.
+ //
+ if ((OpCode == EFI_MTFTP6_OPCODE_RRQ || OpCode == EFI_MTFTP6_OPCODE_DIR) &&
+ Token->Buffer == NULL &&
+ Token->CheckPacket == NULL
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // At least define one method to provide the data for upload.
+ //
+ if (OpCode == EFI_MTFTP6_OPCODE_WRQ && Token->Buffer == NULL && Token->PacketNeeded == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = MTFTP6_INSTANCE_FROM_THIS (This);
+
+ if (Instance->Config == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Instance->Token != NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = EFI_SUCCESS;
+ Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Parse the extension options in the request packet.
+ //
+ if (Token->OptionCount != 0) {
+
+ Status = Mtftp6ParseExtensionOption (
+ Token->OptionList,
+ Token->OptionCount,
+ TRUE,
+ &Instance->ExtInfo
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ //
+ // Initialize runtime data from config data or override data.
+ //
+ Instance->Token = Token;
+ Instance->ServerCmdPort = Instance->Config->InitialServerPort;
+ Instance->ServerDataPort = 0;
+ Instance->MaxRetry = Instance->Config->TryCount;
+ Instance->Timeout = Instance->Config->TimeoutValue;
+ Instance->IsMaster = TRUE;
+
+ CopyMem (
+ &Instance->ServerIp,
+ &Instance->Config->ServerIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ if (Token->OverrideData != NULL) {
+ Instance->ServerCmdPort = Token->OverrideData->ServerPort;
+ Instance->MaxRetry = Token->OverrideData->TryCount;
+ Instance->Timeout = Token->OverrideData->TimeoutValue;
+
+ CopyMem (
+ &Instance->ServerIp,
+ &Token->OverrideData->ServerIp,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+ }
+
+ //
+ // Set default value for undefined parameters.
+ //
+ if (Instance->ServerCmdPort == 0) {
+ Instance->ServerCmdPort = MTFTP6_DEFAULT_SERVER_CMD_PORT;
+ }
+ if (Instance->BlkSize == 0) {
+ Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
+ }
+ if (Instance->MaxRetry == 0) {
+ Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
+ }
+ if (Instance->Timeout == 0) {
+ Instance->Timeout = MTFTP6_DEFAULT_TIMEOUT;
+ }
+
+ Token->Status = EFI_NOT_READY;
+
+ //
+ // Switch the routines by the operation code.
+ //
+ switch (OpCode) {
+ case EFI_MTFTP6_OPCODE_RRQ:
+ Status = Mtftp6RrqStart (Instance, OpCode);
+ break;
+
+ case EFI_MTFTP6_OPCODE_DIR:
+ Status = Mtftp6RrqStart (Instance, OpCode);
+ break;
+
+ case EFI_MTFTP6_OPCODE_WRQ:
+ Status = Mtftp6WrqStart (Instance, OpCode);
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_ERROR;
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Return immediately for asynchronous or poll the instance for synchronous.
+ //
+ gBS->RestoreTPL (Instance->OldTpl);
+
+ if (Token->Event == NULL) {
+ while (Token->Status == EFI_NOT_READY) {
+ This->Poll (This);
+ }
+ return Token->Status;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ Mtftp6OperationClean (Instance, Status);
+ gBS->RestoreTPL (Instance->OldTpl);
+
+ return Status;
+}
+
+
+/**
+ The timer ticking routine for the Mtftp6 instance.
+
+ @param[in] Event The pointer to the ticking event.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6OnTimerTick (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ MTFTP6_SERVICE *Service;
+ MTFTP6_INSTANCE *Instance;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ EFI_MTFTP6_TOKEN *Token;
+ EFI_STATUS Status;
+
+ Service = (MTFTP6_SERVICE *) Context;
+
+ //
+ // Iterate through all the children of the Mtftp service instance. Time
+ // out the packet. If maximum retries reached, clean the session up.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Children) {
+
+ Instance = NET_LIST_USER_STRUCT (Entry, MTFTP6_INSTANCE, Link);
+
+ if (Instance->Token == NULL) {
+ continue;
+ }
+
+ if (Instance->PacketToLive > 0) {
+ Instance->PacketToLive--;
+ continue;
+ }
+
+ Instance->CurRetry++;
+ Token = Instance->Token;
+
+ if (Token->TimeoutCallback != NULL) {
+ //
+ // Call the timeout callback routine if has.
+ //
+ Status = Token->TimeoutCallback (&Instance->Mtftp6, Token);
+
+ if (EFI_ERROR (Status)) {
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
+ (UINT8 *) "User aborted the transfer in time out"
+ );
+ Mtftp6OperationClean (Instance, EFI_ABORTED);
+ continue;
+ }
+ }
+
+ //
+ // Retransmit the packet if haven't reach the maxmium retry count,
+ // otherwise exit the transfer.
+ //
+ if (Instance->CurRetry < Instance->MaxRetry) {
+ Mtftp6TransmitPacket (Instance, Instance->LastPacket);
+ } else {
+ Mtftp6OperationClean (Instance, EFI_TIMEOUT);
+ continue;
+ }
+ }
+}
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.h b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.h
new file mode 100644
index 0000000000..37f03fe298
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.h
@@ -0,0 +1,359 @@
+/** @file
+ Mtftp6 support functions declaration.
+
+ 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 __EFI_MTFTP6_SUPPORT_H__
+#define __EFI_MTFTP6_SUPPORT_H__
+
+//
+// The structure representing a range of block numbers, [Start, End].
+// It is used to remember the holes in the MTFTP block space. If all
+// the holes are filled in, then the download or upload has completed.
+//
+typedef struct {
+ LIST_ENTRY Link;
+ INTN Start;
+ INTN End;
+ INTN Round;
+ INTN Bound;
+} MTFTP6_BLOCK_RANGE;
+
+
+/**
+ Initialize the block range for either RRQ or WRQ. RRQ and WRQ have
+ different requirements for Start and End. For example, during startup,
+ WRQ initializes its whole valid block range to [0, 0xffff]. This
+ is because the server will send an ACK0 to inform the user to start the
+ upload. When the client receives an ACK0, it will remove 0 from the range,
+ get the next block number, which is 1, then upload the BLOCK1. For RRQ
+ without option negotiation, the server will directly send us the BLOCK1
+ in response to the client's RRQ. When BLOCK1 is received, the client will
+ remove it from the block range and send an ACK. It also works if there
+ is option negotiation.
+
+ @param[in] Head The block range head to initialize.
+ @param[in] Start The Start block number.
+ @param[in] End The last block number.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range.
+ @retval EFI_SUCCESS The initial block range is created.
+
+**/
+EFI_STATUS
+Mtftp6InitBlockRange (
+ IN LIST_ENTRY *Head,
+ IN UINT16 Start,
+ IN UINT16 End
+ );
+
+
+/**
+ Get the first valid block number on the range list.
+
+ @param[in] Head The block range head.
+
+ @retval ==-1 If the block range is empty.
+ @retval >-1 The first valid block number.
+
+**/
+INTN
+Mtftp6GetNextBlockNum (
+ IN LIST_ENTRY *Head
+ );
+
+
+/**
+ Set the last block number of the block range list. It
+ removes all the blocks after the Last. MTFTP initialize the
+ block range to the maximum possible range, such as [0, 0xffff]
+ for WRQ. When it gets the last block number, it calls
+ this function to set the last block number.
+
+ @param[in] Head The block range list.
+ @param[in] Last The last block number.
+
+**/
+VOID
+Mtftp6SetLastBlockNum (
+ IN LIST_ENTRY *Head,
+ IN UINT16 Last
+ );
+
+
+/**
+ Remove the block number from the block range list.
+
+ @param[in] Head The block range list to remove from.
+ @param[in] Num The block number to remove.
+ @param[in] Completed Whether Num is the last block number
+ @param[out] TotalBlock The continuous block number in all
+
+ @retval EFI_NOT_FOUND The block number isn't in the block range list.
+ @retval EFI_SUCCESS The block number has been removed from the list.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+Mtftp6RemoveBlockNum (
+ IN LIST_ENTRY *Head,
+ IN UINT16 Num,
+ IN BOOLEAN Completed,
+ OUT UINT64 *TotalBlock
+ );
+
+
+/**
+ Build and transmit the request packet for the Mtftp6 instance.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Operation The operation code of this packet.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request.
+ @retval EFI_SUCCESS The request was built and sent.
+ @retval Others Failed to transmit the packet.
+
+**/
+EFI_STATUS
+Mtftp6SendRequest (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 Operation
+ );
+
+
+/**
+ Build and send an error packet.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] ErrCode The error code in the packet.
+ @param[in] ErrInfo The error message in the packet.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet.
+ @retval EFI_SUCCESS The error packet was transmitted.
+ @retval Others Failed to transmit the packet.
+
+**/
+EFI_STATUS
+Mtftp6SendError (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 ErrCode,
+ IN UINT8* ErrInfo
+ );
+
+
+/**
+ Send the packet for the Mtftp6 instance.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the packet to be sent.
+
+ @retval EFI_SUCCESS The packet was sent out
+ @retval Others Failed to transmit the packet.
+
+**/
+EFI_STATUS
+Mtftp6TransmitPacket (
+ IN MTFTP6_INSTANCE *Instance,
+ IN NET_BUF *Packet
+ );
+
+
+/**
+ Check packet for GetInfo callback routine.
+
+ @param[in] This The pointer to the Mtftp6 protocol.
+ @param[in] Token The pointer to the Mtftp6 token.
+ @param[in] PacketLen The length of the packet
+ @param[in] Packet The pointer to the received packet.
+
+ @retval EFI_SUCCESS The check process passed successfully.
+ @retval EFI_ABORTED Abort the Mtftp6 operation.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6CheckPacket (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token,
+ IN UINT16 PacketLen,
+ IN EFI_MTFTP6_PACKET *Packet
+ );
+
+
+/**
+ The dummy configure routine for create a new Udp6 Io.
+
+ @param[in] UdpIo The pointer to the Udp6 Io.
+ @param[in] Context The pointer to the context.
+
+ @retval EFI_SUCCESS The value is always returned.
+
+**/
+EFI_STATUS
+EFIAPI
+Mtftp6ConfigDummyUdpIo (
+ IN UDP_IO *UdpIo,
+ IN VOID *Context
+ );
+
+
+/**
+ The configure routine for the Mtftp6 instance to transmit/receive.
+
+ @param[in] UdpIo The pointer to the Udp6 Io.
+ @param[in] ServerIp The pointer to the server address.
+ @param[in] ServerPort The pointer to the server port.
+ @param[in] LocalIp The pointer to the local address.
+ @param[in] LocalPort The pointer to the local port.
+
+ @retval EFI_SUCCESS Configure the Udp6 Io for Mtftp6 successfully.
+ @retval EFI_NO_MAPPING The corresponding Ip6 instance has not been
+ configured yet.
+
+**/
+EFI_STATUS
+Mtftp6ConfigUdpIo (
+ IN UDP_IO *UdpIo,
+ IN EFI_IPv6_ADDRESS *ServerIp,
+ IN UINT16 ServerPort,
+ IN EFI_IPv6_ADDRESS *LocalIp,
+ IN UINT16 LocalPort
+ );
+
+
+/**
+ Clean up the current Mtftp6 operation.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Result The result to be returned to the user.
+
+**/
+VOID
+Mtftp6OperationClean (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_STATUS Result
+ );
+
+
+/**
+ Start the Mtftp6 instance to perform the operation, such as read file,
+ write file, and read directory.
+
+ @param[in] This The MTFTP session
+ @param[in] Token The token that encapsulates the user's request.
+ @param[in] OpCode The operation to perform.
+
+ @retval EFI_INVALID_PARAMETER Some of the parameters are invalid.
+ @retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
+ @retval EFI_ALREADY_STARTED There is pending operation for the session.
+ @retval EFI_SUCCESS The operation was successfully started.
+
+**/
+EFI_STATUS
+Mtftp6OperationStart (
+ IN EFI_MTFTP6_PROTOCOL *This,
+ IN EFI_MTFTP6_TOKEN *Token,
+ IN UINT16 OpCode
+ );
+
+
+/**
+ The timer ticking routine for the Mtftp6 instance.
+
+ @param[in] Event The pointer to the ticking event.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6OnTimerTick (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+/**
+ The packet process callback for Mtftp6 upload.
+
+ @param[in] UdpPacket The pointer to the packet received.
+ @param[in] UdpEpt The pointer to the Udp6 access point.
+ @param[in] IoStatus The status from the Udp6 instance.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6WrqInput (
+ IN NET_BUF *UdpPacket,
+ IN UDP_END_POINT *UdpEpt,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ );
+
+
+/**
+ Start the Mtftp6 instance to upload. It will first init some states,
+ then send the WRQ request packet, and start to receive the packet.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Operation The operation code of current packet.
+
+ @retval EFI_SUCCESS The Mtftp6 was started to upload.
+ @retval Others Failed to start to upload.
+
+**/
+EFI_STATUS
+Mtftp6WrqStart (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 Operation
+ );
+
+
+/**
+ The packet process callback for Mtftp6 download.
+
+ @param[in] UdpPacket The pointer to the packet received.
+ @param[in] UdpEpt The pointer to the Udp6 access point.
+ @param[in] IoStatus The status from Udp6 instance.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6RrqInput (
+ IN NET_BUF *UdpPacket,
+ IN UDP_END_POINT *UdpEpt,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ );
+
+
+/**
+ Start the Mtftp6 instance to download. It first initializes some
+ of the internal states then builds and sends an RRQ reqeuest packet.
+ Finally, it starts receive for the downloading.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Operation The operation code of current packet.
+
+ @retval EFI_SUCCESS The Mtftp6 was started to download.
+ @retval Others Failed to start to download.
+
+**/
+EFI_STATUS
+Mtftp6RrqStart (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 Operation
+ );
+
+#endif
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
new file mode 100644
index 0000000000..69ef4d2093
--- /dev/null
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
@@ -0,0 +1,602 @@
+/** @file
+ Mtftp6 Wrq process functions 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 "Mtftp6Impl.h"
+
+
+
+/**
+ Build and send a Mtftp6 data packet for upload.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] BlockNum The block num to be sent.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
+ @retval EFI_SUCCESS The data packet was sent.
+ @retval EFI_ABORTED The user aborted this process.
+
+**/
+EFI_STATUS
+Mtftp6WrqSendBlock (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 BlockNum
+ )
+{
+ EFI_MTFTP6_PACKET *Packet;
+ EFI_MTFTP6_TOKEN *Token;
+ NET_BUF *UdpPacket;
+ EFI_STATUS Status;
+ UINT16 DataLen;
+ UINT8 *DataBuf;
+ UINT64 Start;
+
+ //
+ // Allocate net buffer to create data packet.
+ //
+ UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP6_DATA_HEAD_LEN);
+
+ if (UdpPacket == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Packet = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
+ UdpPacket,
+ MTFTP6_DATA_HEAD_LEN,
+ FALSE
+ );
+ ASSERT (Packet != NULL);
+
+ Packet->Data.OpCode = HTONS (EFI_MTFTP6_OPCODE_DATA);
+ Packet->Data.Block = HTONS (BlockNum);
+
+ //
+ // Read the block from either the buffer or PacketNeeded callback
+ //
+ Token = Instance->Token;
+ DataLen = Instance->BlkSize;
+
+ if (Token->Buffer != NULL) {
+ Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
+
+ if (Token->BufferSize < Start + Instance->BlkSize) {
+ DataLen = (UINT16) (Token->BufferSize - Start);
+ Instance->LastBlk = BlockNum;
+ Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
+ }
+
+ if (DataLen > 0) {
+ NetbufAllocSpace (UdpPacket, DataLen, FALSE);
+ CopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);
+ }
+
+ } else {
+ //
+ // Get data from PacketNeeded
+ //
+ DataBuf = NULL;
+ Status = Token->PacketNeeded (&Instance->Mtftp6, Token, &DataLen, (VOID*) &DataBuf);
+
+ if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
+ if (DataBuf != NULL) {
+ gBS->FreePool (DataBuf);
+ }
+ //
+ // The received packet has already been freed.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
+ (UINT8 *) "User aborted the transfer"
+ );
+
+ return EFI_ABORTED;
+ }
+
+ if (DataLen < Instance->BlkSize) {
+ Instance->LastBlk = BlockNum;
+ Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
+ }
+
+ if (DataLen > 0) {
+ NetbufAllocSpace (UdpPacket, DataLen, FALSE);
+ CopyMem (Packet->Data.Data, DataBuf, DataLen);
+ gBS->FreePool (DataBuf);
+ }
+ }
+
+ //
+ // Reset current retry count of the instance.
+ //
+ Instance->CurRetry = 0;
+
+ return Mtftp6TransmitPacket (Instance, UdpPacket);
+}
+
+
+/**
+ Function to handle received ACK packet. If the ACK number matches the
+ expected block number, with more data pending, send the next
+ block. Otherwise, tell the caller that we are done.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the received packet.
+ @param[in] Len The length of the packet.
+ @param[out] UdpPacket The net buf of received packet.
+ @param[out] IsCompleted If TRUE, the upload has been completed.
+ Otherwise, the upload has not been completed.
+
+ @retval EFI_SUCCESS The ACK packet successfully processed.
+ @retval EFI_TFTP_ERROR The block number loops back.
+ @retval Others Failed to transmit the next data packet.
+
+**/
+EFI_STATUS
+Mtftp6WrqHandleAck (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 Len,
+ OUT NET_BUF **UdpPacket,
+ OUT BOOLEAN *IsCompleted
+ )
+{
+ UINT16 AckNum;
+ INTN Expected;
+ UINT64 TotalBlock;
+
+ *IsCompleted = FALSE;
+ AckNum = NTOHS (Packet->Ack.Block[0]);
+ Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
+
+ ASSERT (Expected >= 0);
+
+ //
+ // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput
+ // restart receive.
+ //
+ if (Expected != AckNum) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Remove the acked block number, if this is the last block number,
+ // tell the Mtftp6WrqInput to finish the transfer. This is the last
+ // block number if the block range are empty..
+ //
+ Mtftp6RemoveBlockNum (&Instance->BlkList, AckNum, *IsCompleted, &TotalBlock);
+
+ Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
+
+ if (Expected < 0) {
+ //
+ // The block range is empty. It may either because the the last
+ // block has been ACKed, or the sequence number just looped back,
+ // that is, there is more than 0xffff blocks.
+ //
+ if (Instance->LastBlk == AckNum) {
+ ASSERT (Instance->LastBlk >= 1);
+ *IsCompleted = TRUE;
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if block number rolls back.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
+ (UINT8 *) "Block number rolls back, not supported, try blksize option"
+ );
+
+ return EFI_TFTP_ERROR;
+ }
+ }
+
+ //
+ // Free the receive buffer before send new packet since it might need
+ // reconfigure udpio.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+
+ return Mtftp6WrqSendBlock (Instance, (UINT16) Expected);
+}
+
+
+/**
+ Check whether the received OACK is valid. The OACK is valid
+ only if:
+ 1. It only include options requested by us.
+ 2. It can only include a smaller block size.
+ 3. It can't change the proposed time out value.
+ 4. Other requirements of the individal MTFTP6 options as required.
+
+ @param[in] ReplyInfo The pointer to options information in reply packet.
+ @param[in] RequestInfo The pointer to requested options information.
+
+ @retval TRUE If the option in OACK is valid.
+ @retval FALSE If the option is invalid.
+
+**/
+BOOLEAN
+Mtftp6WrqOackValid (
+ IN MTFTP6_EXT_OPTION_INFO *ReplyInfo,
+ IN MTFTP6_EXT_OPTION_INFO *RequestInfo
+ )
+{
+ //
+ // It is invalid for server to return options we don't request
+ //
+ if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
+ return FALSE;
+ }
+
+ //
+ // Server can only specify a smaller block size to be used and
+ // return the timeout matches that requested.
+ //
+ if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && (ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
+ (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
+ ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Process the OACK packet for Wrq.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Packet The pointer to the received packet.
+ @param[in] Len The length of the packet.
+ @param[out] UdpPacket The net buf of received packet.
+ @param[out] IsCompleted If TRUE, the upload has been completed.
+ Otherwise, the upload has not been completed.
+
+ @retval EFI_SUCCESS The OACK packet successfully processed.
+ @retval EFI_TFTP_ERROR An TFTP communication error happened.
+ @retval Others Failed to process the OACK packet.
+
+**/
+EFI_STATUS
+Mtftp6WrqHandleOack (
+ IN MTFTP6_INSTANCE *Instance,
+ IN EFI_MTFTP6_PACKET *Packet,
+ IN UINT32 Len,
+ OUT NET_BUF **UdpPacket,
+ OUT BOOLEAN *IsCompleted
+ )
+{
+ EFI_MTFTP6_OPTION *Options;
+ UINT32 Count;
+ MTFTP6_EXT_OPTION_INFO ExtInfo;
+ EFI_MTFTP6_PACKET Dummy;
+ EFI_STATUS Status;
+ INTN Expected;
+
+ *IsCompleted = FALSE;
+
+ //
+ // Ignore the OACK if already started the upload
+ //
+ Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
+
+ if (Expected != 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse and validate the options from server
+ //
+ ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
+
+ Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
+
+ if (EFI_ERROR(Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) {
+ //
+ // Don't send a MTFTP error packet when out of resource, it can
+ // only make it worse.
+ //
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (*UdpPacket);
+ *UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if invalid Oack packet received.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
+ (UINT8 *) "Mal-formated OACK packet"
+ );
+ }
+
+ return EFI_TFTP_ERROR;
+ }
+
+ if (ExtInfo.BlkSize != 0) {
+ Instance->BlkSize = ExtInfo.BlkSize;
+ }
+
+ if (ExtInfo.Timeout != 0) {
+ Instance->Timeout = ExtInfo.Timeout;
+ }
+
+ //
+ // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,
+ // which will start the transmission of the first data block.
+ //
+ Dummy.Ack.OpCode = HTONS (EFI_MTFTP6_OPCODE_ACK);
+ Dummy.Ack.Block[0] = 0;
+
+ return Mtftp6WrqHandleAck (
+ Instance,
+ &Dummy,
+ sizeof (EFI_MTFTP6_ACK_HEADER),
+ UdpPacket,
+ IsCompleted
+ );
+}
+
+
+/**
+ The packet process callback for Mtftp6 upload.
+
+ @param[in] UdpPacket The pointer to the packet received.
+ @param[in] UdpEpt The pointer to the Udp6 access point.
+ @param[in] IoStatus The status from Udp6 instance.
+ @param[in] Context The pointer to the context.
+
+**/
+VOID
+EFIAPI
+Mtftp6WrqInput (
+ IN NET_BUF *UdpPacket,
+ IN UDP_END_POINT *UdpEpt,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ )
+{
+ MTFTP6_INSTANCE *Instance;
+ EFI_MTFTP6_PACKET *Packet;
+ BOOLEAN IsCompleted;
+ EFI_STATUS Status;
+ UINT32 TotalNum;
+ UINT32 Len;
+ UINT16 Opcode;
+
+ Instance = (MTFTP6_INSTANCE *) Context;
+
+ NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
+
+ IsCompleted = FALSE;
+ Packet = NULL;
+ Status = EFI_SUCCESS;
+ TotalNum = 0;
+
+ //
+ // Return error status if Udp6 instance failed to receive.
+ //
+ if (EFI_ERROR (IoStatus)) {
+ Status = IoStatus;
+ goto ON_EXIT;
+ }
+
+ ASSERT (UdpPacket != NULL);
+
+ if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Client send initial request to server's listening port. Server
+ // will select a UDP port to communicate with the client.
+ //
+ if (UdpEpt->RemotePort != Instance->ServerDataPort) {
+ if (Instance->ServerDataPort != 0) {
+ goto ON_EXIT;
+ } else {
+ Instance->ServerDataPort = UdpEpt->RemotePort;
+ }
+ }
+
+ //
+ // Copy the MTFTP packet to a continuous buffer if it isn't already so.
+ //
+ Len = UdpPacket->TotalSize;
+ TotalNum = UdpPacket->BlockOpNum;
+
+ if (TotalNum > 1) {
+ Packet = AllocateZeroPool (Len);
+
+ if (Packet == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
+
+ } else {
+ Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
+ ASSERT (Packet != NULL);
+ }
+
+ Opcode = NTOHS (Packet->OpCode);
+
+ //
+ // Callback to the user's CheckPacket if provided. Abort the transmission
+ // if CheckPacket returns an EFI_ERROR code.
+ //
+ if (Instance->Token->CheckPacket != NULL &&
+ (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR)
+ ) {
+
+ Status = Instance->Token->CheckPacket (
+ &Instance->Mtftp6,
+ Instance->Token,
+ (UINT16) Len,
+ Packet
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Send an error message to the server to inform it
+ //
+ if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
+ //
+ // Free the received packet before send new packet in ReceiveNotify,
+ // since the udpio might need to be reconfigured.
+ //
+ NetbufFree (UdpPacket);
+ UdpPacket = NULL;
+ //
+ // Send the Mtftp6 error message if user aborted the current session.
+ //
+ Mtftp6SendError (
+ Instance,
+ EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
+ (UINT8 *) "User aborted the transfer"
+ );
+ }
+
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Switch the process routines by the operation code.
+ //
+ switch (Opcode) {
+ case EFI_MTFTP6_OPCODE_ACK:
+ if (Len != MTFTP6_OPCODE_LEN + MTFTP6_BLKNO_LEN) {
+ goto ON_EXIT;
+ }
+ //
+ // Handle the Ack packet of Wrq.
+ //
+ Status = Mtftp6WrqHandleAck (Instance, Packet, Len, &UdpPacket, &IsCompleted);
+ break;
+
+ case EFI_MTFTP6_OPCODE_OACK:
+ if (Len <= MTFTP6_OPCODE_LEN) {
+ goto ON_EXIT;
+ }
+ //
+ // Handle the Oack packet of Wrq.
+ //
+ Status = Mtftp6WrqHandleOack (Instance, Packet, Len, &UdpPacket, &IsCompleted);
+ break;
+
+ default:
+ //
+ // Drop and return eror if received error message.
+ //
+ Status = EFI_TFTP_ERROR;
+ break;
+ }
+
+ON_EXIT:
+ //
+ // Free the resources, then if !EFI_ERROR (Status) and not completed,
+ // restart the receive, otherwise end the session.
+ //
+ if (Packet != NULL && TotalNum > 1) {
+ FreePool (Packet);
+ }
+
+ if (UdpPacket != NULL) {
+ NetbufFree (UdpPacket);
+ }
+
+ if (!EFI_ERROR (Status) && !IsCompleted) {
+ Status = UdpIoRecvDatagram (
+ Instance->UdpIo,
+ Mtftp6WrqInput,
+ Instance,
+ 0
+ );
+ }
+ //
+ // Clean up the current session if failed to continue.
+ //
+ if (EFI_ERROR (Status) || IsCompleted) {
+ Mtftp6OperationClean (Instance, Status);
+ }
+}
+
+
+/**
+ Start the Mtftp6 instance to upload. It will first init some states,
+ then send the WRQ request packet, and start to receive the packet.
+
+ @param[in] Instance The pointer to the Mtftp6 instance.
+ @param[in] Operation The operation code of the current packet.
+
+ @retval EFI_SUCCESS The Mtftp6 was started to upload.
+ @retval Others Failed to start to upload.
+
+**/
+EFI_STATUS
+Mtftp6WrqStart (
+ IN MTFTP6_INSTANCE *Instance,
+ IN UINT16 Operation
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // The valid block number range are [0, 0xffff]. For example:
+ // the client sends an WRQ request to the server, the server
+ // ACK with an ACK0 to let client start transfer the first
+ // packet.
+ //
+ Status = Mtftp6InitBlockRange (&Instance->BlkList, 0, 0xffff);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Mtftp6SendRequest (Instance, Operation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return UdpIoRecvDatagram (
+ Instance->UdpIo,
+ Mtftp6WrqInput,
+ Instance,
+ 0
+ );
+}
+