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
This commit is contained in:
hhtian
2010-11-01 06:13:54 +00:00
parent 12873d5766
commit a3bcde70e6
142 changed files with 83988 additions and 0 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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
);
}