]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Support.c
index b43f94da62193e6093f5b3ec4224eca25fbff58f..ad2ff7bf3a3f82a83e3ef4a5d6f9cdd8e0947c45 100644 (file)
@@ -1,22 +1,8 @@
 /** @file\r
+  Support routines for Mtftp.\r
 \r
-Copyright (c) 2006 - 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-Module Name:\r
-\r
-  Mtftp4Support.c\r
-\r
-Abstract:\r
-\r
-  Support routines for Mtftp\r
-\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -24,13 +10,12 @@ Abstract:
 \r
 \r
 /**\r
-  Allocate a MTFTP4 block range, then init it to the\r
-  range of [Start, End]\r
+  Allocate a MTFTP4 block range, then init it to the range of [Start, End]\r
 \r
   @param  Start                 The start block number\r
   @param  End                   The last block number in the range\r
 \r
-  @return NULL if failed to allocate memory, otherwise the created block range.\r
+  @return Pointer to the created block range, NULL if failed to allocate memory.\r
 \r
 **/\r
 MTFTP4_BLOCK_RANGE *\r
@@ -41,7 +26,7 @@ Mtftp4AllocateRange (
 {\r
   MTFTP4_BLOCK_RANGE        *Range;\r
 \r
-  Range = AllocatePool (sizeof (MTFTP4_BLOCK_RANGE));\r
+  Range = AllocateZeroPool (sizeof (MTFTP4_BLOCK_RANGE));\r
 \r
   if (Range == NULL) {\r
     return NULL;\r
@@ -50,22 +35,24 @@ Mtftp4AllocateRange (
   InitializeListHead (&Range->Link);\r
   Range->Start  = Start;\r
   Range->End    = End;\r
+  Range->Bound  = End;\r
 \r
   return Range;\r
 }\r
 \r
 \r
 /**\r
-  Initialize the block range for either RRQ or WRQ. RRQ and WRQ have\r
-  different requirements for Start and End. For example, during start\r
-  up, WRQ initializes its whole valid block range to [0, 0xffff]. This\r
-  is bacause the server will send us a ACK0 to inform us to start the\r
-  upload. When the client received ACK0, it will remove 0 from the range,\r
-  get the next block number, which is 1, then upload the BLOCK1. For RRQ\r
-  without option negotiation, the server will directly send us the BLOCK1\r
-  in response to the client's RRQ. When received BLOCK1, the client will\r
-  remove it from the block range and send an ACK. It also works if there\r
-  is option negotiation.\r
+  Initialize the block range for either RRQ or WRQ.\r
+\r
+  RRQ and WRQ have different requirements for Start and End.\r
+  For example, during start up, WRQ initializes its whole valid block range\r
+  to [0, 0xffff]. This is bacause the server will send us a ACK0 to inform us\r
+  to start the upload. When the client received ACK0, it will remove 0 from the\r
+  range, get the next block number, which is 1, then upload the BLOCK1. For RRQ\r
+  without option negotiation, the server will directly send us the BLOCK1 in\r
+  response to the client's RRQ. When received BLOCK1, the client will remove\r
+  it from the block range and send an ACK. It also works if there is option\r
+  negotiation.\r
 \r
   @param  Head                  The block range head to initialize\r
   @param  Start                 The Start block number.\r
@@ -100,7 +87,7 @@ Mtftp4InitBlockRange (
 \r
   @param  Head                  The block range head\r
 \r
-  @return -1: if the block range is empty. Otherwise the first valid block number.\r
+  @return The first valid block number, -1 if the block range is empty.\r
 \r
 **/\r
 INTN\r
@@ -120,17 +107,15 @@ Mtftp4GetNextBlockNum (
 \r
 \r
 /**\r
-  Set the last block number of the block range list. It will\r
-  remove all the blocks after the Last. MTFTP initialize the\r
-  block range to the maximum possible range, such as [0, 0xffff]\r
-  for WRQ. When it gets the last block number, it will call\r
-  this function to set the last block number.\r
+  Set the last block number of the block range list.\r
+\r
+  It will remove all the blocks after the Last. MTFTP initialize the block range\r
+  to the maximum possible range, such as [0, 0xffff] for WRQ. When it gets the\r
+  last block number, it will call this function to set the last block number.\r
 \r
   @param  Head                  The block range list\r
   @param  Last                  The last block number\r
 \r
-  @return None\r
-\r
 **/\r
 VOID\r
 Mtftp4SetLastBlockNum (\r
@@ -149,7 +134,7 @@ Mtftp4SetLastBlockNum (
 \r
     if (Range->Start > Last) {\r
       RemoveEntryList (&Range->Link);\r
-      gBS->FreePool (Range);\r
+      FreePool (Range);\r
       continue;\r
     }\r
 \r
@@ -167,6 +152,8 @@ Mtftp4SetLastBlockNum (
 \r
   @param  Head                  The block range list to remove from\r
   @param  Num                   The block number to remove\r
+  @param  Completed             Whether Num is the last block number.\r
+  @param  BlockCounter          The continuous block counter instead of the value after roll-over.\r
 \r
   @retval EFI_NOT_FOUND         The block number isn't in the block range list\r
   @retval EFI_SUCCESS           The block number has been removed from the list\r
@@ -176,7 +163,9 @@ Mtftp4SetLastBlockNum (
 EFI_STATUS\r
 Mtftp4RemoveBlockNum (\r
   IN LIST_ENTRY             *Head,\r
-  IN UINT16                 Num\r
+  IN UINT16                 Num,\r
+  IN BOOLEAN                Completed,\r
+  OUT UINT64                *BlockCounter\r
   )\r
 {\r
   MTFTP4_BLOCK_RANGE        *Range;\r
@@ -217,9 +206,28 @@ Mtftp4RemoveBlockNum (
     } else if (Range->Start == Num) {\r
       Range->Start++;\r
 \r
-      if (Range->Start > Range->End) {\r
+      //\r
+      // Note that: RFC 1350 does not mention block counter roll-over,\r
+      // but several TFTP hosts implement the roll-over be able to accept\r
+      // transfers of unlimited size. There is no consensus, however, whether\r
+      // the counter should wrap around to zero or to one. Many implementations\r
+      // wrap to zero, because this is the simplest to implement. Here we choose\r
+      // this solution.\r
+      //\r
+      *BlockCounter  = Num;\r
+\r
+      if (Range->Round > 0) {\r
+        *BlockCounter += Range->Bound +  MultU64x32 ((UINTN) (Range->Round -1), (UINT32) (Range->Bound + 1)) + 1;\r
+      }\r
+\r
+      if (Range->Start > Range->Bound) {\r
+        Range->Start = 0;\r
+        Range->Round ++;\r
+      }\r
+\r
+      if ((Range->Start > Range->End) || Completed) {\r
         RemoveEntryList (&Range->Link);\r
-        gBS->FreePool (Range);\r
+        FreePool (Range);\r
       }\r
 \r
       return EFI_SUCCESS;\r
@@ -264,13 +272,16 @@ Mtftp4SendRequest (
   EFI_MTFTP4_PACKET         *Packet;\r
   EFI_MTFTP4_OPTION         *Options;\r
   EFI_MTFTP4_TOKEN          *Token;\r
+  RETURN_STATUS             Status;\r
   NET_BUF                   *Nbuf;\r
   UINT8                     *Mode;\r
   UINT8                     *Cur;\r
-  UINT32                    Len;\r
   UINTN                     Index;\r
-  UINT32                    Len1;\r
-  UINT32                    Len2;\r
+  UINT32                    BufferLength;\r
+  UINTN                     FileNameLength;\r
+  UINTN                     ModeLength;\r
+  UINTN                     OptionStrLength;\r
+  UINTN                     ValueStrLength;\r
 \r
   Token   = Instance->Token;\r
   Options = Token->OptionList;\r
@@ -283,37 +294,52 @@ Mtftp4SendRequest (
   //\r
   // Compute the packet length\r
   //\r
-  Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Token->Filename);\r
-  Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Mode);\r
-  Len  = (Len1 + Len2 + 4);\r
+  FileNameLength = AsciiStrLen ((CHAR8 *) Token->Filename);\r
+  ModeLength     = AsciiStrLen ((CHAR8 *) Mode);\r
+  BufferLength   = (UINT32) FileNameLength + (UINT32) ModeLength + 4;\r
 \r
   for (Index = 0; Index < Token->OptionCount; Index++) {\r
-    Len1 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
-    Len2 = (UINT32) AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
-    Len += Len1 + Len2 + 2;\r
+    OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
+    ValueStrLength  = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
+    BufferLength   += (UINT32) OptionStrLength + (UINT32) ValueStrLength + 2;\r
   }\r
-\r
   //\r
   // Allocate a packet then copy the data over\r
   //\r
-  if ((Nbuf = NetbufAlloc (Len)) == NULL) {\r
+  if ((Nbuf = NetbufAlloc (BufferLength)) == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Packet         = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);\r
+  Packet         = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, BufferLength, FALSE);\r
+  ASSERT (Packet != NULL);\r
+\r
   Packet->OpCode = HTONS (Instance->Operation);\r
+  BufferLength  -= sizeof (Packet->OpCode);\r
+\r
   Cur            = Packet->Rrq.Filename;\r
-  Cur            = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Token->Filename);\r
-  Cur           += AsciiStrLen ((CHAR8 *) Token->Filename) + 1;\r
-  Cur            = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Mode);\r
-  Cur           += AsciiStrLen ((CHAR8 *) Mode) + 1;\r
+  Status         = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Token->Filename);\r
+  ASSERT_EFI_ERROR (Status);\r
+  BufferLength  -= (UINT32) (FileNameLength + 1);\r
+  Cur           += FileNameLength + 1;\r
+  Status         = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Mode);\r
+  ASSERT_EFI_ERROR (Status);\r
+  BufferLength  -= (UINT32) (ModeLength + 1);\r
+  Cur           += ModeLength + 1;\r
 \r
   for (Index = 0; Index < Token->OptionCount; ++Index) {\r
-    Cur  = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].OptionStr);\r
-    Cur += AsciiStrLen ((CHAR8 *) Options[Index].OptionStr) + 1;\r
+    OptionStrLength = AsciiStrLen ((CHAR8 *) Options[Index].OptionStr);\r
+    ValueStrLength  = AsciiStrLen ((CHAR8 *) Options[Index].ValueStr);\r
+\r
+    Status          = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].OptionStr);\r
+    ASSERT_EFI_ERROR (Status);\r
+    BufferLength   -= (UINT32) (OptionStrLength + 1);\r
+    Cur            += OptionStrLength + 1;\r
+\r
+    Status          = AsciiStrCpyS ((CHAR8 *) Cur, BufferLength, (CHAR8 *) Options[Index].ValueStr);\r
+    ASSERT_EFI_ERROR (Status);\r
+    BufferLength   -= (UINT32) (ValueStrLength + 1);\r
+    Cur            += ValueStrLength + 1;\r
 \r
-    Cur  = (UINT8 *) AsciiStrCpy ((CHAR8 *) Cur, (CHAR8 *) Options[Index].ValueStr);\r
-    Cur += AsciiStrLen ((CHAR8 *) (CHAR8 *) Options[Index].ValueStr) + 1;\r
   }\r
 \r
   return Mtftp4SendPacket (Instance, Nbuf);\r
@@ -321,10 +347,11 @@ Mtftp4SendRequest (
 \r
 \r
 /**\r
-  Build then send an error message\r
+  Build then send an error message.\r
 \r
   @param  Instance              The MTFTP session\r
-  @param  ErrInfo               The error code and message\r
+  @param  ErrCode               The error code\r
+  @param  ErrInfo               The error message\r
 \r
   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the error packet\r
   @retval EFI_SUCCESS           The error packet is transmitted.\r
@@ -335,7 +362,7 @@ EFI_STATUS
 Mtftp4SendError (\r
   IN MTFTP4_PROTOCOL        *Instance,\r
   IN UINT16                 ErrCode,\r
-  IN UINT8*                 ErrInfo\r
+  IN UINT8                  *ErrInfo\r
   )\r
 {\r
   NET_BUF                   *Packet;\r
@@ -344,16 +371,17 @@ Mtftp4SendError (
 \r
   Len     = (UINT32) (AsciiStrLen ((CHAR8 *) ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));\r
   Packet  = NetbufAlloc (Len);\r
-\r
   if (Packet == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   TftpError         = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);\r
+  ASSERT (TftpError != NULL);\r
+\r
   TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);\r
   TftpError->Error.ErrorCode = HTONS (ErrCode);\r
 \r
-  AsciiStrCpy ((CHAR8 *) TftpError->Error.ErrorMessage, (CHAR8 *) ErrInfo);\r
+  AsciiStrCpyS ((CHAR8 *) TftpError->Error.ErrorMessage, Len, (CHAR8 *) ErrInfo);\r
 \r
   return Mtftp4SendPacket (Instance, Packet);\r
 }\r
@@ -361,22 +389,22 @@ Mtftp4SendError (
 \r
 /**\r
   The callback function called when the packet is transmitted.\r
+\r
   It simply frees the packet.\r
 \r
   @param  Packet                The transmitted (or failed to) packet\r
-  @param  Points                The local and remote UDP access point\r
+  @param  EndPoint              The local and remote UDP access point\r
   @param  IoStatus              The result of the transmission\r
   @param  Context               Opaque parameter to the callback\r
 \r
-  @return None\r
-\r
 **/\r
 VOID\r
+EFIAPI\r
 Mtftp4OnPacketSent (\r
-  NET_BUF                   *Packet,\r
-  UDP_POINTS                *Points,\r
-  EFI_STATUS                IoStatus,\r
-  VOID                      *Context\r
+  IN NET_BUF                   *Packet,\r
+  IN UDP_END_POINT             *EndPoint,\r
+  IN EFI_STATUS                IoStatus,\r
+  IN VOID                      *Context\r
   )\r
 {\r
   NetbufFree (Packet);\r
@@ -384,17 +412,14 @@ Mtftp4OnPacketSent (
 \r
 \r
 /**\r
-  Set the timeout for the instance. User a longer time for\r
-  passive instances.\r
+  Set the timeout for the instance. User a longer time for passive instances.\r
 \r
   @param  Instance              The Mtftp session to set time out\r
 \r
-  @return None\r
-\r
 **/\r
 VOID\r
 Mtftp4SetTimeout (\r
-  IN MTFTP4_PROTOCOL        *Instance\r
+  IN OUT MTFTP4_PROTOCOL        *Instance\r
   )\r
 {\r
   if (Instance->Master) {\r
@@ -406,10 +431,11 @@ Mtftp4SetTimeout (
 \r
 \r
 /**\r
-  Send the packet for the instance. It will first save a reference to\r
-  the packet for later retransmission. then determine the destination\r
-  port, listen port for requests, and connected port for others. At last,\r
-  send the packet out.\r
+  Send the packet for the instance.\r
+\r
+  It will first save a reference to the packet for later retransmission.\r
+  Then determine the destination port, listen port for requests, and connected\r
+  port for others. At last, send the packet out.\r
 \r
   @param  Instance              The Mtftp instance\r
   @param  Packet                The packet to send\r
@@ -420,14 +446,14 @@ Mtftp4SetTimeout (
 **/\r
 EFI_STATUS\r
 Mtftp4SendPacket (\r
-  IN MTFTP4_PROTOCOL        *Instance,\r
-  IN NET_BUF                *Packet\r
+  IN OUT MTFTP4_PROTOCOL        *Instance,\r
+  IN OUT NET_BUF                *Packet\r
   )\r
 {\r
-  UDP_POINTS                UdpPoint;\r
+  UDP_END_POINT             UdpPoint;\r
   EFI_STATUS                Status;\r
   UINT16                    OpCode;\r
-  UINT16                    Value;\r
+  UINT8                     *Buffer;\r
 \r
   //\r
   // Save the packet for retransmission\r
@@ -436,23 +462,24 @@ Mtftp4SendPacket (
     NetbufFree (Instance->LastPacket);\r
   }\r
 \r
-  Instance->LastPacket  = Packet;\r
+  Instance->LastPacket        = Packet;\r
 \r
-  Instance->CurRetry    = 0;\r
+  Instance->CurRetry          = 0;\r
   Mtftp4SetTimeout (Instance);\r
 \r
-  UdpPoint.LocalAddr    = 0;\r
-  UdpPoint.LocalPort    = 0;\r
-  UdpPoint.RemoteAddr   = Instance->ServerIp;\r
+  ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
+  UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
 \r
   //\r
   // Send the requests to the listening port, other packets\r
   // to the connected port\r
   //\r
-  Value = *((UINT16 *) NetbufGetByte (Packet, 0, NULL));\r
-  OpCode = NTOHS (Value);\r
+  Buffer = NetbufGetByte (Packet, 0, NULL);\r
+  ASSERT (Buffer != NULL);\r
+  OpCode = NTOHS (*(UINT16 *)Buffer);\r
 \r
-  if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
+  if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) ||\r
+      (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
       (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
     UdpPoint.RemotePort = Instance->ListeningPort;\r
   } else {\r
@@ -465,7 +492,7 @@ Mtftp4SendPacket (
              Instance->UnicastPort,\r
              Packet,\r
              &UdpPoint,\r
-             0,\r
+             NULL,\r
              Mtftp4OnPacketSent,\r
              Instance\r
              );\r
@@ -479,7 +506,7 @@ Mtftp4SendPacket (
 \r
 \r
 /**\r
-  Retransmit the last packet for the instance\r
+  Retransmit the last packet for the instance.\r
 \r
   @param  Instance              The Mtftp instance\r
 \r
@@ -492,22 +519,22 @@ Mtftp4Retransmit (
   IN MTFTP4_PROTOCOL        *Instance\r
   )\r
 {\r
-  UDP_POINTS                UdpPoint;\r
+  UDP_END_POINT             UdpPoint;\r
   EFI_STATUS                Status;\r
   UINT16                    OpCode;\r
-  UINT16                    Value;\r
+  UINT8                     *Buffer;\r
 \r
   ASSERT (Instance->LastPacket != NULL);\r
 \r
-  UdpPoint.LocalAddr  = 0;\r
-  UdpPoint.LocalPort  = 0;\r
-  UdpPoint.RemoteAddr = Instance->ServerIp;\r
+  ZeroMem (&UdpPoint, sizeof (UdpPoint));\r
+  UdpPoint.RemoteAddr.Addr[0] = Instance->ServerIp;\r
 \r
   //\r
   // Set the requests to the listening port, other packets to the connected port\r
   //\r
-  Value = *(UINT16 *) NetbufGetByte (Instance->LastPacket, 0, NULL);\r
-  OpCode = NTOHS (Value);\r
+  Buffer = NetbufGetByte (Instance->LastPacket, 0, NULL);\r
+  ASSERT (Buffer != NULL);\r
+  OpCode = NTOHS (*(UINT16 *) Buffer);\r
 \r
   if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
       (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
@@ -522,7 +549,7 @@ Mtftp4Retransmit (
              Instance->UnicastPort,\r
              Instance->LastPacket,\r
              &UdpPoint,\r
-             0,\r
+             NULL,\r
              Mtftp4OnPacketSent,\r
              Instance\r
              );\r
@@ -536,12 +563,46 @@ Mtftp4Retransmit (
 \r
 \r
 /**\r
-  The timer ticking function for the Mtftp service instance.\r
+  The timer ticking function in TPL_NOTIFY level for the Mtftp service instance.\r
 \r
   @param  Event                 The ticking event\r
   @param  Context               The Mtftp service instance\r
 \r
-  @return None\r
+**/\r
+VOID\r
+EFIAPI\r
+Mtftp4OnTimerTickNotifyLevel (\r
+  IN EFI_EVENT              Event,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  MTFTP4_SERVICE            *MtftpSb;\r
+  LIST_ENTRY                *Entry;\r
+  LIST_ENTRY                *Next;\r
+  MTFTP4_PROTOCOL           *Instance;\r
+\r
+  MtftpSb = (MTFTP4_SERVICE *) Context;\r
+\r
+  //\r
+  // Iterate through all the children of the Mtftp service instance. Time\r
+  // out the current packet transmit.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
+    Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
+    if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
+      Instance->HasTimeout = FALSE;\r
+    } else {\r
+      Instance->HasTimeout = TRUE;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  The timer ticking function for the Mtftp service instance.\r
+\r
+  @param  Event                 The ticking event\r
+  @param  Context               The Mtftp service instance\r
 \r
 **/\r
 VOID\r
@@ -560,29 +621,28 @@ Mtftp4OnTimerTick (
   MtftpSb = (MTFTP4_SERVICE *) Context;\r
 \r
   //\r
-  // Iterate through all the children of the Mtftp service instance. Time\r
-  // out the packet. If maximum retries reached, clean the session up.\r
+  // Iterate through all the children of the Mtftp service instance.\r
   //\r
   NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
     Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
-\r
-    if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
+    if (!Instance->HasTimeout) {\r
       continue;\r
     }\r
 \r
+    Instance->HasTimeout = FALSE;\r
+\r
     //\r
     // Call the user's time out handler\r
     //\r
     Token = Instance->Token;\r
 \r
-    if ((Token->TimeoutCallback != NULL) &&\r
+    if (Token != NULL && Token->TimeoutCallback != NULL &&\r
         EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {\r
-\r
       Mtftp4SendError (\r
-         Instance,\r
-         EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
-         (UINT8 *) "User aborted the transfer in time out"\r
-         );\r
+        Instance,\r
+        EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
+        (UINT8 *) "User aborted the transfer in time out"\r
+        );\r
 \r
       Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
       continue;\r