Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=886

This patch is to support the TFTP windowsize option described in RFC 7440.
The feature allows the client and server to negotiate a window size of
consecutive blocks to send as an alternative for replacing the single-block
lockstep schema.

Currently, the windowsize for write request operation is not supported since
there is no real use cases.

Cc: Ye Ting <ting...@intel.com>
Cc: Fu Siyuan <siyuan...@intel.com>
Cc: Shao Ming <ming.s...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Wu Jiaxin <jiaxin...@intel.com>
---
 NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h    | 13 ++++++-
 NetworkPkg/Mtftp6Dxe/Mtftp6Option.c  | 22 +++++++++++-
 NetworkPkg/Mtftp6Dxe/Mtftp6Option.h  | 14 +++++---
 NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c     | 53 +++++++++++++++++++---------
 NetworkPkg/Mtftp6Dxe/Mtftp6Support.c | 10 ++++++
 NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c     |  2 +-
 6 files changed, 90 insertions(+), 24 deletions(-)

diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h 
b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
index 6b1ce7f853..cf1b6abacc 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Impl.h
@@ -1,9 +1,9 @@
 /** @file
   Mtftp6 internal data structure and definition declaration.
 
-  Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved. <BR>
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. <BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
   http://opensource.org/licenses/bsd-license.php.
@@ -44,10 +44,11 @@ typedef struct _MTFTP6_INSTANCE MTFTP6_INSTANCE;
 #define MTFTP6_DEFAULT_SERVER_CMD_PORT 69
 #define MTFTP6_DEFAULT_TIMEOUT         3
 #define MTFTP6_GET_MAPPING_TIMEOUT     3
 #define MTFTP6_DEFAULT_MAX_RETRY       5
 #define MTFTP6_DEFAULT_BLK_SIZE        512
+#define MTFTP6_DEFAULT_WINDOWSIZE      1
 #define MTFTP6_TICK_PER_SECOND         10000000U
 
 #define MTFTP6_SERVICE_FROM_THIS(a)    CR (a, MTFTP6_SERVICE, ServiceBinding, 
MTFTP6_SERVICE_SIGNATURE)
 #define MTFTP6_INSTANCE_FROM_THIS(a)   CR (a, MTFTP6_INSTANCE, Mtftp6, 
MTFTP6_INSTANCE_SIGNATURE)
 
@@ -75,10 +76,20 @@ struct _MTFTP6_INSTANCE {
 
   UINT16                        BlkSize;
   UINT16                        LastBlk;
   LIST_ENTRY                    BlkList;
 
+  UINT16                        Operation;
+
+  UINT16                        WindowSize;
+
+  //
+  // Record the total received block number and the already acked block number.
+  //
+  UINT64                        TotalBlock;
+  UINT64                        AckedBlock;
+
   EFI_IPv6_ADDRESS              ServerIp;
   UINT16                        ServerCmdPort;
   UINT16                        ServerDataPort;
   UDP_IO                        *UdpIo;
 
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c 
b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
index 0dcf546fa8..94790e3ad6 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.c
@@ -1,9 +1,9 @@
 /** @file
   Mtftp6 option parse functions implementation.
 
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
   http://opensource.org/licenses/bsd-license.php.
@@ -15,10 +15,11 @@
 
 #include "Mtftp6Impl.h"
 
 CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = {
   "blksize",
+  "windowsize",
   "timeout",
   "tsize",
   "multicast"
 };
 
@@ -144,10 +145,11 @@ Mtftp6ParseMcastOption (
 
   @param[in]  Options       The pointer to the extension options list.
   @param[in]  Count         The num of the extension options.
   @param[in]  IsRequest     If FALSE, the extension options is included
                             by a request packet.
+  @param[in]  Operation     The current performed operation.
   @param[in]  ExtInfo       The pointer to the option information to be filled.
 
   @retval EFI_SUCCESS            Parse the multicast option successfully.
   @retval EFI_INVALID_PARAMETER  There is one option is malformatted at least.
   @retval EFI_UNSUPPORTED        There is one option is not supported at least.
@@ -156,10 +158,11 @@ Mtftp6ParseMcastOption (
 EFI_STATUS
 Mtftp6ParseExtensionOption (
   IN EFI_MTFTP6_OPTION        *Options,
   IN UINT32                   Count,
   IN BOOLEAN                  IsRequest,
+  IN UINT16                   Operation,
   IN MTFTP6_EXT_OPTION_INFO   *ExtInfo
   )
 {
   EFI_STATUS                  Status;
   EFI_MTFTP6_OPTION           *Opt;
@@ -226,10 +229,27 @@ Mtftp6ParseExtensionOption (
         return EFI_INVALID_PARAMETER;
       }
 
       ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;
 
+    } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "windowsize") == 0) {
+      if (Operation == EFI_MTFTP6_OPCODE_WRQ) {
+        //
+        // Currently, windowsize is not supported in the write operation.
+        //
+        return EFI_UNSUPPORTED;
+      }
+
+      Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
+
+      if ((Value < 1)) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      ExtInfo->WindowSize = (UINT16) Value;
+      ExtInfo->BitMap |= MTFTP6_OPT_WINDOWSIZE_BIT;
+
     } else if (IsRequest) {
       //
       // If it's a request, unsupported; else if it's a reply, ignore.
       //
       return EFI_UNSUPPORTED;
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h 
b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
index 8e2671fa21..08aa45ff63 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Option.h
@@ -1,9 +1,9 @@
 /** @file
   Mtftp6 option parse functions declaration.
 
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
   http://opensource.org/licenses/bsd-license.php.
@@ -24,11 +24,11 @@
 #include <Library/UdpIoLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiRuntimeServicesTableLib.h>
 
-#define MTFTP6_SUPPORTED_OPTIONS_NUM  4
+#define MTFTP6_SUPPORTED_OPTIONS_NUM  5
 #define MTFTP6_OPCODE_LEN             2
 #define MTFTP6_ERRCODE_LEN            2
 #define MTFTP6_BLKNO_LEN              2
 #define MTFTP6_DATA_HEAD_LEN          4
 
@@ -37,15 +37,17 @@
 //
 #define MTFTP6_OPT_BLKSIZE_BIT        0x01
 #define MTFTP6_OPT_TIMEOUT_BIT        0x02
 #define MTFTP6_OPT_TSIZE_BIT          0x04
 #define MTFTP6_OPT_MCAST_BIT          0x08
+#define MTFTP6_OPT_WINDOWSIZE_BIT     0X10
 
 extern CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM];
 
 typedef struct {
   UINT16                    BlkSize;
+  UINT16                    WindowSize;
   UINT8                     Timeout;
   UINT32                    Tsize;
   EFI_IPv6_ADDRESS          McastIp;
   UINT16                    McastPort;
   BOOLEAN                   IsMaster;
@@ -74,22 +76,24 @@ Mtftp6ParseMcastOption (
 
   @param[in]  Options       The pointer to the extension options list.
   @param[in]  Count         The num of the extension options.
   @param[in]  IsRequest     If FALSE, the extension options is included
                             by a request packet.
+  @param[in]  Operation     The current performed operation.
   @param[in]  ExtInfo       The pointer to the option information to be filled.
 
-  @retval EFI_SUCCESS            Parse the multi-cast option successfully.
-  @retval EFI_INVALID_PARAMETER  An option is malformatted.
-  @retval EFI_UNSUPPORTED        An option is not supported.
+  @retval EFI_SUCCESS            Parse the multicast option successfully.
+  @retval EFI_INVALID_PARAMETER  There is one option is malformatted at least.
+  @retval EFI_UNSUPPORTED        There is one option is not supported at least.
 
 **/
 EFI_STATUS
 Mtftp6ParseExtensionOption (
   IN EFI_MTFTP6_OPTION        *Options,
   IN UINT32                   Count,
   IN BOOLEAN                  IsRequest,
+  IN UINT16                   Operation,
   IN MTFTP6_EXT_OPTION_INFO   *ExtInfo
   );
 
 
 /**
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
index 2aadef076c..1f685b2bfe 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Rrq.c
@@ -1,9 +1,9 @@
 /** @file
   Mtftp6 Rrq process functions implementation.
 
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
   http://opensource.org/licenses/bsd-license.php.
@@ -33,10 +33,13 @@ Mtftp6RrqSendAck (
   IN UINT16                 BlockNum
   )
 {
   EFI_MTFTP6_PACKET         *Ack;
   NET_BUF                   *Packet;
+  EFI_STATUS                Status;
+
+  Status = EFI_SUCCESS;
 
   //
   // Allocate net buffer to create ack packet.
   //
   Packet = NetbufAlloc (sizeof (EFI_MTFTP6_ACK_HEADER));
@@ -59,11 +62,16 @@ Mtftp6RrqSendAck (
   // Reset current retry count of the instance.
   //
   Instance->CurRetry = 0;
   Instance->LastPacket = Packet;
 
-  return Mtftp6TransmitPacket (Instance, Packet);
+  Status = Mtftp6TransmitPacket (Instance, Packet);
+  if (!EFI_ERROR (Status)) {
+    Instance->AckedBlock = Instance->TotalBlock;
+  }
+
+  return Status;
 }
 
 
 /**
   Deliver the received data block to the user, which can be saved
@@ -92,11 +100,10 @@ Mtftp6RrqSaveBlock (
   EFI_MTFTP6_TOKEN          *Token;
   EFI_STATUS                Status;
   UINT16                    Block;
   UINT64                    Start;
   UINT32                    DataLen;
-  UINT64                    TotalBlock;
   BOOLEAN                   Completed;
 
   Completed = FALSE;
   Token     = Instance->Token;
   Block     = NTOHS (Packet->Data.Block);
@@ -116,11 +123,11 @@ Mtftp6RrqSaveBlock (
   // returns EFI_NOT_FOUND, the block has been saved, don't save it again.
   // Note that : For bigger files, allowing the block counter to roll over
   // to accept transfers of unlimited size. So TotalBlock is memorised as
   // continuous block counter.
   //
-  Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, 
&TotalBlock);
+  Status = Mtftp6RemoveBlockNum (&Instance->BlkList, Block, Completed, 
&Instance->TotalBlock);
 
   if (Status == EFI_NOT_FOUND) {
     return EFI_SUCCESS;
   } else if (EFI_ERROR (Status)) {
     return Status;
@@ -152,11 +159,11 @@ Mtftp6RrqSaveBlock (
     }
   }
 
   if (Token->Buffer != NULL) {
 
-    Start = MultU64x32 (TotalBlock - 1, Instance->BlkSize);
+    Start = MultU64x32 (Instance->TotalBlock - 1, Instance->BlkSize);
     if (Start + DataLen <= Token->BufferSize) {
       CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
       //
       // Update the file size when received the last block
       //
@@ -222,30 +229,33 @@ Mtftp6RrqHandleData (
   EFI_STATUS                Status;
   UINT16                    BlockNum;
   INTN                      Expected;
 
   *IsCompleted = FALSE;
+  Status       = EFI_SUCCESS;
   BlockNum     = NTOHS (Packet->Data.Block);
   Expected     = Mtftp6GetNextBlockNum (&Instance->BlkList);
 
   ASSERT (Expected >= 0);
 
   //
-  // If we are active and received an unexpected packet, retransmit
-  // the last ACK then restart receiving. If we are passive, save
-  // the block.
+  // If we are active and received an unexpected packet, transmit
+  // the ACK for the block we received, then restart receiving the
+  // expected one. If we are passive, save the block.
   //
   if (Instance->IsMaster && (Expected != BlockNum)) {
     //
     // Free the received packet before send new packet in ReceiveNotify,
     // since the udpio might need to be reconfigured.
     //
     NetbufFree (*UdpPacket);
     *UdpPacket = NULL;
 
-    Mtftp6TransmitPacket (Instance, Instance->LastPacket);
-    return EFI_SUCCESS;
+    //
+    // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack 
number (65535).
+    //
+    return Mtftp6RrqSendAck (Instance,  (UINT16) (Expected - 1));
   }
 
   Status = Mtftp6RrqSaveBlock (Instance, Packet, Len, UdpPacket);
 
   if (EFI_ERROR (Status)) {
@@ -286,14 +296,16 @@ Mtftp6RrqHandleData (
     // since the udpio might need to be reconfigured.
     //
     NetbufFree (*UdpPacket);
     *UdpPacket = NULL;
 
-    Mtftp6RrqSendAck (Instance, BlockNum);
+    if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) 
|| Expected < 0) {
+      Status = Mtftp6RrqSendAck (Instance, BlockNum);
+    }
   }
 
-  return EFI_SUCCESS;
+  return Status;
 }
 
 
 /**
   Validate whether the options received in the server's OACK packet is valid.
@@ -324,16 +336,17 @@ Mtftp6RrqOackValid (
   if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
     return FALSE;
   }
 
   //
-  // Server can only specify a smaller block size to be used and
+  // Server can only specify a smaller block size and windowsize to be used and
   // return the timeout matches that requested.
   //
   if ((((ReplyInfo->BitMap & MTFTP6_OPT_BLKSIZE_BIT) != 0) && 
(ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
+      (((ReplyInfo->BitMap & MTFTP6_OPT_WINDOWSIZE_BIT) != 0) && 
(ReplyInfo->BlkSize > RequestInfo->BlkSize)) ||
       (((ReplyInfo->BitMap & MTFTP6_OPT_TIMEOUT_BIT) != 0) && 
(ReplyInfo->Timeout != RequestInfo->Timeout))
-      ) {
+     ) {
     return FALSE;
   }
 
   //
   // The server can send ",,master" to client to change its master
@@ -483,11 +496,11 @@ Mtftp6RrqHandleOack (
   ASSERT (Options != NULL);
 
   //
   // Parse the extensive options in the packet.
   //
-  Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
+  Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, 
Instance->Operation, &ExtInfo);
 
   if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, 
&Instance->ExtInfo)) {
     //
     // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
     //
@@ -513,11 +526,11 @@ Mtftp6RrqHandleOack (
 
   if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {
 
     //
     // Save the multicast info. Always update the Master, only update the
-    // multicast IP address, block size, timeoute at the first time. If IP
+    // multicast IP address, block size, window size, timeoute at the first 
time. If IP
     // address is updated, create a UDP child to receive the multicast.
     //
     Instance->IsMaster = ExtInfo.IsMaster;
 
     if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
@@ -610,10 +623,14 @@ Mtftp6RrqHandleOack (
       //
       if (ExtInfo.BlkSize != 0) {
         Instance->BlkSize = ExtInfo.BlkSize;
       }
 
+      if (ExtInfo.WindowSize != 0) {
+        Instance->WindowSize = ExtInfo.WindowSize;
+      }
+
       if (ExtInfo.Timeout != 0) {
         Instance->Timeout = ExtInfo.Timeout;
       }
     }
 
@@ -623,10 +640,14 @@ Mtftp6RrqHandleOack (
 
     if (ExtInfo.BlkSize != 0) {
       Instance->BlkSize = ExtInfo.BlkSize;
     }
 
+    if (ExtInfo.WindowSize != 0) {
+      Instance->WindowSize = ExtInfo.WindowSize;
+    }
+
     if (ExtInfo.Timeout != 0) {
       Instance->Timeout = ExtInfo.Timeout;
     }
   }
 
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c 
b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
index 282a9c8e49..275272b89e 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Support.c
@@ -977,10 +977,14 @@ Mtftp6OperationClean (
 
   Instance->ServerCmdPort  = 0;
   Instance->ServerDataPort = 0;
   Instance->McastPort      = 0;
   Instance->BlkSize        = 0;
+  Instance->Operation      = 0;
+  Instance->WindowSize     = 1;
+  Instance->TotalBlock     = 0;
+  Instance->AckedBlock     = 0;
   Instance->LastBlk        = 0;
   Instance->PacketToLive   = 0;
   Instance->MaxRetry       = 0;
   Instance->CurRetry       = 0;
   Instance->Timeout        = 0;
@@ -1049,19 +1053,22 @@ Mtftp6OperationStart (
   }
 
   Status           = EFI_SUCCESS;
   Instance->OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 
+  Instance->Operation = OpCode;
+
   //
   // Parse the extension options in the request packet.
   //
   if (Token->OptionCount != 0) {
 
     Status = Mtftp6ParseExtensionOption (
                Token->OptionList,
                Token->OptionCount,
                TRUE,
+               Instance->Operation,
                &Instance->ExtInfo
                );
 
     if (EFI_ERROR (Status)) {
       goto ON_ERROR;
@@ -1103,10 +1110,13 @@ Mtftp6OperationStart (
     Instance->ServerCmdPort = MTFTP6_DEFAULT_SERVER_CMD_PORT;
   }
   if (Instance->BlkSize == 0) {
     Instance->BlkSize = MTFTP6_DEFAULT_BLK_SIZE;
   }
+  if (Instance->WindowSize == 0) {
+    Instance->WindowSize = MTFTP6_DEFAULT_WINDOWSIZE;
+  }
   if (Instance->MaxRetry == 0) {
     Instance->MaxRetry = MTFTP6_DEFAULT_MAX_RETRY;
   }
   if (Instance->Timeout == 0) {
     Instance->Timeout = MTFTP6_DEFAULT_TIMEOUT;
diff --git a/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c b/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
index 254b757f7e..055fbe6d1b 100644
--- a/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
+++ b/NetworkPkg/Mtftp6Dxe/Mtftp6Wrq.c
@@ -316,11 +316,11 @@ Mtftp6WrqHandleOack (
   if (EFI_ERROR (Status)) {
     return Status;
   }
   ASSERT (Options != NULL);
 
-  Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);
+  Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, 
Instance->Operation, &ExtInfo);
 
   if (EFI_ERROR(Status) || !Mtftp6WrqOackValid (&ExtInfo, &Instance->ExtInfo)) 
{
     //
     // Don't send a MTFTP error packet when out of resource, it can
     // only make it worse.
-- 
2.17.1.windows.2

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to