NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
Signed-off-by: Liming Gao <liming.gao@intel.com> Cc: Siyuan Fu <siyuan.fu@intel.com> Cc: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
This commit is contained in:
663
NetworkPkg/Mtftp4Dxe/Mtftp4Support.c
Normal file
663
NetworkPkg/Mtftp4Dxe/Mtftp4Support.c
Normal file
@@ -0,0 +1,663 @@
|
||||
/** @file
|
||||
Support routines for Mtftp.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#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 Pointer to the created block range, NULL if failed to allocate memory.
|
||||
|
||||
**/
|
||||
MTFTP4_BLOCK_RANGE *
|
||||
Mtftp4AllocateRange (
|
||||
IN UINT16 Start,
|
||||
IN UINT16 End
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
Range = AllocateZeroPool (sizeof (MTFTP4_BLOCK_RANGE));
|
||||
|
||||
if (Range == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InitializeListHead (&Range->Link);
|
||||
Range->Start = Start;
|
||||
Range->End = End;
|
||||
Range->Bound = End;
|
||||
|
||||
return Range;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the block range for either RRQ or WRQ.
|
||||
|
||||
RRQ and WRQ have different requirements for Start and End.
|
||||
For example, during 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 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;
|
||||
}
|
||||
|
||||
InsertTailList (Head, &Range->Link);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the first valid block number on the range list.
|
||||
|
||||
@param Head The block range head
|
||||
|
||||
@return The first valid block number, -1 if the block range is empty.
|
||||
|
||||
**/
|
||||
INTN
|
||||
Mtftp4GetNextBlockNum (
|
||||
IN LIST_ENTRY *Head
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
|
||||
if (IsListEmpty (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
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetLastBlockNum (
|
||||
IN 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 (!IsListEmpty (Head)) {
|
||||
Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);
|
||||
|
||||
if (Range->Start > Last) {
|
||||
RemoveEntryList (&Range->Link);
|
||||
FreePool (Range);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Range->End > Last) {
|
||||
Range->End = Last;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove the block number from the block range list.
|
||||
|
||||
@param Head The block range list to remove from
|
||||
@param Num The block number to remove
|
||||
@param Completed Whether Num is the last block number.
|
||||
@param BlockCounter The continuous block counter instead of the value after roll-over.
|
||||
|
||||
@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 LIST_ENTRY *Head,
|
||||
IN UINT16 Num,
|
||||
IN BOOLEAN Completed,
|
||||
OUT UINT64 *BlockCounter
|
||||
)
|
||||
{
|
||||
MTFTP4_BLOCK_RANGE *Range;
|
||||
MTFTP4_BLOCK_RANGE *NewRange;
|
||||
LIST_ENTRY *Entry;
|
||||
|
||||
NET_LIST_FOR_EACH (Entry, Head) {
|
||||
|
||||
//
|
||||
// Each block represents a hole [Start, End] in the file,
|
||||
// skip to the first range with End >= Num
|
||||
//
|
||||
Range = NET_LIST_USER_STRUCT (Entry, 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++;
|
||||
|
||||
//
|
||||
// Note that: RFC 1350 does not mention block counter roll-over,
|
||||
// but several TFTP hosts implement the roll-over be able to accept
|
||||
// transfers of unlimited size. There is no consensus, however, whether
|
||||
// the counter should wrap around to zero or to one. Many implementations
|
||||
// wrap to zero, because this is the simplest to implement. Here we choose
|
||||
// this solution.
|
||||
//
|
||||
*BlockCounter = Num;
|
||||
|
||||
if (Range->Round > 0) {
|
||||
*BlockCounter += Range->Bound + MultU64x32 ((UINTN) (Range->Round -1), (UINT32) (Range->Bound + 1)) + 1;
|
||||
}
|
||||
|
||||
if (Range->Start > Range->Bound) {
|
||||
Range->Start = 0;
|
||||
Range->Round ++;
|
||||
}
|
||||
|
||||
if ((Range->Start > Range->End) || Completed) {
|
||||
RemoveEntryList (&Range->Link);
|
||||
FreePool (Range);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
if (Range->End == Num) {
|
||||
Range->End--;
|
||||
} else {
|
||||
NewRange = Mtftp4AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);
|
||||
|
||||
if (NewRange == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Range->End = Num - 1;
|
||||
NetListInsertAfter (&Range->Link, &NewRange->Link);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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;
|
||||
RETURN_STATUS Status;
|
||||
NET_BUF *Nbuf;
|
||||
UINT8 *Mode;
|
||||
UINT8 *Cur;
|
||||
UINTN Index;
|
||||
UINT32 BufferLength;
|
||||
UINTN FileNameLength;
|
||||
UINTN ModeLength;
|
||||
UINTN OptionStrLength;
|
||||
UINTN ValueStrLength;
|
||||
|
||||
Token = Instance->Token;
|
||||
Options = Token->OptionList;
|
||||
Mode = Instance->Token->ModeStr;
|
||||
|
||||
if (Mode == NULL) {
|
||||
Mode = (UINT8 *) "octet";
|
||||
}
|
||||
|
||||
//
|
||||
// Compute the packet length
|
||||
//
|
||||
FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);
|
||||
ModeLength = AsciiStrLen ((CHAR8 *) Mode);
|
||||
BufferLength = (UINT32) FileNameLength + (UINT32) ModeLength + 4;
|
||||
|
||||
for (Index = 0; Index < Token->OptionCount; Index++) {
|
||||
OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
|
||||
ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
|
||||
BufferLength += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;
|
||||
}
|
||||
//
|
||||
// Allocate a packet then copy the data over
|
||||
//
|
||||
if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);
|
||||
ASSERT (Packet != NULL);
|
||||
|
||||
Packet->OpCode = HTONS (Instance->Operation);
|
||||
BufferLength -= sizeof (Packet->OpCode);
|
||||
|
||||
Cur = Packet->Rrq.Filename;
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (FileNameLength + 1);
|
||||
Cur += FileNameLength + 1;
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (ModeLength + 1);
|
||||
Cur += ModeLength + 1;
|
||||
|
||||
for (Index = 0; Index < Token->OptionCount; ++Index) {
|
||||
OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);
|
||||
ValueStrLength = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);
|
||||
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (OptionStrLength + 1);
|
||||
Cur += OptionStrLength + 1;
|
||||
|
||||
Status = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
BufferLength -= (UINT32) (ValueStrLength + 1);
|
||||
Cur += ValueStrLength + 1;
|
||||
|
||||
}
|
||||
|
||||
return Mtftp4SendPacket (Instance, Nbuf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Build then send an error message.
|
||||
|
||||
@param Instance The MTFTP session
|
||||
@param ErrCode The error code
|
||||
@param ErrInfo The error 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 ((CHAR8 *) 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);
|
||||
ASSERT (TftpError != NULL);
|
||||
|
||||
TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);
|
||||
TftpError->Error.ErrorCode = HTONS (ErrCode);
|
||||
|
||||
AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, Len, (CHAR8 *) 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 EndPoint The local and remote UDP access point
|
||||
@param IoStatus The result of the transmission
|
||||
@param Context Opaque parameter to the callback
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnPacketSent (
|
||||
IN NET_BUF *Packet,
|
||||
IN UDP_END_POINT *EndPoint,
|
||||
IN EFI_STATUS IoStatus,
|
||||
IN 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
|
||||
|
||||
**/
|
||||
VOID
|
||||
Mtftp4SetTimeout (
|
||||
IN OUT 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 OUT MTFTP4_PROTOCOL *Instance,
|
||||
IN OUT NET_BUF *Packet
|
||||
)
|
||||
{
|
||||
UDP_END_POINT UdpPoint;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
UINT8 *Buffer;
|
||||
|
||||
//
|
||||
// Save the packet for retransmission
|
||||
//
|
||||
if (Instance->LastPacket != NULL) {
|
||||
NetbufFree (Instance->LastPacket);
|
||||
}
|
||||
|
||||
Instance->LastPacket = Packet;
|
||||
|
||||
Instance->CurRetry = 0;
|
||||
Mtftp4SetTimeout (Instance);
|
||||
|
||||
ZeroMem (&UdpPoint, sizeof (UdpPoint));
|
||||
UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;
|
||||
|
||||
//
|
||||
// Send the requests to the listening port, other packets
|
||||
// to the connected port
|
||||
//
|
||||
Buffer = NetbufGetByte (Packet, 0, NULL);
|
||||
ASSERT (Buffer != NULL);
|
||||
OpCode = NTOHS (*(UINT16 *)Buffer);
|
||||
|
||||
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,
|
||||
NULL,
|
||||
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_END_POINT UdpPoint;
|
||||
EFI_STATUS Status;
|
||||
UINT16 OpCode;
|
||||
UINT8 *Buffer;
|
||||
|
||||
ASSERT (Instance->LastPacket != NULL);
|
||||
|
||||
ZeroMem (&UdpPoint, sizeof (UdpPoint));
|
||||
UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;
|
||||
|
||||
//
|
||||
// Set the requests to the listening port, other packets to the connected port
|
||||
//
|
||||
Buffer = NetbufGetByte (Instance->LastPacket, 0, NULL);
|
||||
ASSERT (Buffer != NULL);
|
||||
OpCode = NTOHS (*(UINT16 *) Buffer);
|
||||
|
||||
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,
|
||||
NULL,
|
||||
Mtftp4OnPacketSent,
|
||||
Instance
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
NET_PUT_REF (Instance->LastPacket);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The timer ticking function in TPL_NOTIFY level for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTickNotifyLevel (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
|
||||
MtftpSb = (MTFTP4_SERVICE *) Context;
|
||||
|
||||
//
|
||||
// Iterate through all the children of the Mtftp service instance. Time
|
||||
// out the current packet transmit.
|
||||
//
|
||||
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)) {
|
||||
Instance->HasTimeout = FALSE;
|
||||
} else {
|
||||
Instance->HasTimeout = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The timer ticking function for the Mtftp service instance.
|
||||
|
||||
@param Event The ticking event
|
||||
@param Context The Mtftp service instance
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
Mtftp4OnTimerTick (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
MTFTP4_SERVICE *MtftpSb;
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
MTFTP4_PROTOCOL *Instance;
|
||||
EFI_MTFTP4_TOKEN *Token;
|
||||
|
||||
MtftpSb = (MTFTP4_SERVICE *) Context;
|
||||
|
||||
//
|
||||
// Iterate through all the children of the Mtftp service instance.
|
||||
//
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
|
||||
Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
|
||||
if (!Instance->HasTimeout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Instance->HasTimeout = FALSE;
|
||||
|
||||
//
|
||||
// Call the user's time out handler
|
||||
//
|
||||
Token = Instance->Token;
|
||||
|
||||
if (Token != NULL && Token->TimeoutCallback != NULL &&
|
||||
EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {
|
||||
Mtftp4SendError (
|
||||
Instance,
|
||||
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
|
||||
(UINT8 *) "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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user