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:
vanjeff
2007-07-30 02:37:10 +00:00
parent eca7eaf49b
commit 772db4bb33
113 changed files with 42735 additions and 302 deletions

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

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

View 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

View 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

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

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

View 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

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

View 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

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

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

View 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

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