Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
161
MdeModulePkg/Universal/Network/Mtftp4Dxe/ComponentName.c
Normal file
161
MdeModulePkg/Universal/Network/Mtftp4Dxe/ComponentName.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
ComponentName.c
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Driver.h"
|
||||
|
||||
//
|
||||
// EFI Component Name Functions
|
||||
//
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
);
|
||||
|
||||
//
|
||||
// EFI Component Name Protocol
|
||||
//
|
||||
EFI_COMPONENT_NAME_PROTOCOL gMtftp4ComponentName = {
|
||||
Mtftp4ComponentNameGetDriverName,
|
||||
Mtftp4ComponentNameGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
static EFI_UNICODE_STRING_TABLE mMtftp4DriverNameTable[] = {
|
||||
{
|
||||
"eng",
|
||||
L"MTFTP4 Network Service"
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Retrieves a Unicode string that is the user readable name of the EFI Driver.
|
||||
|
||||
Arguments:
|
||||
This : A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
Language : A pointer to a three character ISO 639-2 language identifier.
|
||||
This is the language of the driver name that that the caller
|
||||
is requesting, and it must match one of the languages specified
|
||||
in SupportedLanguages. The number of languages supported by a
|
||||
driver is up to the driver writer.
|
||||
DriverName : A pointer to the Unicode string to return. This Unicode string
|
||||
is the name of the driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
Returns:
|
||||
EFI_SUCCES : The Unicode string for the Driver specified by This
|
||||
and the language specified by Language was returned
|
||||
in DriverName.
|
||||
EFI_INVALID_PARAMETER : Language is NULL.
|
||||
EFI_INVALID_PARAMETER : DriverName is NULL.
|
||||
EFI_UNSUPPORTED : The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
--*/
|
||||
{
|
||||
return LookupUnicodeString (
|
||||
Language,
|
||||
gMtftp4ComponentName.SupportedLanguages,
|
||||
mMtftp4DriverNameTable,
|
||||
DriverName
|
||||
);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4ComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by an EFI Driver.
|
||||
|
||||
Arguments:
|
||||
This : A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
ControllerHandle :The handle of a controller that the driver specified by
|
||||
This is managing. This handle specifies the controller
|
||||
whose name is to be returned.
|
||||
ChildHandle :The handle of the child controller to retrieve the name
|
||||
of. This is an optional parameter that may be NULL. It
|
||||
will be NULL for device drivers. It will also be NULL
|
||||
for a bus drivers that wish to retrieve the name of the
|
||||
bus controller. It will not be NULL for a bus driver
|
||||
that wishes to retrieve the name of a child controller.
|
||||
Language : A pointer to a three character ISO 639-2 language
|
||||
identifier. This is the language of the controller name
|
||||
that that the caller is requesting, and it must match one
|
||||
of the languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up to the
|
||||
driver writer.
|
||||
ControllerName : A pointer to the Unicode string to return. This Unicode
|
||||
string is the name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the language specified
|
||||
by Language from the point of view of the driver specified
|
||||
by This.
|
||||
|
||||
Returns:
|
||||
EFI_SUCCESS :The Unicode string for the user readable name in the
|
||||
language specified by Language for the driver
|
||||
specified by This was returned in DriverName.
|
||||
EFI_INVALID_PARAMETER : ControllerHandle is not a valid EFI_HANDLE.
|
||||
EFI_INVALID_PARAMETER : ChildHandle is not NULL and it is not a valid EFI_HANDLE.
|
||||
EFI_INVALID_PARAMETER : Language is NULL.
|
||||
EFI_INVALID_PARAMETER : ControllerName is NULL.
|
||||
EFI_UNSUPPORTED : The driver specified by This is not currently managing
|
||||
the controller specified by ControllerHandle and
|
||||
ChildHandle.
|
||||
EFI_UNSUPPORTED :The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
--*/
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
643
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
Normal file
643
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c
Normal file
@@ -0,0 +1,643 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Driver.c
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {
|
||||
Mtftp4DriverBindingSupported,
|
||||
Mtftp4DriverBindingStart,
|
||||
Mtftp4DriverBindingStop,
|
||||
0xa,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {
|
||||
Mtftp4ServiceBindingCreateChild,
|
||||
Mtftp4ServiceBindingDestroyChild
|
||||
};
|
||||
|
||||
//@MT: EFI_DRIVER_ENTRY_POINT (Mtftp4DriverEntryPoint)
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Mtftp4DriverEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The driver entry point which installs multiple protocols to the ImageHandle.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - The MTFTP's image handle
|
||||
SystemTable - The system table
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - The handles are successfully installed on the image. Otherwise
|
||||
some EFI_ERROR.
|
||||
|
||||
--*/
|
||||
{
|
||||
return NetLibInstallAllDriverProtocols (
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
&gMtftp4DriverBinding,
|
||||
ImageHandle,
|
||||
&gMtftp4ComponentName,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Test whether MTFTP driver support this controller.
|
||||
|
||||
@param This The MTFTP driver binding instance
|
||||
@param Controller The controller to test
|
||||
@param RemainingDevicePath The remaining device path
|
||||
|
||||
@retval EFI_SUCCESS The controller has UDP service binding protocol
|
||||
installed, MTFTP can support it.
|
||||
@retval Others MTFTP can't support the controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4DriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiUdp4ServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Config a NULL UDP that is used to keep the connection between UDP
|
||||
and MTFTP. Just leave the Udp child unconfigured. When UDP is
|
||||
unloaded, MTFTP will be informed with DriverBinding Stop.
|
||||
|
||||
@param UdpIo The UDP port to configure
|
||||
@param Context The opaque parameter to the callback
|
||||
|
||||
@retval EFI_SUCCESS It always return EFI_SUCCESS directly.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ConfigNullUdp (
|
||||
IN UDP_IO_PORT *UdpIo,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create then initialize a MTFTP service binding instance.
|
||||
|
||||
@param Controller The controller to install the MTFTP service
|
||||
binding on
|
||||
@param Image The driver binding image of the MTFTP driver
|
||||
@param Service The variable to receive the created service
|
||||
binding instance.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource 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
|
||||
Mtftp4CreateService (
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_HANDLE Image,
|
||||
OUT MTFTP4_SERVICE **Service
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
EFI_STATUS Status;
|
||||
|
||||
*Service = NULL;
|
||||
MtftpSb = NetAllocatePool (sizeof (MTFTP4_SERVICE));
|
||||
|
||||
if (MtftpSb == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;
|
||||
MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
|
||||
MtftpSb->InDestory = FALSE;
|
||||
MtftpSb->ChildrenNum = 0;
|
||||
NetListInit (&MtftpSb->Children);
|
||||
|
||||
MtftpSb->Timer = NULL;
|
||||
MtftpSb->TimerToGetMap = NULL;
|
||||
MtftpSb->Controller = Controller;
|
||||
MtftpSb->Image = Image;
|
||||
MtftpSb->ConnectUdp = NULL;
|
||||
|
||||
//
|
||||
// Create the timer and a udp to be notified when UDP is uninstalled
|
||||
//
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL | EVT_TIMER,
|
||||
TPL_CALLBACK,
|
||||
Mtftp4OnTimerTick,
|
||||
MtftpSb,
|
||||
&MtftpSb->Timer
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NetFreePool (MtftpSb);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Create the timer used to time out the procedure which is used to
|
||||
// get the default IP address.
|
||||
//
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_TIMER,
|
||||
TPL_CALLBACK,
|
||||
NULL,
|
||||
NULL,
|
||||
&MtftpSb->TimerToGetMap
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
NetFreePool (MtftpSb);
|
||||
return Status;
|
||||
}
|
||||
|
||||
MtftpSb->ConnectUdp = UdpIoCreatePort (Controller, Image, Mtftp4ConfigNullUdp, NULL);
|
||||
|
||||
if (MtftpSb->ConnectUdp == NULL) {
|
||||
gBS->CloseEvent (MtftpSb->TimerToGetMap);
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
NetFreePool (MtftpSb);
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
*Service = MtftpSb;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Release all the resource used the MTFTP service binding instance.
|
||||
|
||||
@param MtftpSb The MTFTP service binding instance.
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4CleanService (
|
||||
IN MTFTP4_SERVICE *MtftpSb
|
||||
)
|
||||
{
|
||||
UdpIoFreePort (MtftpSb->ConnectUdp);
|
||||
gBS->CloseEvent (MtftpSb->TimerToGetMap);
|
||||
gBS->CloseEvent (MtftpSb->Timer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP driver on this controller. MTFTP driver will
|
||||
install a MTFTP SERVICE BINDING protocol on the supported
|
||||
controller, which can be used to create/destroy MTFTP children.
|
||||
|
||||
@param This The MTFTP driver binding protocol.
|
||||
@param Controller The controller to manage.
|
||||
@param RemainingDevicePath Remaining device path.
|
||||
|
||||
@retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
|
||||
started on the controller.
|
||||
@retval EFI_SUCCESS The MTFTP service binding is installed on the
|
||||
controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4DriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Directly return if driver is already running.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
if (Status == EFI_SUCCESS) {
|
||||
return EFI_ALREADY_STARTED;
|
||||
}
|
||||
|
||||
Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Install the Mtftp4ServiceBinding Protocol onto Controller
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Controller,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
&MtftpSb->ServiceBinding,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
Mtftp4CleanService (MtftpSb);
|
||||
NetFreePool (MtftpSb);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Stop the MTFTP driver on controller. The controller is a UDP
|
||||
child handle.
|
||||
|
||||
@param This The MTFTP driver binding protocol
|
||||
@param Controller The controller to stop
|
||||
@param NumberOfChildren The number of children
|
||||
@param ChildHandleBuffer The array of the child handle.
|
||||
|
||||
@retval EFI_SUCCESS The driver is stopped on the controller.
|
||||
@retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4DriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer
|
||||
)
|
||||
{
|
||||
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_HANDLE NicHandle;
|
||||
EFI_STATUS Status;
|
||||
EFI_TPL OldTpl;
|
||||
|
||||
//
|
||||
// MTFTP driver opens UDP child, So, Controller is a UDP
|
||||
// child handle. Locate the Nic handle first. Then get the
|
||||
// MTFTP private data back.
|
||||
//
|
||||
NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
|
||||
|
||||
if (NicHandle == NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
NicHandle,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
(VOID **) &ServiceBinding,
|
||||
This->DriverBindingHandle,
|
||||
NicHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
|
||||
|
||||
if (MtftpSb->InDestory) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
MtftpSb->InDestory = TRUE;
|
||||
|
||||
while (!NetListIsEmpty (&MtftpSb->Children)) {
|
||||
Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);
|
||||
Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
|
||||
}
|
||||
|
||||
if (MtftpSb->ChildrenNum != 0) {
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Status = gBS->UninstallProtocolInterface (
|
||||
NicHandle,
|
||||
&gEfiMtftp4ServiceBindingProtocolGuid,
|
||||
ServiceBinding
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Mtftp4CleanService (MtftpSb);
|
||||
NetFreePool (MtftpSb);
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
MtftpSb->InDestory = FALSE;
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize a MTFTP protocol instance which is the child of MtftpSb.
|
||||
|
||||
@param MtftpSb The MTFTP service binding protocol.
|
||||
@param Instance The MTFTP instance to initialize.
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4InitProtocol (
|
||||
IN MTFTP4_SERVICE *MtftpSb,
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
NetZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
|
||||
|
||||
Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
|
||||
NetListInit (&Instance->Link);
|
||||
CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (EFI_MTFTP4_PROTOCOL));
|
||||
Instance->State = MTFTP4_STATE_UNCONFIGED;
|
||||
Instance->Indestory = FALSE;
|
||||
Instance->Service = MtftpSb;
|
||||
|
||||
NetListInit (&Instance->Blocks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create a MTFTP child for the service binding instance, then
|
||||
install the MTFTP protocol to the ChildHandle.
|
||||
|
||||
@param This The MTFTP service binding instance.
|
||||
@param ChildHandle The Child handle to install the MTFTP protocol.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invalid.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
|
||||
@retval EFI_SUCCESS The child is successfully create.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ServiceBindingCreateChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN OUT EFI_HANDLE *ChildHandle
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_STATUS Status;
|
||||
EFI_TPL OldTpl;
|
||||
VOID *Udp4;
|
||||
|
||||
if ((This == NULL) || (ChildHandle == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Instance = NetAllocatePool (sizeof (*Instance));
|
||||
|
||||
if (Instance == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
|
||||
|
||||
Mtftp4InitProtocol (MtftpSb, Instance);
|
||||
|
||||
Instance->UnicastPort = UdpIoCreatePort (
|
||||
MtftpSb->Controller,
|
||||
MtftpSb->Image,
|
||||
Mtftp4ConfigNullUdp,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (Instance->UnicastPort == NULL) {
|
||||
NetFreePool (Instance);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Install the MTFTP protocol onto ChildHandle
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
&Instance->Mtftp4,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Instance->Handle = *ChildHandle;
|
||||
|
||||
//
|
||||
// Open the Udp4 protocol BY_CHILD.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
MtftpSb->ConnectUdp->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
(VOID **) &Udp4,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
Instance->Handle,
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->UninstallMultipleProtocolInterfaces (
|
||||
Instance->Handle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
&Instance->Mtftp4,
|
||||
NULL
|
||||
);
|
||||
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Add it to the parent's child list.
|
||||
//
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
|
||||
NetListInsertTail (&MtftpSb->Children, &Instance->Link);
|
||||
MtftpSb->ChildrenNum++;
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
|
||||
ON_ERROR:
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
UdpIoFreePort (Instance->UnicastPort);
|
||||
NetFreePool (Instance);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Destory one of the service binding's child.
|
||||
|
||||
@param This The service binding instance
|
||||
@param ChildHandle The child handle to destory
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invaid.
|
||||
@retval EFI_UNSUPPORTED The child may have already been destoried.
|
||||
@retval EFI_SUCCESS The child is destoried and removed from the
|
||||
parent's child list.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ServiceBindingDestroyChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ChildHandle
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_PROTOCOL *Mtftp4;
|
||||
EFI_STATUS Status;
|
||||
EFI_TPL OldTpl;
|
||||
|
||||
if ((This == NULL) || (ChildHandle == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve the private context data structures
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
(VOID **) &Mtftp4,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
|
||||
MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
|
||||
|
||||
if (Instance->Service != MtftpSb) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Instance->Indestory) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Instance->Indestory = TRUE;
|
||||
|
||||
//
|
||||
// Close the Udp4 protocol.
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
MtftpSb->ConnectUdp->UdpHandle,
|
||||
&gEfiUdp4ProtocolGuid,
|
||||
gMtftp4DriverBinding.DriverBindingHandle,
|
||||
ChildHandle
|
||||
);
|
||||
|
||||
//
|
||||
// Uninstall the MTFTP4 protocol first to enable a top down destruction.
|
||||
//
|
||||
Status = gBS->UninstallProtocolInterface (
|
||||
ChildHandle,
|
||||
&gEfiMtftp4ProtocolGuid,
|
||||
Mtftp4
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Instance->Indestory = FALSE;
|
||||
return Status;
|
||||
}
|
||||
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
|
||||
Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
|
||||
UdpIoFreePort (Instance->UnicastPort);
|
||||
|
||||
NetListRemoveEntry (&Instance->Link);
|
||||
MtftpSb->ChildrenNum--;
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
|
||||
NetFreePool (Instance);
|
||||
return EFI_SUCCESS;
|
||||
}
|
69
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.h
Normal file
69
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Driver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_MTFTP4_DRIVER_H__
|
||||
#define __EFI_MTFTP4_DRIVER_H__
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Protocol/ServiceBinding.h>
|
||||
|
||||
#include <Library/NetLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4DriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4DriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4DriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4ServiceBindingCreateChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN OUT EFI_HANDLE *ChildHandle
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4ServiceBindingDestroyChild (
|
||||
IN EFI_SERVICE_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ChildHandle
|
||||
);
|
||||
|
||||
extern EFI_COMPONENT_NAME_PROTOCOL gMtftp4ComponentName;
|
||||
extern EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding;
|
||||
|
||||
#endif
|
68
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
Normal file
68
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
Normal file
@@ -0,0 +1,68 @@
|
||||
#/** @file
|
||||
# Component name for module Mtftp4
|
||||
#
|
||||
# Copyright (c) 2007, Intel Corporation.
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#
|
||||
#**/
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = Mtftp4Dxe
|
||||
FILE_GUID = DC3641B8-2FA8-4ed3-BC1F-F9962A03454B
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
EDK_RELEASE_VERSION = 0x00020000
|
||||
EFI_SPECIFICATION_VERSION = 0x00020000
|
||||
|
||||
ENTRY_POINT = Mtftp4DriverEntryPoint
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||
#
|
||||
|
||||
[Sources.common]
|
||||
Mtftp4Option.c
|
||||
Mtftp4Rrq.c
|
||||
Mtftp4Impl.h
|
||||
ComponentName.c
|
||||
Mtftp4Support.c
|
||||
Mtftp4Impl.c
|
||||
Mtftp4Option.h
|
||||
Mtftp4Support.h
|
||||
Mtftp4Driver.h
|
||||
Mtftp4Driver.c
|
||||
Mtftp4Wrq.c
|
||||
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
UefiLib
|
||||
UefiBootServicesTableLib
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
NetLib
|
||||
UdpIoLib
|
||||
|
||||
|
||||
[Protocols]
|
||||
gEfiMtftp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||
gEfiMtftp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||
gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||
gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||
|
79
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.msa
Normal file
79
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.msa
Normal file
@@ -0,0 +1,79 @@
|
||||
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<MsaHeader>
|
||||
<ModuleName>Mtftp4Dxe</ModuleName>
|
||||
<ModuleType>DXE_DRIVER</ModuleType>
|
||||
<GuidValue>DC3641B8-2FA8-4ed3-BC1F-F9962A03454B</GuidValue>
|
||||
<Version>1.0</Version>
|
||||
<Abstract>Component name for module Mtftp4</Abstract>
|
||||
<Description>FIX ME!</Description>
|
||||
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
|
||||
<License>All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
|
||||
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
|
||||
</MsaHeader>
|
||||
<ModuleDefinitions>
|
||||
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
|
||||
<BinaryModule>false</BinaryModule>
|
||||
<OutputFileBasename>Mtftp4Dxe</OutputFileBasename>
|
||||
</ModuleDefinitions>
|
||||
<LibraryClassDefinitions>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>DebugLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>UefiDriverEntryPoint</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>UefiBootServicesTableLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>UefiLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>BaseLib</Keyword>
|
||||
</LibraryClass>
|
||||
</LibraryClassDefinitions>
|
||||
<SourceFiles>
|
||||
<Filename>Mtftp4Wrq.c</Filename>
|
||||
<Filename>Mtftp4Driver.c</Filename>
|
||||
<Filename>Mtftp4Driver.h</Filename>
|
||||
<Filename>Mtftp4Support.h</Filename>
|
||||
<Filename>Mtftp4Option.h</Filename>
|
||||
<Filename>Mtftp4Impl.c</Filename>
|
||||
<Filename>Mtftp4Support.c</Filename>
|
||||
<Filename>ComponentName.c</Filename>
|
||||
<Filename>Mtftp4Impl.h</Filename>
|
||||
<Filename>Mtftp4Rrq.c</Filename>
|
||||
<Filename>Mtftp4Option.c</Filename>
|
||||
</SourceFiles>
|
||||
<PackageDependencies>
|
||||
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
|
||||
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
|
||||
</PackageDependencies>
|
||||
<Protocols>
|
||||
<Protocol Usage="ALWAYS_CONSUMED">
|
||||
<ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
<Protocol Usage="ALWAYS_CONSUMED">
|
||||
<ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
<Protocol Usage="ALWAYS_CONSUMED">
|
||||
<ProtocolCName>gEfiMtftp4ProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
<Protocol Usage="ALWAYS_CONSUMED">
|
||||
<ProtocolCName>gEfiMtftp4ServiceBindingProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
</Protocols>
|
||||
<Externs>
|
||||
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
|
||||
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
|
||||
<Extern>
|
||||
<ModuleEntryPoint>Mtftp4DriverEntryPoint</ModuleEntryPoint>
|
||||
</Extern>
|
||||
</Externs>
|
||||
</ModuleSurfaceArea>
|
892
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Impl.c
Normal file
892
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Impl.c
Normal file
@@ -0,0 +1,892 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Impl.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Interface routine for Mtftp4
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4ReadFile (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_TOKEN *Token
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Get the current operation parameter for the MTFTP session
|
||||
|
||||
@param This The MTFTP protocol instance
|
||||
@param ModeData The MTFTP mode data
|
||||
|
||||
@retval EFI_INVALID_PARAMETER This or ModeData is NULL
|
||||
@retval EFI_SUCCESS The operation parameter is saved in ModeData
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4GetModeData (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
OUT EFI_MTFTP4_MODE_DATA *ModeData
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_TPL OldTpl;
|
||||
|
||||
if ((This == NULL) || (ModeData == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
|
||||
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
|
||||
ModeData->ConfigData = Instance->Config;
|
||||
ModeData->SupportedOptionCount = MTFTP4_SUPPORTED_OPTIONS;
|
||||
ModeData->SupportedOptoins = mMtftp4SupportedOptions;
|
||||
ModeData->UnsupportedOptionCount = 0;
|
||||
ModeData->UnsupportedOptoins = NULL;
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clean up the MTFTP session to get ready for new operation.
|
||||
|
||||
@param Instance The MTFTP session to clean up
|
||||
@param Result The result to return to the caller who initiated
|
||||
the operation.
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4CleanOperation (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_STATUS Result
|
||||
)
|
||||
{
|
||||
NET_LIST_ENTRY *Entry;
|
||||
NET_LIST_ENTRY *Next;
|
||||
MTFTP4_BLOCK_RANGE *Block;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
|
||||
//
|
||||
// Free various resources.
|
||||
//
|
||||
Token = Instance->Token;
|
||||
|
||||
if (Token != NULL) {
|
||||
Token->Status = Result;
|
||||
|
||||
if (Token->Event != NULL) {
|
||||
gBS->SignalEvent (Token->Event);
|
||||
}
|
||||
|
||||
Instance->Token = NULL;
|
||||
}
|
||||
|
||||
ASSERT (Instance->UnicastPort != NULL);
|
||||
UdpIoCleanPort (Instance->UnicastPort);
|
||||
|
||||
if (Instance->LastPacket != NULL) {
|
||||
NetbufFree (Instance->LastPacket);
|
||||
Instance->LastPacket = NULL;
|
||||
}
|
||||
|
||||
if (Instance->McastUdpPort != NULL) {
|
||||
UdpIoFreePort (Instance->McastUdpPort);
|
||||
Instance->McastUdpPort = NULL;
|
||||
}
|
||||
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->Blocks) {
|
||||
Block = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);
|
||||
NetListRemoveEntry (Entry);
|
||||
NetFreePool (Block);
|
||||
}
|
||||
|
||||
NetZeroMem (&Instance->RequestOption, sizeof (MTFTP4_OPTION));
|
||||
|
||||
Instance->Operation = 0;
|
||||
|
||||
Instance->BlkSize = MTFTP4_DEFAULT_BLKSIZE;
|
||||
Instance->LastBlock = 0;
|
||||
Instance->ServerIp = 0;
|
||||
Instance->ListeningPort = 0;
|
||||
Instance->ConnectedPort = 0;
|
||||
Instance->Gateway = 0;
|
||||
Instance->PacketToLive = 0;
|
||||
Instance->MaxRetry = 0;
|
||||
Instance->CurRetry = 0;
|
||||
Instance->Timeout = 0;
|
||||
Instance->McastIp = 0;
|
||||
Instance->McastPort = 0;
|
||||
Instance->Master = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Configure the MTFTP session for new operation or reset the current
|
||||
operation if ConfigData is NULL.
|
||||
|
||||
@param This The MTFTP session to configure
|
||||
@param ConfigData The configure parameters
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Some of the parameter is invalid.
|
||||
@retval EFI_ACCESS_DENIED There is pending operation
|
||||
@retval EFI_SUCCESS The instance is configured for operation.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4Configure (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_CONFIG_DATA *ConfigData
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_TPL OldTpl;
|
||||
IP4_ADDR Ip;
|
||||
IP4_ADDR Netmask;
|
||||
IP4_ADDR Gateway;
|
||||
IP4_ADDR ServerIp;
|
||||
|
||||
if (This == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
|
||||
|
||||
if (ConfigData == NULL) {
|
||||
//
|
||||
// Reset the operation if ConfigData is NULL
|
||||
//
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
|
||||
Mtftp4CleanOperation (Instance, EFI_ABORTED);
|
||||
NetZeroMem (&Instance->Config, sizeof (EFI_MTFTP4_CONFIG_DATA));
|
||||
Instance->State = MTFTP4_STATE_UNCONFIGED;
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
|
||||
} else {
|
||||
//
|
||||
// Configure the parameters for new operation.
|
||||
//
|
||||
NetCopyMem (&Ip, &ConfigData->StationIp, sizeof (IP4_ADDR));
|
||||
NetCopyMem (&Netmask, &ConfigData->SubnetMask, sizeof (IP4_ADDR));
|
||||
NetCopyMem (&Gateway, &ConfigData->GatewayIp, sizeof (IP4_ADDR));
|
||||
NetCopyMem (&ServerIp, &ConfigData->ServerIp, sizeof (IP4_ADDR));
|
||||
|
||||
Ip = NTOHL (Ip);
|
||||
Netmask = NTOHL (Netmask);
|
||||
Gateway = NTOHL (Gateway);
|
||||
ServerIp = NTOHL (ServerIp);
|
||||
|
||||
if (!Ip4IsUnicast (ServerIp, 0)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!ConfigData->UseDefaultSetting &&
|
||||
((!IP4_IS_VALID_NETMASK (Netmask) || !Ip4IsUnicast (Ip, Netmask)))) {
|
||||
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((Gateway != 0) &&
|
||||
(!IP4_NET_EQUAL (Gateway, Ip, Netmask) || !Ip4IsUnicast (Gateway, Netmask))) {
|
||||
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
|
||||
if ((Instance->State == MTFTP4_STATE_CONFIGED) && (Instance->Operation != 0)) {
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
Instance->Config = *ConfigData;
|
||||
Instance->State = MTFTP4_STATE_CONFIGED;
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check packet for GetInfo. GetInfo is implemented with EfiMtftp4ReadFile.
|
||||
It use Mtftp4GetInfoCheckPacket to inspect the first packet from server,
|
||||
then abort the session.
|
||||
|
||||
@param This The MTFTP4 protocol instance
|
||||
@param Token The user's token
|
||||
@param PacketLen The length of the packet
|
||||
@param Packet The received packet.
|
||||
|
||||
@retval EFI_ABORTED Abort the ReadFile operation and return.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Mtftp4GetInfoCheckPacket (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_TOKEN *Token,
|
||||
IN UINT16 PacketLen,
|
||||
IN EFI_MTFTP4_PACKET *Packet
|
||||
)
|
||||
{
|
||||
MTFTP4_GETINFO_STATE *State;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
|
||||
State = (MTFTP4_GETINFO_STATE *) Token->Context;
|
||||
OpCode = NTOHS (Packet->OpCode);
|
||||
|
||||
//
|
||||
// Set the GetInfo's return status according to the OpCode.
|
||||
//
|
||||
switch (OpCode) {
|
||||
case EFI_MTFTP4_OPCODE_ERROR:
|
||||
State->Status = EFI_TFTP_ERROR;
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_OACK:
|
||||
State->Status = EFI_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
State->Status = EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate buffer then copy the packet over. Use gBS->AllocatePool
|
||||
// in case NetAllocatePool will implements something tricky.
|
||||
//
|
||||
Status = gBS->AllocatePool (EfiBootServicesData, PacketLen, (VOID **) State->Packet);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
State->Status = EFI_OUT_OF_RESOURCES;
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
*(State->PacketLen) = PacketLen;
|
||||
NetCopyMem (*(State->Packet), Packet, PacketLen);
|
||||
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the information of the download from the server. It is implemented
|
||||
with EfiMtftp4ReadFile: build a token, then pass it to EfiMtftp4ReadFile.
|
||||
In its check packet callback abort the opertions.
|
||||
|
||||
@param This The MTFTP protocol instance
|
||||
@param OverrideData The MTFTP override data
|
||||
@param Filename The file to get information
|
||||
@param ModeStr The mode to use
|
||||
@param OptionCount The number of options to append
|
||||
@param OptionList The options to append
|
||||
@param PacketLength The variable to receive the packet length
|
||||
@param Packet The variable to receive the packet.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameter is invaid
|
||||
@retval EFI_SUCCESS The information is got
|
||||
@retval Others Failed to get the information.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4GetInfo (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_OVERRIDE_DATA *OverrideData, OPTIONAL
|
||||
IN UINT8 *Filename,
|
||||
IN UINT8 *ModeStr, OPTIONAL
|
||||
IN UINT8 OptionCount,
|
||||
IN EFI_MTFTP4_OPTION *OptionList,
|
||||
OUT UINT32 *PacketLength,
|
||||
OUT EFI_MTFTP4_PACKET **Packet OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_TOKEN Token;
|
||||
MTFTP4_GETINFO_STATE State;
|
||||
EFI_STATUS Status;
|
||||
|
||||
if ((This == NULL) || (Filename == NULL) || (PacketLength == NULL) ||
|
||||
(OptionCount && (OptionList == NULL))) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Packet != NULL) {
|
||||
*Packet = NULL;
|
||||
}
|
||||
|
||||
*PacketLength = 0;
|
||||
State.Packet = Packet;
|
||||
State.PacketLen = PacketLength;
|
||||
State.Status = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// Fill in the Token to issue an synchronous ReadFile 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 = &State;
|
||||
Token.CheckPacket = Mtftp4GetInfoCheckPacket;
|
||||
Token.TimeoutCallback = NULL;
|
||||
Token.PacketNeeded = NULL;
|
||||
|
||||
Status = EfiMtftp4ReadFile (This, &Token);
|
||||
|
||||
if (EFI_ABORTED == Status) {
|
||||
return State.Status;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the packet into an array of options. The OptionList is allocated
|
||||
by this function, and caller should free it when used.
|
||||
|
||||
@param This The MTFTP protocol instance
|
||||
@param PacketLen The length of the packet
|
||||
@param Packet The packet to parse
|
||||
@param OptionCount The size of the OptionList array allocated.
|
||||
@param OptionList The allocated option array to save the option
|
||||
addresses.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parameters are invalid.
|
||||
@retval EFI_NOT_FOUND There is no valid option in the packet
|
||||
@retval EFI_SUCCESS The packet is parsed.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4ParseOptions (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN UINT32 PacketLen,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN OUT UINT32 *OptionCount,
|
||||
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if ((This == NULL) || (PacketLen < MTFTP4_OPCODE_LEN) ||
|
||||
(Packet == NULL) || (OptionCount == NULL)) {
|
||||
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = Mtftp4ExtractOptions (Packet, PacketLen, OptionCount, OptionList);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (*OptionCount == 0) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check whether the override data is valid. It will first
|
||||
validate whether the server is a valid unicast. If a gateway
|
||||
is provided in the Override, it also check that it is a
|
||||
unicast on the connected network.
|
||||
|
||||
@param Instance The MTFTP instance
|
||||
@param Override The override data to validate.
|
||||
|
||||
@return TRUE if the override data is valid, otherwise FALSE.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
Mtftp4OverrideValid (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_OVERRIDE_DATA *Override
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_CONFIG_DATA *Config;
|
||||
IP4_ADDR Ip;
|
||||
IP4_ADDR Netmask;
|
||||
IP4_ADDR Gateway;
|
||||
|
||||
NetCopyMem (&Ip, &Override->ServerIp, sizeof (IP4_ADDR));
|
||||
if (!Ip4IsUnicast (NTOHL (Ip), 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Config = &Instance->Config;
|
||||
|
||||
NetCopyMem (&Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));
|
||||
Gateway = NTOHL (Gateway);
|
||||
|
||||
if (!Config->UseDefaultSetting && (Gateway != 0)) {
|
||||
NetCopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
|
||||
NetCopyMem (&Ip, &Config->StationIp, sizeof (IP4_ADDR));
|
||||
|
||||
Netmask = NTOHL (Netmask);
|
||||
Ip = NTOHL (Ip);
|
||||
|
||||
if (!Ip4IsUnicast (Gateway, Netmask) || !IP4_NET_EQUAL (Gateway, Ip, Netmask)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Poll the UDP to get the IP4 default address, which may be retrieved
|
||||
by DHCP. The default time out value is 5 seconds. If IP has retrieved
|
||||
the default address, the UDP is reconfigured.
|
||||
|
||||
@param Instance The Mtftp instance
|
||||
@param UdpPort The UDP port to poll
|
||||
@param UdpCfgData The UDP configure data to reconfigure the UDP
|
||||
port.
|
||||
|
||||
@return TRUE if the default address is retrieved and UDP is reconfigured.
|
||||
@return Otherwise FALSE.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
Mtftp4GetMapping (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UDP_IO_PORT *UdpPort,
|
||||
IN EFI_UDP4_CONFIG_DATA *UdpCfgData
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *Service;
|
||||
EFI_IP4_MODE_DATA Ip4Mode;
|
||||
EFI_UDP4_PROTOCOL *Udp;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Instance->Config.UseDefaultSetting);
|
||||
|
||||
Service = Instance->Service;
|
||||
Udp = UdpPort->Udp;
|
||||
|
||||
Status = gBS->SetTimer (
|
||||
Service->TimerToGetMap,
|
||||
TimerRelative,
|
||||
MTFTP4_TIME_TO_GETMAP * TICKS_PER_SECOND
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
|
||||
Udp->Poll (Udp);
|
||||
|
||||
if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&
|
||||
Ip4Mode.IsConfigured) {
|
||||
|
||||
Udp->Configure (Udp, NULL);
|
||||
return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Configure the UDP port for unicast receiving.
|
||||
|
||||
@param UdpIo The UDP port
|
||||
@param Instance The MTFTP session
|
||||
|
||||
@retval EFI_SUCCESS The UDP port is successfully configured for the
|
||||
session to unicast receive.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Mtftp4ConfigUnicastPort (
|
||||
IN UDP_IO_PORT *UdpIo,
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_CONFIG_DATA *Config;
|
||||
EFI_UDP4_CONFIG_DATA UdpConfig;
|
||||
EFI_STATUS Status;
|
||||
IP4_ADDR Ip;
|
||||
|
||||
Config = &Instance->Config;
|
||||
|
||||
UdpConfig.AcceptBroadcast = FALSE;
|
||||
UdpConfig.AcceptPromiscuous = FALSE;
|
||||
UdpConfig.AcceptAnyPort = FALSE;
|
||||
UdpConfig.AllowDuplicatePort = FALSE;
|
||||
UdpConfig.TypeOfService = 0;
|
||||
UdpConfig.TimeToLive = 64;
|
||||
UdpConfig.DoNotFragment = FALSE;
|
||||
UdpConfig.ReceiveTimeout = 0;
|
||||
UdpConfig.TransmitTimeout = 0;
|
||||
UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
|
||||
UdpConfig.StationAddress = Config->StationIp;
|
||||
UdpConfig.SubnetMask = Config->SubnetMask;
|
||||
UdpConfig.StationPort = 0;
|
||||
UdpConfig.RemotePort = 0;
|
||||
|
||||
Ip = HTONL (Instance->ServerIp);
|
||||
NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
|
||||
|
||||
Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfig);
|
||||
|
||||
if ((Status == EFI_NO_MAPPING) && Mtftp4GetMapping (Instance, UdpIo, &UdpConfig)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP session to do the operation, such as read file,
|
||||
write file, and read directory.
|
||||
|
||||
@param This The MTFTP session
|
||||
@param Token The token than encapsues the user's request.
|
||||
@param Operation The operation to do
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Some of the parameters are invalid.
|
||||
@retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
|
||||
@retval EFI_ALREADY_STARTED There is pending operation for the session.
|
||||
@retval EFI_SUCCESS The operation is successfully started.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Mtftp4Start (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_TOKEN *Token,
|
||||
IN UINT16 Operation
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_OVERRIDE_DATA *Override;
|
||||
EFI_MTFTP4_CONFIG_DATA *Config;
|
||||
EFI_TPL OldTpl;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Validate the parameters
|
||||
//
|
||||
if ((This == NULL) || (Token == NULL) || (Token->Filename == NULL) ||
|
||||
((Token->OptionCount != 0) && (Token->OptionList == NULL))) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// User must provide at least one method to collect the data for download.
|
||||
//
|
||||
if (((Operation == EFI_MTFTP4_OPCODE_RRQ) || (Operation == EFI_MTFTP4_OPCODE_DIR)) &&
|
||||
((Token->Buffer == NULL) && (Token->CheckPacket == NULL))) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// User must provide at least one method to provide the data for upload.
|
||||
//
|
||||
if ((Operation == EFI_MTFTP4_OPCODE_WRQ) &&
|
||||
((Token->Buffer == NULL) && (Token->PacketNeeded == NULL))) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
|
||||
|
||||
if (Instance->State != MTFTP4_STATE_CONFIGED) {
|
||||
Status = EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
if (Instance->Operation != 0) {
|
||||
Status = EFI_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the Operation now to prevent the application start other
|
||||
// operations.
|
||||
//
|
||||
Instance->Operation = Operation;
|
||||
Override = Token->OverrideData;
|
||||
|
||||
if ((Override != NULL) && !Mtftp4OverrideValid (Instance, Override)) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
if (Token->OptionCount != 0) {
|
||||
Status = Mtftp4ParseOption (
|
||||
Token->OptionList,
|
||||
Token->OptionCount,
|
||||
TRUE,
|
||||
&Instance->RequestOption
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Set the operation parameters from the configuration or override data.
|
||||
//
|
||||
Config = &Instance->Config;
|
||||
Instance->Token = Token;
|
||||
Instance->BlkSize = MTFTP4_DEFAULT_BLKSIZE;
|
||||
|
||||
NetCopyMem (&Instance->ServerIp, &Config->ServerIp, sizeof (IP4_ADDR));
|
||||
Instance->ServerIp = NTOHL (Instance->ServerIp);
|
||||
|
||||
Instance->ListeningPort = Config->InitialServerPort;
|
||||
Instance->ConnectedPort = 0;
|
||||
|
||||
NetCopyMem (&Instance->Gateway, &Config->GatewayIp, sizeof (IP4_ADDR));
|
||||
Instance->Gateway = NTOHL (Instance->Gateway);
|
||||
|
||||
Instance->MaxRetry = Config->TryCount;
|
||||
Instance->Timeout = Config->TimeoutValue;
|
||||
Instance->Master = TRUE;
|
||||
|
||||
if (Override != NULL) {
|
||||
NetCopyMem (&Instance->ServerIp, &Override->ServerIp, sizeof (IP4_ADDR));
|
||||
NetCopyMem (&Instance->Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));
|
||||
|
||||
Instance->ServerIp = NTOHL (Instance->ServerIp);
|
||||
Instance->Gateway = NTOHL (Instance->Gateway);
|
||||
|
||||
Instance->ListeningPort = Override->ServerPort;
|
||||
Instance->MaxRetry = Override->TryCount;
|
||||
Instance->Timeout = Override->TimeoutValue;
|
||||
}
|
||||
|
||||
if (Instance->ListeningPort == 0) {
|
||||
Instance->ListeningPort = MTFTP4_DEFAULT_SERVER_PORT;
|
||||
}
|
||||
|
||||
if (Instance->MaxRetry == 0) {
|
||||
Instance->MaxRetry = MTFTP4_DEFAULT_RETRY;
|
||||
}
|
||||
|
||||
if (Instance->Timeout == 0) {
|
||||
Instance->Timeout = MTFTP4_DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
//
|
||||
// Config the unicast UDP child to send initial request
|
||||
//
|
||||
Status = Mtftp4ConfigUnicastPort (Instance->UnicastPort, Instance);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Build and send an initial requests
|
||||
//
|
||||
if (Operation == EFI_MTFTP4_OPCODE_WRQ) {
|
||||
Status = Mtftp4WrqStart (Instance, Operation);
|
||||
} else {
|
||||
Status = Mtftp4RrqStart (Instance, Operation);
|
||||
}
|
||||
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
//
|
||||
// Return immediately for asynchronous operation or poll the
|
||||
// instance for synchronous operation.
|
||||
//
|
||||
Token->Status = EFI_NOT_READY;
|
||||
|
||||
if (Token->Event != NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
while (Token->Status == EFI_NOT_READY) {
|
||||
This->Poll (This);
|
||||
}
|
||||
|
||||
return Token->Status;
|
||||
|
||||
ON_ERROR:
|
||||
Mtftp4CleanOperation (Instance, Status);
|
||||
NET_RESTORE_TPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read a file from the server.
|
||||
|
||||
@param This The Mtftp protocol instance.
|
||||
@param Token The user's request wrap token.
|
||||
|
||||
@retval EFI_SUCCESS The ReadFile has finished, the file has been
|
||||
downloaded if it is synchronous operation,
|
||||
otherwise it has been initated.
|
||||
@retval Others Some error happened.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4ReadFile (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_TOKEN *Token
|
||||
)
|
||||
{
|
||||
return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_RRQ);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Upload a file to the server.
|
||||
|
||||
@param This The MTFTP protocol session
|
||||
@param Token The user's request wrap token.
|
||||
|
||||
@retval EFI_SUCCESS The WriteFile has finished, the file has been
|
||||
uploaded if it is synchronous operation, otherwise
|
||||
it has been initated.
|
||||
@retval Others Some error happened.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4WriteFile (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_TOKEN *Token
|
||||
)
|
||||
{
|
||||
return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_WRQ);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read a directory from the server. The only difference
|
||||
between ReadFile and ReadDirectory is the opcode used.
|
||||
|
||||
@param This The MTFTP protocol session
|
||||
@param Token The user's request wrap token.
|
||||
|
||||
@retval EFI_SUCCESS The ReadDirectory has finished, the directory has
|
||||
been downloaded as a file if it is synchronous
|
||||
operation, otherwise it has been initated.
|
||||
@retval Others Some error happened.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4ReadDirectory (
|
||||
IN EFI_MTFTP4_PROTOCOL *This,
|
||||
IN EFI_MTFTP4_TOKEN *Token
|
||||
)
|
||||
{
|
||||
return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_DIR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Poll the network stack to accelerate the packet process.
|
||||
|
||||
@param This The MTFTP protocol instance.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER This is NULL.
|
||||
@retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
|
||||
@retval EFI_DEVICE_ERROR The MTFTP session has been destoried.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiMtftp4Poll (
|
||||
IN EFI_MTFTP4_PROTOCOL *This
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_UDP4_PROTOCOL *Udp;
|
||||
|
||||
if (This == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
|
||||
|
||||
if (Instance->State == MTFTP4_STATE_UNCONFIGED) {
|
||||
return EFI_NOT_STARTED;
|
||||
} else if (Instance->State == MTFTP4_STATE_DESTORY) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
Udp = Instance->UnicastPort->Udp;
|
||||
return Udp->Poll (Udp);
|
||||
}
|
||||
|
||||
EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate = {
|
||||
EfiMtftp4GetModeData,
|
||||
EfiMtftp4Configure,
|
||||
EfiMtftp4GetInfo,
|
||||
EfiMtftp4ParseOptions,
|
||||
EfiMtftp4ReadFile,
|
||||
EfiMtftp4WriteFile,
|
||||
EfiMtftp4ReadDirectory,
|
||||
EfiMtftp4Poll
|
||||
};
|
176
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Impl.h
Normal file
176
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Impl.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Impl.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Mtftp4 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
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_MTFTP4_IMPL_H__
|
||||
#define __EFI_MTFTP4_IMPL_H__
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Protocol/Udp4.h>
|
||||
#include <Protocol/Mtftp4.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/UefiDriverEntryPoint.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/UdpIoLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
|
||||
typedef struct _MTFTP4_SERVICE MTFTP4_SERVICE;
|
||||
typedef struct _MTFTP4_PROTOCOL MTFTP4_PROTOCOL;
|
||||
|
||||
#include "Mtftp4Driver.h"
|
||||
#include "Mtftp4Option.h"
|
||||
#include "Mtftp4Support.h"
|
||||
|
||||
enum {
|
||||
MTFTP4_SERVICE_SIGNATURE = EFI_SIGNATURE_32 ('T', 'F', 'T', 'P'),
|
||||
MTFTP4_PROTOCOL_SIGNATURE = EFI_SIGNATURE_32 ('t', 'f', 't', 'p'),
|
||||
|
||||
MTFTP4_DEFAULT_SERVER_PORT = 69,
|
||||
MTFTP4_DEFAULT_TIMEOUT = 3,
|
||||
MTFTP4_DEFAULT_RETRY = 5,
|
||||
MTFTP4_DEFAULT_BLKSIZE = 512,
|
||||
MTFTP4_TIME_TO_GETMAP = 5,
|
||||
|
||||
MTFTP4_STATE_UNCONFIGED = 0,
|
||||
MTFTP4_STATE_CONFIGED,
|
||||
MTFTP4_STATE_DESTORY,
|
||||
};
|
||||
|
||||
typedef struct _MTFTP4_SERVICE {
|
||||
UINT32 Signature;
|
||||
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
|
||||
|
||||
BOOLEAN InDestory;
|
||||
|
||||
UINT16 ChildrenNum;
|
||||
NET_LIST_ENTRY Children;
|
||||
|
||||
EFI_EVENT Timer; // Ticking timer for all the MTFTP clients
|
||||
EFI_EVENT TimerToGetMap;
|
||||
|
||||
EFI_HANDLE Controller;
|
||||
EFI_HANDLE Image;
|
||||
|
||||
//
|
||||
// This UDP child is used to keep the connection between the UDP
|
||||
// and MTFTP, so MTFTP will be notified when UDP is uninstalled.
|
||||
//
|
||||
UDP_IO_PORT *ConnectUdp;
|
||||
};
|
||||
|
||||
typedef struct _MTFTP4_PROTOCOL {
|
||||
UINT32 Signature;
|
||||
NET_LIST_ENTRY Link;
|
||||
EFI_MTFTP4_PROTOCOL Mtftp4;
|
||||
|
||||
INTN State;
|
||||
BOOLEAN Indestory;
|
||||
|
||||
MTFTP4_SERVICE *Service;
|
||||
EFI_HANDLE Handle;
|
||||
|
||||
EFI_MTFTP4_CONFIG_DATA Config;
|
||||
|
||||
//
|
||||
// Operation parameters: token and requested options.
|
||||
//
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
MTFTP4_OPTION RequestOption;
|
||||
UINT16 Operation;
|
||||
|
||||
//
|
||||
// Blocks is a list of MTFTP4_BLOCK_RANGE which contains
|
||||
// holes in the file
|
||||
//
|
||||
UINT16 BlkSize;
|
||||
UINT16 LastBlock;
|
||||
NET_LIST_ENTRY Blocks;
|
||||
|
||||
//
|
||||
// The server's communication end point: IP and two ports. one for
|
||||
// initial request, one for its selected port.
|
||||
//
|
||||
IP4_ADDR ServerIp;
|
||||
UINT16 ListeningPort;
|
||||
UINT16 ConnectedPort;
|
||||
IP4_ADDR Gateway;
|
||||
UDP_IO_PORT *UnicastPort;
|
||||
|
||||
//
|
||||
// Timeout and retransmit status
|
||||
//
|
||||
NET_BUF *LastPacket;
|
||||
UINT32 PacketToLive;
|
||||
UINT32 CurRetry;
|
||||
UINT32 MaxRetry;
|
||||
UINT32 Timeout;
|
||||
|
||||
//
|
||||
// Parameter used by RRQ's multicast download.
|
||||
//
|
||||
IP4_ADDR McastIp;
|
||||
UINT16 McastPort;
|
||||
BOOLEAN Master;
|
||||
UDP_IO_PORT *McastUdpPort;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
EFI_MTFTP4_PACKET **Packet;
|
||||
UINT32 *PacketLen;
|
||||
EFI_STATUS Status;
|
||||
} MTFTP4_GETINFO_STATE;
|
||||
|
||||
VOID
|
||||
Mtftp4CleanOperation (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_STATUS Result
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4WrqStart (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 Operation
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4RrqStart (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 Operation
|
||||
);
|
||||
|
||||
#define MTFTP4_SERVICE_FROM_THIS(a) \
|
||||
CR (a, MTFTP4_SERVICE, ServiceBinding, MTFTP4_SERVICE_SIGNATURE)
|
||||
|
||||
#define MTFTP4_PROTOCOL_FROM_THIS(a) \
|
||||
CR (a, MTFTP4_PROTOCOL, Mtftp4, MTFTP4_PROTOCOL_SIGNATURE)
|
||||
|
||||
extern EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate;
|
||||
#endif
|
542
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.c
Normal file
542
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.c
Normal file
@@ -0,0 +1,542 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Option.c
|
||||
|
||||
Abstract:
|
||||
routines to process MTFTP4 options
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
UINT8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {
|
||||
"blksize",
|
||||
"timeout",
|
||||
"tsize",
|
||||
"multicast"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Go through the packet to fill the Options array with the start
|
||||
addresses of each MTFTP option name/value pair.
|
||||
|
||||
@param Packet The packet to check
|
||||
@param PacketLen The packet's length
|
||||
@param Count The size of the Options on input. The actual
|
||||
options on output
|
||||
@param Options The option array to fill in
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The packet is mal-formated
|
||||
@retval EFI_BUFFER_TOO_SMALL The Options array is too small
|
||||
@retval EFI_SUCCESS The packet has been parsed into the Options array.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Mtftp4FillOptions (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
IN OUT UINT32 *Count,
|
||||
OUT EFI_MTFTP4_OPTION *Options OPTIONAL
|
||||
)
|
||||
{
|
||||
UINT8 *Cur;
|
||||
UINT8 *Last;
|
||||
UINT8 Num;
|
||||
UINT8 *Name;
|
||||
UINT8 *Value;
|
||||
|
||||
Num = 0;
|
||||
Cur = (UINT8 *) Packet + MTFTP4_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_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Value = ++Cur;
|
||||
|
||||
while (*Cur != 0) {
|
||||
Cur++;
|
||||
}
|
||||
|
||||
Num++;
|
||||
|
||||
if ((Options != NULL) && (Num <= *Count)) {
|
||||
Options[Num - 1].OptionStr = Name;
|
||||
Options[Num - 1].ValueStr = Value;
|
||||
}
|
||||
|
||||
Cur++;
|
||||
}
|
||||
|
||||
if ((*Count < Num) || (Options == NULL)) {
|
||||
*Count = Num;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
*Count = Num;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Allocate and fill in a array of Mtftp options from the Packet. It
|
||||
first calls Mtftp4FillOption to get the option number, then allocate
|
||||
the array, at last, call Mtftp4FillOption again to save the options.
|
||||
|
||||
@param Packet The packet to parse
|
||||
@param PacketLen The length of the packet
|
||||
@param OptionCount The number of options in the packet
|
||||
@param OptionList The point to get the option array.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a
|
||||
well-formated OACK packet.
|
||||
@retval EFI_SUCCESS The option array is build
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ExtractOptions (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
IN OUT UINT32 *OptionCount,
|
||||
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
*OptionCount = 0;
|
||||
|
||||
if (OptionList != NULL) {
|
||||
*OptionList = NULL;
|
||||
}
|
||||
|
||||
if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (PacketLen == MTFTP4_OPCODE_LEN) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// The last byte must be zero to terminate the options
|
||||
//
|
||||
if (*((UINT8 *) Packet + PacketLen - 1) != 0) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the number of options
|
||||
//
|
||||
Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);
|
||||
|
||||
if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate memory for the options, then call Mtftp4FillOptions to
|
||||
// fill it if caller want that.
|
||||
//
|
||||
if (OptionList == NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
*OptionList = NetAllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));
|
||||
|
||||
if (*OptionList == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check whether two ascii strings are equel, ignore the case.
|
||||
|
||||
@param Str1 The first ascii string
|
||||
@param Str2 The second ascii string
|
||||
|
||||
@retval TRUE Two strings are equal when case is ignored.
|
||||
@retval FALSE Two string are not equal.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
NetStringEqualNoCase (
|
||||
IN UINT8 *Str1,
|
||||
IN UINT8 *Str2
|
||||
)
|
||||
{
|
||||
UINT8 Ch1;
|
||||
UINT8 Ch2;
|
||||
|
||||
ASSERT ((Str1 != NULL) && (Str2 != NULL));
|
||||
|
||||
for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {
|
||||
Ch1 = *Str1;
|
||||
Ch2 = *Str2;
|
||||
|
||||
//
|
||||
// Convert them to lower case then compare two
|
||||
//
|
||||
if (('A' <= Ch1) && (Ch1 <= 'Z')) {
|
||||
Ch1 += 'a' - 'A';
|
||||
}
|
||||
|
||||
if (('A' <= Ch2) && (Ch2 <= 'Z')) {
|
||||
Ch2 += 'a' - 'A';
|
||||
}
|
||||
|
||||
if (Ch1 != Ch2) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return (BOOLEAN) (*Str1 == *Str2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a string to a UINT32 number.
|
||||
|
||||
@param Str The string to convert from
|
||||
|
||||
@return The number get from the string
|
||||
|
||||
**/
|
||||
UINT32
|
||||
NetStringToU32 (
|
||||
IN UINT8 *Str
|
||||
)
|
||||
{
|
||||
UINT32 Num;
|
||||
|
||||
ASSERT (Str != NULL);
|
||||
|
||||
Num = 0;
|
||||
|
||||
for (; NET_IS_DIGIT (*Str); Str++) {
|
||||
Num = Num * 10 + (*Str - '0');
|
||||
}
|
||||
|
||||
return Num;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a string of the format "192.168.0.1" to an IP address.
|
||||
|
||||
@param Str The string representation of IP
|
||||
@param Ip The varible to get IP.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The IP string is invalid.
|
||||
@retval EFI_SUCCESS The IP is parsed into the Ip
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
NetStringToIp (
|
||||
IN UINT8 *Str,
|
||||
OUT IP4_ADDR *Ip
|
||||
)
|
||||
{
|
||||
UINT32 Byte;
|
||||
UINT32 Addr;
|
||||
UINTN Index;
|
||||
|
||||
*Ip = 0;
|
||||
Addr = 0;
|
||||
|
||||
for (Index = 0; Index < 4; Index++) {
|
||||
if (!NET_IS_DIGIT (*Str)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Byte = NetStringToU32 (Str);
|
||||
|
||||
if (Byte > 255) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Addr = (Addr << 8) | Byte;
|
||||
|
||||
//
|
||||
// Skip all the digitals and check whether the sepeator is the dot
|
||||
//
|
||||
while (NET_IS_DIGIT (*Str)) {
|
||||
Str++;
|
||||
}
|
||||
|
||||
if ((Index < 3) && (*Str != '.')) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Str++;
|
||||
}
|
||||
|
||||
*Ip = Addr;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the MTFTP multicast option.
|
||||
|
||||
@param Value The Mtftp multicast value string
|
||||
@param Option The option to save the info into.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The multicast value string is invalid.
|
||||
@retval EFI_SUCCESS The multicast value is parsed into the Option
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Mtftp4ExtractMcast (
|
||||
IN UINT8 *Value,
|
||||
IN MTFTP4_OPTION *Option
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 Num;
|
||||
|
||||
//
|
||||
// The multicast option is formated like "204.0.0.1,1857,1"
|
||||
// The server can also omit the ip and port, use ",,1"
|
||||
//
|
||||
if (*Value == ',') {
|
||||
Option->McastIp = 0;
|
||||
} else {
|
||||
Status = NetStringToIp (Value, &Option->McastIp);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
while (*Value && (*Value != ',')) {
|
||||
Value++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*Value != ',') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Value++;
|
||||
|
||||
//
|
||||
// Convert the port setting. the server can send us a port number or
|
||||
// empty string. such as the port in ",,1"
|
||||
//
|
||||
if (*Value == ',') {
|
||||
Option->McastPort = 0;
|
||||
} else {
|
||||
Num = NetStringToU32 (Value);
|
||||
|
||||
if (Num > 65535) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Option->McastPort = (UINT16)Num;
|
||||
|
||||
while (NET_IS_DIGIT (*Value)) {
|
||||
Value++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*Value != ',') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Value++;
|
||||
|
||||
//
|
||||
// Check the master/slave setting, 1 for master, 0 for slave.
|
||||
//
|
||||
Num = NetStringToU32 (Value);
|
||||
|
||||
if ((Num != 0) && (Num != 1)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Option->Master = (BOOLEAN)(Num == 1);
|
||||
|
||||
while (NET_IS_DIGIT (*Value)) {
|
||||
Value++;
|
||||
}
|
||||
|
||||
if (*Value != '\0') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the option in Options array to MTFTP4_OPTION which program
|
||||
can access directly.
|
||||
|
||||
@param Options The option array, which contains addresses of each
|
||||
option's name/value string.
|
||||
@param Count The number of options in the Options
|
||||
@param Request Whether this is a request or OACK. The format of
|
||||
multicast is different according to this setting.
|
||||
@param MtftpOption The MTFTP4_OPTION for easy access.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The option is mal-formated
|
||||
@retval EFI_UNSUPPORTED Some option isn't supported
|
||||
@retval EFI_SUCCESS The option are OK and has been parsed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOption (
|
||||
IN EFI_MTFTP4_OPTION *Options,
|
||||
IN UINT32 Count,
|
||||
IN BOOLEAN Request,
|
||||
OUT MTFTP4_OPTION *MtftpOption
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 Index;
|
||||
UINT32 Value;
|
||||
EFI_MTFTP4_OPTION *This;
|
||||
|
||||
MtftpOption->Exist = 0;
|
||||
|
||||
for (Index = 0; Index < Count; Index++) {
|
||||
This = Options + Index;
|
||||
|
||||
if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (NetStringEqualNoCase (This->OptionStr, "blksize")) {
|
||||
//
|
||||
// block size option, valid value is between [8, 65464]
|
||||
//
|
||||
Value = NetStringToU32 (This->ValueStr);
|
||||
|
||||
if ((Value < 8) || (Value > 65464)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
MtftpOption->BlkSize = (UINT16) Value;
|
||||
MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, "timeout")) {
|
||||
//
|
||||
// timeout option, valid value is between [1, 255]
|
||||
//
|
||||
Value = NetStringToU32 (This->ValueStr);
|
||||
|
||||
if ((Value < 1) || (Value > 255)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
MtftpOption->Timeout = (UINT8) Value;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, "tsize")) {
|
||||
//
|
||||
// tsize option, the biggest transfer supported is 4GB with block size option
|
||||
//
|
||||
MtftpOption->Tsize = NetStringToU32 (This->ValueStr);
|
||||
MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;
|
||||
|
||||
} else if (NetStringEqualNoCase (This->OptionStr, "multicast")) {
|
||||
//
|
||||
// Multicast option, if it is a request, the value must be a zero
|
||||
// length string, otherwise, it is formated like "204.0.0.1,1857,1\0"
|
||||
//
|
||||
if (Request) {
|
||||
if (*(This->ValueStr) != '\0') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
} else {
|
||||
Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
MtftpOption->Exist |= MTFTP4_MCAST_EXIST;
|
||||
|
||||
} else if (Request) {
|
||||
//
|
||||
// Ignore the unsupported option if it is a reply, and return
|
||||
// EFI_UNSUPPORTED if it's a request according to the UEFI spec.
|
||||
//
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse the options in the OACK packet to MTFTP4_OPTION which program
|
||||
can access directly.
|
||||
|
||||
@param Packet The OACK packet to parse
|
||||
@param PacketLen The length of the packet
|
||||
@param MtftpOption The MTFTP_OPTION for easy access.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER The packet option is mal-formated
|
||||
@retval EFI_UNSUPPORTED Some option isn't supported
|
||||
@retval EFI_SUCCESS The option are OK and has been parsed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOptionOack (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
OUT MTFTP4_OPTION *MtftpOption
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_OPTION *OptionList;
|
||||
EFI_STATUS Status;
|
||||
UINT32 Count;
|
||||
|
||||
MtftpOption->Exist = 0;
|
||||
|
||||
Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);
|
||||
|
||||
if (EFI_ERROR (Status) || (Count == 0)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = Mtftp4ParseOption (OptionList, Count, FALSE, MtftpOption);
|
||||
|
||||
NetFreePool (OptionList);
|
||||
return Status;
|
||||
}
|
73
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.h
Normal file
73
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Option.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Mtftp4 option process routines.
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_MTFTP4_OPTION_H__
|
||||
#define __EFI_MTFTP4_OPTION_H__
|
||||
|
||||
enum {
|
||||
MTFTP4_SUPPORTED_OPTIONS = 4,
|
||||
MTFTP4_OPCODE_LEN = 2,
|
||||
MTFTP4_ERRCODE_LEN = 2,
|
||||
MTFTP4_BLKNO_LEN = 2,
|
||||
MTFTP4_DATA_HEAD_LEN = 4,
|
||||
|
||||
MTFTP4_BLKSIZE_EXIST = 0x01,
|
||||
MTFTP4_TIMEOUT_EXIST = 0x02,
|
||||
MTFTP4_TSIZE_EXIST = 0x04,
|
||||
MTFTP4_MCAST_EXIST = 0x08,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
UINT16 BlkSize;
|
||||
UINT8 Timeout;
|
||||
UINT32 Tsize;
|
||||
IP4_ADDR McastIp;
|
||||
UINT16 McastPort;
|
||||
BOOLEAN Master;
|
||||
UINT32 Exist;
|
||||
} MTFTP4_OPTION;
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4ExtractOptions (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
IN OUT UINT32 *OptionCount,
|
||||
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOption (
|
||||
IN EFI_MTFTP4_OPTION *OptionList,
|
||||
IN UINT32 Count,
|
||||
IN BOOLEAN Request,
|
||||
OUT MTFTP4_OPTION *Option
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4ParseOptionOack (
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 PacketLen,
|
||||
OUT MTFTP4_OPTION *Option
|
||||
);
|
||||
|
||||
extern UINT8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS];
|
||||
#endif
|
735
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c
Normal file
735
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c
Normal file
@@ -0,0 +1,735 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Rrq.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Routines to process Rrq (download)
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
VOID
|
||||
Mtftp4RrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_POINTS *Points,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP session to download. It will first initialize some
|
||||
of the internal states then build and send a RRQ reqeuest packet, at
|
||||
last, it will start receive for the downloading.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
@param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
|
||||
or EFI_MTFTP4_OPCODE_DIR.
|
||||
|
||||
@retval EFI_SUCCESS The mtftp download session is started.
|
||||
@retval Others Failed to start downloading.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqStart (
|
||||
IN MTFTP4_PROTOCOL *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 = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = Mtftp4SendRequest (Instance);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build and send a ACK packet for the download session.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
@param BlkNo The BlkNo to ack.
|
||||
|
||||
@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
|
||||
Mtftp4RrqSendAck (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 BlkNo
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_PACKET *Ack;
|
||||
NET_BUF *Packet;
|
||||
|
||||
Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));
|
||||
|
||||
if (Packet == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (
|
||||
Packet,
|
||||
sizeof (EFI_MTFTP4_ACK_HEADER),
|
||||
FALSE
|
||||
);
|
||||
|
||||
Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
|
||||
Ack->Ack.Block[0] = HTONS (BlkNo);
|
||||
|
||||
return Mtftp4SendPacket (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 Instance The Mtftp session
|
||||
@param Packet The received data packet
|
||||
@param Len The packet length
|
||||
|
||||
@retval EFI_SUCCESS The data is 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
|
||||
Mtftp4RrqSaveBlock (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
EFI_STATUS Status;
|
||||
UINT16 Block;
|
||||
UINT64 Start;
|
||||
UINT32 DataLen;
|
||||
|
||||
Token = Instance->Token;
|
||||
Block = NTOHS (Packet->Data.Block);
|
||||
DataLen = Len - MTFTP4_DATA_HEAD_LEN;
|
||||
|
||||
//
|
||||
// This is the last block, save the block no
|
||||
//
|
||||
if (DataLen < Instance->BlkSize) {
|
||||
Instance->LastBlock = Block;
|
||||
Mtftp4SetLastBlockNum (&Instance->Blocks, Block);
|
||||
}
|
||||
|
||||
//
|
||||
// Remove this block number from the file hole. If Mtftp4RemoveBlockNum
|
||||
// returns EFI_NOT_FOUND, the block has been saved, don't save it again.
|
||||
//
|
||||
Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block);
|
||||
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
return EFI_SUCCESS;
|
||||
} else if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (Token->CheckPacket != NULL) {
|
||||
Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
"User aborted download"
|
||||
);
|
||||
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token->Buffer != NULL) {
|
||||
Start = MultU64x32 (Block - 1, Instance->BlkSize);
|
||||
|
||||
if (Start + DataLen <= Token->BufferSize) {
|
||||
NetCopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
|
||||
|
||||
//
|
||||
// Update the file size when received the last block
|
||||
//
|
||||
if (Instance->LastBlock == Block) {
|
||||
Token->BufferSize = Start + DataLen;
|
||||
}
|
||||
|
||||
} else if (Instance->LastBlock != 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;
|
||||
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_DISK_FULL,
|
||||
"User provided memory block is too small"
|
||||
);
|
||||
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to process the received data packets. It will save the block
|
||||
then send back an ACK if it is active.
|
||||
|
||||
@param Instance The downloading MTFTP session
|
||||
@param Packet The packet received
|
||||
@param Len The length of the packet
|
||||
@param Multicast Whether this packet is multicast or unicast
|
||||
@param Completed Return whether the download has completed
|
||||
|
||||
@retval EFI_SUCCESS The data packet is successfully processed
|
||||
@retval EFI_ABORTED The download is aborted by the user
|
||||
@retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqHandleData (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
IN BOOLEAN Multicast,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT16 BlockNum;
|
||||
INTN Expected;
|
||||
|
||||
*Completed = FALSE;
|
||||
BlockNum = NTOHS (Packet->Data.Block);
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
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->Master && (Expected != BlockNum)) {
|
||||
Mtftp4Retransmit (Instance);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the passive client's timer whenever it received a
|
||||
// valid data packet.
|
||||
//
|
||||
if (!Instance->Master) {
|
||||
Mtftp4SetTimeout (Instance);
|
||||
}
|
||||
|
||||
//
|
||||
// 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 = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
if (Instance->Master || (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->LastBlock;
|
||||
*Completed = TRUE;
|
||||
|
||||
} else {
|
||||
BlockNum = (UINT16) (Expected - 1);
|
||||
}
|
||||
|
||||
Mtftp4RrqSendAck (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 This The downloading Mtftp session
|
||||
@param Reply The options in the OACK packet
|
||||
@param Request The requested options
|
||||
|
||||
@return TRUE if the options in the OACK is OK, otherwise FALSE.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
Mtftp4RrqOackValid (
|
||||
IN MTFTP4_PROTOCOL *This,
|
||||
IN MTFTP4_OPTION *Reply,
|
||||
IN MTFTP4_OPTION *Request
|
||||
)
|
||||
{
|
||||
|
||||
//
|
||||
// It is invalid for server to return options we don't request
|
||||
//
|
||||
if ((Reply->Exist &~Request->Exist) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Server can only specify a smaller block size to be used and
|
||||
// return the timeout matches that requested.
|
||||
//
|
||||
if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||
|
||||
((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->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 ((Reply->Exist & MTFTP4_MCAST_EXIST) && (This->McastIp != 0)) {
|
||||
if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Configure a UDP IO port to receive the multicast.
|
||||
|
||||
@param McastIo The UDP IO port to configure
|
||||
@param Context The opaque parameter to the function which is the
|
||||
MTFTP session.
|
||||
|
||||
@retval EFI_SUCCESS The udp child is successfully configured.
|
||||
@retval Others Failed to configure the UDP child.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Mtftp4RrqConfigMcastPort (
|
||||
IN UDP_IO_PORT *McastIo,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_CONFIG_DATA *Config;
|
||||
EFI_UDP4_CONFIG_DATA UdpConfig;
|
||||
EFI_IPv4_ADDRESS Group;
|
||||
EFI_STATUS Status;
|
||||
IP4_ADDR Ip;
|
||||
|
||||
Instance = (MTFTP4_PROTOCOL *) Context;
|
||||
Config = &Instance->Config;
|
||||
|
||||
UdpConfig.AcceptBroadcast = FALSE;
|
||||
UdpConfig.AcceptPromiscuous = FALSE;
|
||||
UdpConfig.AcceptAnyPort = FALSE;
|
||||
UdpConfig.AllowDuplicatePort = FALSE;
|
||||
UdpConfig.TypeOfService = 0;
|
||||
UdpConfig.TimeToLive = 64;
|
||||
UdpConfig.DoNotFragment = FALSE;
|
||||
UdpConfig.ReceiveTimeout = 0;
|
||||
UdpConfig.TransmitTimeout = 0;
|
||||
UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
|
||||
UdpConfig.StationAddress = Config->StationIp;
|
||||
UdpConfig.SubnetMask = Config->SubnetMask;
|
||||
UdpConfig.StationPort = Instance->McastPort;
|
||||
UdpConfig.RemotePort = 0;
|
||||
|
||||
Ip = HTONL (Instance->ServerIp);
|
||||
NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
|
||||
|
||||
Status = McastIo->Udp->Configure (McastIo->Udp, &UdpConfig);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// join the multicast group
|
||||
//
|
||||
Ip = HTONL (Instance->McastIp);
|
||||
NetCopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));
|
||||
|
||||
return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to process the OACK. It will first validate the OACK
|
||||
packet, then update the various negotiated parameters.
|
||||
|
||||
@param Instance The download MTFTP session
|
||||
@param Packet The packet received
|
||||
@param Len The packet length
|
||||
@param Multicast Whether this packet is received as a multicast
|
||||
@param Completed Returns whether the download has completed. NOT
|
||||
used by this function.
|
||||
|
||||
@retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
|
||||
@retval EFI_TFTP_ERROR Some error happened during the process
|
||||
@retval EFI_SUCCESS The OACK is successfully processed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RrqHandleOack (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
IN BOOLEAN Multicast,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
MTFTP4_OPTION Reply;
|
||||
EFI_STATUS Status;
|
||||
INTN Expected;
|
||||
|
||||
*Completed = FALSE;
|
||||
|
||||
//
|
||||
// If already started the master download, don't change the
|
||||
// setting. Master download always succeeds.
|
||||
//
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
ASSERT (Expected != -1);
|
||||
|
||||
if (Instance->Master && (Expected != 1)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse and validate the options from server
|
||||
//
|
||||
NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));
|
||||
|
||||
Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);
|
||||
|
||||
if (EFI_ERROR (Status) ||
|
||||
!Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {
|
||||
//
|
||||
// Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
|
||||
//
|
||||
if (Status != EFI_OUT_OF_RESOURCES) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
"Mal-formated OACK packet"
|
||||
);
|
||||
}
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
|
||||
if (Reply.Exist & MTFTP4_MCAST_EXIST) {
|
||||
|
||||
//
|
||||
// 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->Master = Reply.Master;
|
||||
|
||||
if (Instance->McastIp == 0) {
|
||||
if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
"Illegal multicast setting"
|
||||
);
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a UDP child then start receive the multicast from it.
|
||||
//
|
||||
Instance->McastIp = Reply.McastIp;
|
||||
Instance->McastPort = Reply.McastPort;
|
||||
Instance->McastUdpPort = UdpIoCreatePort (
|
||||
Instance->Service->Controller,
|
||||
Instance->Service->Image,
|
||||
Mtftp4RrqConfigMcastPort,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (Instance->McastUdpPort == NULL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,
|
||||
"Failed to create socket to receive multicast packet"
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the parameters used.
|
||||
//
|
||||
if (Reply.BlkSize != 0) {
|
||||
Instance->BlkSize = Reply.BlkSize;
|
||||
}
|
||||
|
||||
if (Reply.Timeout != 0) {
|
||||
Instance->Timeout = Reply.Timeout;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Instance->Master = TRUE;
|
||||
|
||||
if (Reply.BlkSize != 0) {
|
||||
Instance->BlkSize = Reply.BlkSize;
|
||||
}
|
||||
|
||||
if (Reply.Timeout != 0) {
|
||||
Instance->Timeout = Reply.Timeout;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Send an ACK to (Expected - 1) which is 0 for unicast download,
|
||||
// or tell the server we want to receive the Expected block.
|
||||
//
|
||||
return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The packet process callback for MTFTP download.
|
||||
|
||||
@param UdpPacket The packet received
|
||||
@param Points The local/remote access point of the packet
|
||||
@param IoStatus The status of the receiving
|
||||
@param Context Opaque parameter, which is the MTFTP session
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4RrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_POINTS *Points,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
BOOLEAN Completed;
|
||||
BOOLEAN Multicast;
|
||||
EFI_STATUS Status;
|
||||
UINT16 Opcode;
|
||||
UINT32 Len;
|
||||
|
||||
Instance = (MTFTP4_PROTOCOL *) Context;
|
||||
NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
Packet = NULL;
|
||||
Completed = FALSE;
|
||||
Multicast = FALSE;
|
||||
|
||||
if (EFI_ERROR (IoStatus)) {
|
||||
Status = IoStatus;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ASSERT (UdpPacket != NULL);
|
||||
|
||||
//
|
||||
// Find the port this packet is from to restart receive correctly.
|
||||
//
|
||||
Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);
|
||||
|
||||
if (UdpPacket->TotalSize < MTFTP4_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. The server
|
||||
// is required to use the same port as RemotePort to multicast the
|
||||
// data.
|
||||
//
|
||||
if (Points->RemotePort != Instance->ConnectedPort) {
|
||||
if (Instance->ConnectedPort != 0) {
|
||||
goto ON_EXIT;
|
||||
} else {
|
||||
Instance->ConnectedPort = Points->RemotePort;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the MTFTP packet to a continuous buffer if it isn't already so.
|
||||
//
|
||||
Len = UdpPacket->TotalSize;
|
||||
|
||||
if (UdpPacket->BlockOpNum > 1) {
|
||||
Packet = NetAllocatePool (Len);
|
||||
|
||||
if (Packet == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
|
||||
|
||||
} else {
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
|
||||
}
|
||||
|
||||
Opcode = NTOHS (Packet->OpCode);
|
||||
|
||||
//
|
||||
// Call the user's CheckPacket if provided. Abort the transmission
|
||||
// if CheckPacket returns an EFI_ERROR code.
|
||||
//
|
||||
if ((Instance->Token->CheckPacket != NULL) &&
|
||||
((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
|
||||
|
||||
Status = Instance->Token->CheckPacket (
|
||||
&Instance->Mtftp4,
|
||||
Instance->Token,
|
||||
(UINT16) Len,
|
||||
Packet
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Send an error message to the server to inform it
|
||||
//
|
||||
if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
"User aborted the transfer"
|
||||
);
|
||||
}
|
||||
|
||||
Status = EFI_ABORTED;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Opcode) {
|
||||
case EFI_MTFTP4_OPCODE_DATA:
|
||||
if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||
|
||||
(Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_OACK:
|
||||
if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_ERROR:
|
||||
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) && (UdpPacket->BlockOpNum > 1)) {
|
||||
NetFreePool (Packet);
|
||||
}
|
||||
|
||||
if (UdpPacket != NULL) {
|
||||
NetbufFree (UdpPacket);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status) && !Completed) {
|
||||
if (Multicast) {
|
||||
Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
|
||||
} else {
|
||||
Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status) || Completed) {
|
||||
Mtftp4CleanOperation (Instance, Status);
|
||||
}
|
||||
}
|
591
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
Normal file
591
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
Normal file
@@ -0,0 +1,591 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Support.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Support routines for Mtftp
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
|
||||
/**
|
||||
Allocate a MTFTP4 block range, then init it to the
|
||||
range of [Start, End]
|
||||
|
||||
@param Start The start block number
|
||||
@param End The last block number in the range
|
||||
|
||||
@return NULL if failed to allocate memory, otherwise the created block range.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
MTFTP4_BLOCK_RANGE *
|
||||
Mtftp4AllocateRange (
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
Range = NetAllocatePool (sizeof (MTFTP4_BLOCK_RANGE));
|
||||
|
||||
if (Range == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetListInit (&Range->Link);
|
||||
Range->Start = Start;
|
||||
Range->End = End;
|
||||
|
||||
return Range;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the block range for either RRQ or WRQ. RRQ and WRQ have
|
||||
different requirements for Start and End. For example, during start
|
||||
up, WRQ initializes its whole valid block range to [0, 0xffff]. This
|
||||
is bacause the server will send us a ACK0 to inform us to start the
|
||||
upload. When the client received 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 received BLOCK1, the client will
|
||||
remove it from the block range and send an ACK. It also works if there
|
||||
is option negotiation.
|
||||
|
||||
@param Head The block range head to initialize
|
||||
@param Start The Start block number.
|
||||
@param 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
|
||||
Mtftp4InitBlockRange (
|
||||
IN NET_LIST_ENTRY *Head,
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
Range = Mtftp4AllocateRange (Start, End);
|
||||
|
||||
if (Range == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
NetListInsertTail (Head, &Range->Link);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the first valid block number on the range list.
|
||||
|
||||
@param Head The block range head
|
||||
|
||||
@return -1: if the block range is empty. Otherwise the first valid block number.
|
||||
|
||||
**/
|
||||
INTN
|
||||
Mtftp4GetNextBlockNum (
|
||||
IN NET_LIST_ENTRY *Head
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
if (NetListIsEmpty (Head)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);
|
||||
return Range->Start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the last block number of the block range list. It will
|
||||
remove 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 will call
|
||||
this function to set the last block number.
|
||||
|
||||
@param Head The block range list
|
||||
@param Last The last block number
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetLastBlockNum (
|
||||
IN NET_LIST_ENTRY *Head,
|
||||
IN UINT16 Last
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
//
|
||||
// Iterate from the tail to head to remove the block number
|
||||
// after the last.
|
||||
//
|
||||
while (!NetListIsEmpty (Head)) {
|
||||
Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);
|
||||
|
||||
if (Range->Start > Last) {
|
||||
NetListRemoveEntry (&Range->Link);
|
||||
NetFreePool (Range);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Range->End > Last) {
|
||||
Range->End = Last;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove the block number from the block range list.
|
||||
|
||||
@param Head The block range list to remove from
|
||||
@param Num The block number to remove
|
||||
|
||||
@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 resource
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4RemoveBlockNum (
|
||||
IN NET_LIST_ENTRY *Head,
|
||||
IN UINT16 Num
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
MTFTP4_BLOCK_RANGE *NewRange;
|
||||
NET_LIST_ENTRY *Entry;
|
||||
|
||||
NET_LIST_FOR_EACH (Entry, Head) {
|
||||
|
||||
//
|
||||
// Each block represents a hole [Start, End] in the file,
|
||||
// skip to the first range with End >= Num
|
||||
//
|
||||
Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);
|
||||
|
||||
if (Range->End < Num) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// There are three different cases for Start
|
||||
// 1. (Start > Num) && (End >= Num):
|
||||
// because all the holes before this one has the condition of
|
||||
// End < Num, so this block number has been removed.
|
||||
//
|
||||
// 2. (Start == Num) && (End >= Num):
|
||||
// Need to increase the Start by one, and if End == Num, this
|
||||
// hole has been removed completely, remove it.
|
||||
//
|
||||
// 3. (Start < Num) && (End >= Num):
|
||||
// if End == Num, only need to decrease the End by one because
|
||||
// we have (Start < Num) && (Num == End), so (Start <= End - 1).
|
||||
// if (End > Num), the hold is splited into two holes, with
|
||||
// [Start, Num - 1] and [Num + 1, End].
|
||||
//
|
||||
if (Range->Start > Num) {
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
} else if (Range->Start == Num) {
|
||||
Range->Start++;
|
||||
|
||||
if (Range->Start > Range->End) {
|
||||
NetListRemoveEntry (&Range->Link);
|
||||
NetFreePool (Range);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
if (Range->End == Num) {
|
||||
Range->End--;
|
||||
} else {
|
||||
NewRange = Mtftp4AllocateRange (Num + 1, (UINT16) Range->End);
|
||||
|
||||
if (NewRange == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Range->End = Num - 1;
|
||||
NetListInsertAfter (&Range->Link, &NewRange->Link);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build then transmit the request packet for the MTFTP session.
|
||||
|
||||
@param Instance The Mtftp session
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request
|
||||
@retval EFI_SUCCESS The request is built and sent
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendRequest (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
EFI_MTFTP4_OPTION *Options;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
NET_BUF *Nbuf;
|
||||
UINT8 *Mode;
|
||||
UINT8 *Cur;
|
||||
UINT32 Len;
|
||||
UINTN Index;
|
||||
|
||||
Token = Instance->Token;
|
||||
Options = Token->OptionList;
|
||||
Mode = Instance->Token->ModeStr;
|
||||
|
||||
if (Mode == NULL) {
|
||||
Mode = "octet";
|
||||
}
|
||||
|
||||
//
|
||||
// Compute the packet length
|
||||
//
|
||||
Len = (UINT32) (AsciiStrLen (Token->Filename) + AsciiStrLen (Mode) + 4);
|
||||
|
||||
for (Index = 0; Index < Token->OptionCount; Index++) {
|
||||
Len += (UINT32) (AsciiStrLen (Options[Index].OptionStr) +
|
||||
AsciiStrLen (Options[Index].ValueStr) + 2);
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate a packet then copy the data over
|
||||
//
|
||||
if ((Nbuf = NetbufAlloc (Len)) == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
|
||||
Packet->OpCode = HTONS (Instance->Operation);
|
||||
Cur = Packet->Rrq.Filename;
|
||||
Cur = AsciiStrCpy (Cur, Token->Filename);
|
||||
Cur = AsciiStrCpy (Cur, Mode);
|
||||
|
||||
for (Index = 0; Index < Token->OptionCount; ++Index) {
|
||||
Cur = AsciiStrCpy (Cur, Options[Index].OptionStr);
|
||||
Cur = AsciiStrCpy (Cur, Options[Index].ValueStr);
|
||||
}
|
||||
|
||||
return Mtftp4SendPacket (Instance, Nbuf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build then send an error message
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param ErrInfo The error code and message
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet
|
||||
@retval EFI_SUCCESS The error packet is transmitted.
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendError (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 ErrCode,
|
||||
IN UINT8* ErrInfo
|
||||
)
|
||||
{
|
||||
NET_BUF *Packet;
|
||||
EFI_MTFTP4_PACKET *TftpError;
|
||||
UINT32 Len;
|
||||
|
||||
Len = (UINT32) (AsciiStrLen (ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));
|
||||
Packet = NetbufAlloc (Len);
|
||||
|
||||
if (Packet == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);
|
||||
TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);
|
||||
TftpError->Error.ErrorCode = HTONS (ErrCode);
|
||||
|
||||
AsciiStrCpy (TftpError->Error.ErrorMessage, ErrInfo);
|
||||
|
||||
return Mtftp4SendPacket (Instance, Packet);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The callback function called when the packet is transmitted.
|
||||
It simply frees the packet.
|
||||
|
||||
@param Packet The transmitted (or failed to) packet
|
||||
@param Points The local and remote UDP access point
|
||||
@param IoStatus The result of the transmission
|
||||
@param Context Opaque parameter to the callback
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
Mtftp4OnPacketSent (
|
||||
NET_BUF *Packet,
|
||||
UDP_POINTS *Points,
|
||||
EFI_STATUS IoStatus,
|
||||
VOID *Context
|
||||
)
|
||||
{
|
||||
NetbufFree (Packet);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the timeout for the instance. User a longer time for
|
||||
passive instances.
|
||||
|
||||
@param Instance The Mtftp session to set time out
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetTimeout (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
if (Instance->Master) {
|
||||
Instance->PacketToLive = Instance->Timeout;
|
||||
} else {
|
||||
Instance->PacketToLive = Instance->Timeout * 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Send the packet for the instance. It will first save a reference to
|
||||
the packet for later retransmission. then determine the destination
|
||||
port, listen port for requests, and connected port for others. At last,
|
||||
send the packet out.
|
||||
|
||||
@param Instance The Mtftp instance
|
||||
@param Packet The packet to send
|
||||
|
||||
@retval EFI_SUCCESS The packet is sent out
|
||||
@retval Others Failed to transmit the packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4SendPacket (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN NET_BUF *Packet
|
||||
)
|
||||
{
|
||||
UDP_POINTS UdpPoint;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
|
||||
//
|
||||
// Save the packet for retransmission
|
||||
//
|
||||
if (Instance->LastPacket != NULL) {
|
||||
NetbufFree (Instance->LastPacket);
|
||||
}
|
||||
|
||||
Instance->LastPacket = Packet;
|
||||
|
||||
Instance->CurRetry = 0;
|
||||
Mtftp4SetTimeout (Instance);
|
||||
|
||||
UdpPoint.LocalAddr = 0;
|
||||
UdpPoint.LocalPort = 0;
|
||||
UdpPoint.RemoteAddr = Instance->ServerIp;
|
||||
|
||||
//
|
||||
// Send the requests to the listening port, other packets
|
||||
// to the connected port
|
||||
//
|
||||
OpCode = NTOHS (*((UINT16 *) NetbufGetByte (Packet, 0, NULL)));
|
||||
|
||||
if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
|
||||
(OpCode == EFI_MTFTP4_OPCODE_WRQ)) {
|
||||
UdpPoint.RemotePort = Instance->ListeningPort;
|
||||
} else {
|
||||
UdpPoint.RemotePort = Instance->ConnectedPort;
|
||||
}
|
||||
|
||||
NET_GET_REF (Packet);
|
||||
|
||||
Status = UdpIoSendDatagram (
|
||||
Instance->UnicastPort,
|
||||
Packet,
|
||||
&UdpPoint,
|
||||
Instance->Gateway,
|
||||
Mtftp4OnPacketSent,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NET_PUT_REF (Packet);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Retransmit the last packet for the instance
|
||||
|
||||
@param Instance The Mtftp instance
|
||||
|
||||
@retval EFI_SUCCESS The last packet is retransmitted.
|
||||
@retval Others Failed to retransmit.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4Retransmit (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
)
|
||||
{
|
||||
UDP_POINTS UdpPoint;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
|
||||
ASSERT (Instance->LastPacket != NULL);
|
||||
|
||||
UdpPoint.LocalAddr = 0;
|
||||
UdpPoint.LocalPort = 0;
|
||||
UdpPoint.RemoteAddr = Instance->ServerIp;
|
||||
|
||||
//
|
||||
// Set the requests to the listening port, other packets to the connected port
|
||||
//
|
||||
OpCode = NTOHS (*(UINT16 *) NetbufGetByte (Instance->LastPacket, 0, NULL));
|
||||
|
||||
if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
|
||||
(OpCode == EFI_MTFTP4_OPCODE_WRQ)) {
|
||||
UdpPoint.RemotePort = Instance->ListeningPort;
|
||||
} else {
|
||||
UdpPoint.RemotePort = Instance->ConnectedPort;
|
||||
}
|
||||
|
||||
NET_GET_REF (Instance->LastPacket);
|
||||
|
||||
Status = UdpIoSendDatagram (
|
||||
Instance->UnicastPort,
|
||||
Instance->LastPacket,
|
||||
&UdpPoint,
|
||||
Instance->Gateway,
|
||||
Mtftp4OnPacketSent,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NET_PUT_REF (Instance->LastPacket);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The timer ticking function for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTick (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
NET_LIST_ENTRY *Entry;
|
||||
NET_LIST_ENTRY *Next;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
|
||||
MtftpSb = (MTFTP4_SERVICE *) Context;
|
||||
|
||||
//
|
||||
// Iterate through all the children of the Mtftp service instance. Time
|
||||
// out the packet. If maximum retries reached, clean the session up.
|
||||
//
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
|
||||
Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
|
||||
|
||||
if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Call the user's time out handler
|
||||
//
|
||||
Token = Instance->Token;
|
||||
|
||||
if ((Token->TimeoutCallback != NULL) &&
|
||||
EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {
|
||||
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
"User aborted the transfer in time out"
|
||||
);
|
||||
|
||||
Mtftp4CleanOperation (Instance, EFI_ABORTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Retransmit the packet if haven't reach the maxmium retry count,
|
||||
// otherwise exit the transfer.
|
||||
//
|
||||
if (++Instance->CurRetry < Instance->MaxRetry) {
|
||||
Mtftp4Retransmit (Instance);
|
||||
Mtftp4SetTimeout (Instance);
|
||||
} else {
|
||||
Mtftp4CleanOperation (Instance, EFI_TIMEOUT);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
96
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.h
Normal file
96
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Support.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Support routines for MTFTP
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __EFI_MTFTP4_SUPPORT_H__
|
||||
#define __EFI_MTFTP4_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 {
|
||||
NET_LIST_ENTRY Link;
|
||||
INTN Start;
|
||||
INTN End;
|
||||
} MTFTP4_BLOCK_RANGE;
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4InitBlockRange (
|
||||
IN NET_LIST_ENTRY *Head,
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
);
|
||||
|
||||
INTN
|
||||
Mtftp4GetNextBlockNum (
|
||||
IN NET_LIST_ENTRY *Head
|
||||
);
|
||||
|
||||
VOID
|
||||
Mtftp4SetLastBlockNum (
|
||||
IN NET_LIST_ENTRY *Head,
|
||||
IN UINT16 Last
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4RemoveBlockNum (
|
||||
IN NET_LIST_ENTRY *Head,
|
||||
IN UINT16 Num
|
||||
);
|
||||
|
||||
VOID
|
||||
Mtftp4SetTimeout (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4SendPacket (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN NET_BUF *Packet
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4SendRequest (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4SendError (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 ErrCode,
|
||||
IN UINT8* ErrInfo
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
Mtftp4Retransmit (
|
||||
IN MTFTP4_PROTOCOL *Instance
|
||||
);
|
||||
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTick (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
);
|
||||
#endif
|
522
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Wrq.c
Normal file
522
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Wrq.c
Normal file
@@ -0,0 +1,522 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2006, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Mtftp4Wrq.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Routines to process Wrq (upload)
|
||||
|
||||
|
||||
**/
|
||||
|
||||
#include "Mtftp4Impl.h"
|
||||
|
||||
VOID
|
||||
Mtftp4WrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_POINTS *Points,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Start the MTFTP session for pload. It will first init some states,
|
||||
then send the WRQ request packet, and start receiving the packet.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param Operation Redundant parameter, which is always
|
||||
EFI_MTFTP4_OPCODE_WRQ here.
|
||||
|
||||
@retval EFI_SUCCESS The upload process has been started.
|
||||
@retval Others Failed to start the upload.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqStart (
|
||||
IN MTFTP4_PROTOCOL *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 = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = Mtftp4SendRequest (Instance);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build then send a MTFTP data packet for the MTFTP upload session.
|
||||
|
||||
@param Instance The MTFTP upload session
|
||||
@param BlockNum The block number to send
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to build the packet
|
||||
@retval EFI_ABORTED The consumer of this child directs to abort the
|
||||
transmission by return an error through
|
||||
PacketNeeded
|
||||
@retval EFI_SUCCESS The data is sent.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqSendBlock (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN UINT16 BlockNum
|
||||
)
|
||||
{
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
NET_BUF *UdpPacket;
|
||||
EFI_STATUS Status;
|
||||
UINT16 DataLen;
|
||||
UINT8 *DataBuf;
|
||||
UINT64 Start;
|
||||
|
||||
//
|
||||
// Allocate a buffer to hold the user data
|
||||
//
|
||||
UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP4_DATA_HEAD_LEN);
|
||||
|
||||
if (UdpPacket == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Packet = (EFI_MTFTP4_PACKET *)NetbufAllocSpace (UdpPacket, MTFTP4_DATA_HEAD_LEN, FALSE);
|
||||
|
||||
Packet->Data.OpCode = HTONS (EFI_MTFTP4_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->LastBlock = BlockNum;
|
||||
Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);
|
||||
}
|
||||
|
||||
if (DataLen > 0) {
|
||||
NetbufAllocSpace (UdpPacket, DataLen, FALSE);
|
||||
NetCopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);
|
||||
}
|
||||
|
||||
} else {
|
||||
//
|
||||
// Get data from PacketNeeded
|
||||
//
|
||||
DataBuf = NULL;
|
||||
Status = Token->PacketNeeded (&Instance->Mtftp4, Token, &DataLen, &DataBuf);
|
||||
|
||||
if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
|
||||
if (DataBuf != NULL) {
|
||||
gBS->FreePool (DataBuf);
|
||||
}
|
||||
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
"User aborted the transfer"
|
||||
);
|
||||
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
if (DataLen < Instance->BlkSize) {
|
||||
Instance->LastBlock = BlockNum;
|
||||
Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);
|
||||
}
|
||||
|
||||
if (DataLen > 0) {
|
||||
NetbufAllocSpace (UdpPacket, DataLen, FALSE);
|
||||
NetCopyMem (Packet->Data.Data, DataBuf, DataLen);
|
||||
gBS->FreePool (DataBuf);
|
||||
}
|
||||
}
|
||||
|
||||
return Mtftp4SendPacket (Instance, UdpPacket);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to handle received ACK packet. If the ACK number matches the
|
||||
expected block number, and there are more data pending, send the next
|
||||
block. Otherwise tell the caller that we are done.
|
||||
|
||||
@param Instance The MTFTP upload session
|
||||
@param Packet The MTFTP packet received
|
||||
@param Len The packet length
|
||||
@param Completed Return whether the upload has finished.
|
||||
|
||||
@retval EFI_SUCCESS The ACK is successfully processed.
|
||||
@retval EFI_TFTP_ERROR The block number loops back.
|
||||
@retval Others Failed to transmit the next data packet.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqHandleAck (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
UINT16 AckNum;
|
||||
INTN Expected;
|
||||
|
||||
*Completed = FALSE;
|
||||
AckNum = NTOHS (Packet->Ack.Block[0]);
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
ASSERT (Expected >= 0);
|
||||
|
||||
//
|
||||
// Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
|
||||
// restart receive.
|
||||
//
|
||||
if (Expected != AckNum) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove the acked block number, if this is the last block number,
|
||||
// tell the Mtftp4WrqInput to finish the transfer. This is the last
|
||||
// block number if the block range are empty..
|
||||
//
|
||||
Mtftp4RemoveBlockNum (&Instance->Blocks, AckNum);
|
||||
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
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->LastBlock == AckNum) {
|
||||
ASSERT (Instance->LastBlock >= 1);
|
||||
*Completed = TRUE;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
"Block number rolls back, not supported, try blksize option"
|
||||
);
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return Mtftp4WrqSendBlock (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 MTFTP options as required.s
|
||||
|
||||
@param Reply The options included in the OACK
|
||||
@param Request The options we requested
|
||||
|
||||
@return TRUE if the options included in OACK is valid, otherwise FALSE.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
Mtftp4WrqOackValid (
|
||||
IN MTFTP4_OPTION *Reply,
|
||||
IN MTFTP4_OPTION *Request
|
||||
)
|
||||
{
|
||||
//
|
||||
// It is invalid for server to return options we don't request
|
||||
//
|
||||
if ((Reply->Exist &~Request->Exist) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Server can only specify a smaller block size to be used and
|
||||
// return the timeout matches that requested.
|
||||
//
|
||||
if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||
|
||||
((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Function to handle the MTFTP OACK packet. It parses the packet's
|
||||
options, and update the internal states of the session
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param Packet The received OACK packet
|
||||
@param Len The length of the packet
|
||||
@param Completed Whether the transmisson has completed. NOT used by
|
||||
this function.
|
||||
|
||||
@retval EFI_SUCCESS The OACK process is OK
|
||||
@retval EFI_TFTP_ERROR Some error occured, and the session reset.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Mtftp4WrqHandleOack (
|
||||
IN MTFTP4_PROTOCOL *Instance,
|
||||
IN EFI_MTFTP4_PACKET *Packet,
|
||||
IN UINT32 Len,
|
||||
OUT BOOLEAN *Completed
|
||||
)
|
||||
{
|
||||
MTFTP4_OPTION Reply;
|
||||
EFI_MTFTP4_PACKET Bogus;
|
||||
EFI_STATUS Status;
|
||||
INTN Expected;
|
||||
|
||||
*Completed = FALSE;
|
||||
|
||||
//
|
||||
// Ignore the OACK if already started the upload
|
||||
//
|
||||
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
|
||||
|
||||
if (Expected != 0) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse and validate the options from server
|
||||
//
|
||||
NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));
|
||||
Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);
|
||||
|
||||
if (EFI_ERROR (Status) || !Mtftp4WrqOackValid (&Reply, &Instance->RequestOption)) {
|
||||
//
|
||||
// Don't send a MTFTP error packet when out of resource, it can
|
||||
// only make it worse.
|
||||
//
|
||||
if (Status != EFI_OUT_OF_RESOURCES) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
|
||||
"Mal-formated OACK packet"
|
||||
);
|
||||
}
|
||||
|
||||
return EFI_TFTP_ERROR;
|
||||
}
|
||||
|
||||
if (Reply.BlkSize != 0) {
|
||||
Instance->BlkSize = Reply.BlkSize;
|
||||
}
|
||||
|
||||
if (Reply.Timeout != 0) {
|
||||
Instance->Timeout = Reply.Timeout;
|
||||
}
|
||||
|
||||
//
|
||||
// Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
|
||||
// which will start the transmission of the first data block.
|
||||
//
|
||||
Bogus.Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
|
||||
Bogus.Ack.Block[0] = 0;
|
||||
|
||||
return Mtftp4WrqHandleAck (Instance, &Bogus, sizeof (EFI_MTFTP4_ACK_HEADER), Completed);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The input process routine for MTFTP upload.
|
||||
|
||||
@param UdpPacket The received MTFTP packet.
|
||||
@param Points The local/remote access point
|
||||
@param IoStatus The result of the packet receiving
|
||||
@param Context Opaque parameter for the callback, which is the
|
||||
MTFTP session.
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4WrqInput (
|
||||
IN NET_BUF *UdpPacket,
|
||||
IN UDP_POINTS *Points,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_PACKET *Packet;
|
||||
BOOLEAN Completed;
|
||||
EFI_STATUS Status;
|
||||
UINT32 Len;
|
||||
UINT16 Opcode;
|
||||
|
||||
Instance = (MTFTP4_PROTOCOL *) Context;
|
||||
NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
|
||||
|
||||
Completed = FALSE;
|
||||
Packet = NULL;
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
if (EFI_ERROR (IoStatus)) {
|
||||
Status = IoStatus;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ASSERT (UdpPacket != NULL);
|
||||
|
||||
if (UdpPacket->TotalSize < MTFTP4_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 (Points->RemotePort != Instance->ConnectedPort) {
|
||||
if (Instance->ConnectedPort != 0) {
|
||||
goto ON_EXIT;
|
||||
} else {
|
||||
Instance->ConnectedPort = Points->RemotePort;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the MTFTP packet to a continuous buffer if it isn't already so.
|
||||
//
|
||||
Len = UdpPacket->TotalSize;
|
||||
|
||||
if (UdpPacket->BlockOpNum > 1) {
|
||||
Packet = NetAllocatePool (Len);
|
||||
|
||||
if (Packet == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
|
||||
|
||||
} else {
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
|
||||
}
|
||||
|
||||
Opcode = NTOHS (Packet->OpCode);
|
||||
|
||||
//
|
||||
// Call the user's CheckPacket if provided. Abort the transmission
|
||||
// if CheckPacket returns an EFI_ERROR code.
|
||||
//
|
||||
if ((Instance->Token->CheckPacket != NULL) &&
|
||||
((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
|
||||
|
||||
Status = Instance->Token->CheckPacket (
|
||||
&Instance->Mtftp4,
|
||||
Instance->Token,
|
||||
(UINT16) Len,
|
||||
Packet
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Send an error message to the server to inform it
|
||||
//
|
||||
if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
"User aborted the transfer"
|
||||
);
|
||||
}
|
||||
|
||||
Status = EFI_ABORTED;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Opcode) {
|
||||
case EFI_MTFTP4_OPCODE_ACK:
|
||||
if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_OACK:
|
||||
if (Len <= MTFTP4_OPCODE_LEN) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);
|
||||
break;
|
||||
|
||||
case EFI_MTFTP4_OPCODE_ERROR:
|
||||
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) && (UdpPacket->BlockOpNum > 1)) {
|
||||
NetFreePool (Packet);
|
||||
}
|
||||
|
||||
if (UdpPacket != NULL) {
|
||||
NetbufFree (UdpPacket);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status) && !Completed) {
|
||||
Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// Status may have been updated by UdpIoRecvDatagram
|
||||
//
|
||||
if (EFI_ERROR (Status) || Completed) {
|
||||
Mtftp4CleanOperation (Instance, Status);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user