]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c
BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Rrq.c
index 34fb6a0b6b31794826c8bd42372563671b5b7174..24c965afb5807771b1bbb8b520d0fce5189171ef 100644 (file)
@@ -1,14 +1,9 @@
 /** @file\r
   Routines to process Rrq (download).\r
-  \r
-Copyright (c) 2006 - 2009, Intel Corporation<BR>\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<BR>\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
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -36,9 +31,9 @@ Mtftp4RrqInput (
 \r
 \r
 /**\r
-  Start the MTFTP session to download. \r
-  \r
-  It will first initialize some of the internal states then build and send a RRQ \r
+  Start the MTFTP session to download.\r
+\r
+  It will first initialize some of the internal states then build and send a RRQ\r
   reqeuest packet, at last, it will start receive for the downloading.\r
 \r
   @param  Instance              The Mtftp session\r
@@ -98,6 +93,9 @@ Mtftp4RrqSendAck (
 {\r
   EFI_MTFTP4_PACKET         *Ack;\r
   NET_BUF                   *Packet;\r
+  EFI_STATUS                Status;\r
+\r
+  Status = EFI_SUCCESS;\r
 \r
   Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
   if (Packet == NULL) {\r
@@ -114,7 +112,12 @@ Mtftp4RrqSendAck (
   Ack->Ack.OpCode   = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
   Ack->Ack.Block[0] = HTONS (BlkNo);\r
 \r
-  return Mtftp4SendPacket (Instance, Packet);\r
+  Status = Mtftp4SendPacket (Instance, Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    Instance->AckedBlock = Instance->TotalBlock;\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 \r
@@ -145,15 +148,19 @@ Mtftp4RrqSaveBlock (
   UINT16                    Block;\r
   UINT64                    Start;\r
   UINT32                    DataLen;\r
+  UINT64                    BlockCounter;\r
+  BOOLEAN                   Completed;\r
 \r
-  Token   = Instance->Token;\r
-  Block   = NTOHS (Packet->Data.Block);\r
-  DataLen = Len - MTFTP4_DATA_HEAD_LEN;\r
+  Completed = FALSE;\r
+  Token     = Instance->Token;\r
+  Block     = NTOHS (Packet->Data.Block);\r
+  DataLen   = Len - MTFTP4_DATA_HEAD_LEN;\r
 \r
   //\r
   // This is the last block, save the block no\r
   //\r
   if (DataLen < Instance->BlkSize) {\r
+    Completed = TRUE;\r
     Instance->LastBlock = Block;\r
     Mtftp4SetLastBlockNum (&Instance->Blocks, Block);\r
   }\r
@@ -161,8 +168,11 @@ Mtftp4RrqSaveBlock (
   //\r
   // Remove this block number from the file hole. If Mtftp4RemoveBlockNum\r
   // returns EFI_NOT_FOUND, the block has been saved, don't save it again.\r
+  // Note that : For bigger files, allowing the block counter to roll over\r
+  // to accept transfers of unlimited size. So BlockCounter is memorised as\r
+  // continuous block counter.\r
   //\r
-  Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block);\r
+  Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &BlockCounter);\r
 \r
   if (Status == EFI_NOT_FOUND) {\r
     return EFI_SUCCESS;\r
@@ -185,7 +195,7 @@ Mtftp4RrqSaveBlock (
   }\r
 \r
   if (Token->Buffer != NULL) {\r
-    Start = MultU64x32 (Block - 1, Instance->BlkSize);\r
+     Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize);\r
 \r
     if (Start + DataLen <= Token->BufferSize) {\r
       CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
@@ -193,7 +203,7 @@ Mtftp4RrqSaveBlock (
       //\r
       // Update the file size when received the last block\r
       //\r
-      if (Instance->LastBlock == Block) {\r
+      if ((Instance->LastBlock == Block) && Completed) {\r
         Token->BufferSize = Start + DataLen;\r
       }\r
 \r
@@ -220,8 +230,8 @@ Mtftp4RrqSaveBlock (
 \r
 \r
 /**\r
-  Function to process the received data packets. \r
-  \r
+  Function to process the received data packets.\r
+\r
   It will save the block then send back an ACK if it is active.\r
 \r
   @param  Instance              The downloading MTFTP session\r
@@ -249,19 +259,22 @@ Mtftp4RrqHandleData (
   INTN                      Expected;\r
 \r
   *Completed  = FALSE;\r
+  Status      = EFI_SUCCESS;\r
   BlockNum    = NTOHS (Packet->Data.Block);\r
   Expected    = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
 \r
   ASSERT (Expected >= 0);\r
 \r
   //\r
-  // If we are active and received an unexpected packet, retransmit\r
-  // the last ACK then restart receiving. If we are passive, save\r
-  // the block.\r
+  // If we are active (Master) and received an unexpected packet, transmit\r
+  // the ACK for the block we received, then restart receiving the\r
+  // expected one. If we are passive (Slave), save the block.\r
   //\r
   if (Instance->Master && (Expected != BlockNum)) {\r
-    Mtftp4Retransmit (Instance);\r
-    return EFI_SUCCESS;\r
+    //\r
+    // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535).\r
+    //\r
+    return Mtftp4RrqSendAck (Instance,  (UINT16) (Expected - 1));\r
   }\r
 \r
   Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);\r
@@ -270,6 +283,11 @@ Mtftp4RrqHandleData (
     return Status;\r
   }\r
 \r
+  //\r
+  // Record the total received and saved block number.\r
+  //\r
+  Instance->TotalBlock ++;\r
+\r
   //\r
   // Reset the passive client's timer whenever it received a\r
   // valid data packet.\r
@@ -301,16 +319,19 @@ Mtftp4RrqHandleData (
       BlockNum = (UINT16) (Expected - 1);\r
     }\r
 \r
-    Mtftp4RrqSendAck (Instance, BlockNum);\r
+    if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) {\r
+      Status = Mtftp4RrqSendAck (Instance, BlockNum);\r
+    }\r
+\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 \r
 /**\r
   Validate whether the options received in the server's OACK packet is valid.\r
-  \r
+\r
   The options are valid only if:\r
   1. The server doesn't include options not requested by us\r
   2. The server can only use smaller blksize than that is requested\r
@@ -341,11 +362,13 @@ Mtftp4RrqOackValid (
   }\r
 \r
   //\r
-  // Server can only specify a smaller block size to be used and\r
+  // Server can only specify a smaller block size and window size to be used and\r
   // return the timeout matches that requested.\r
   //\r
   if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0)&& (Reply->BlkSize > Request->BlkSize)) ||\r
-      (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))) {\r
+      (((Reply->Exist & MTFTP4_WINDOWSIZE_EXIST) != 0)&& (Reply->WindowSize > Request->WindowSize)) ||\r
+      (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))\r
+     ) {\r
     return FALSE;\r
   }\r
 \r
@@ -406,13 +429,13 @@ Mtftp4RrqConfigMcastPort (
   UdpConfig.ReceiveTimeout     = 0;\r
   UdpConfig.TransmitTimeout    = 0;\r
   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;\r
-  UdpConfig.StationAddress     = Config->StationIp;\r
-  UdpConfig.SubnetMask         = Config->SubnetMask;\r
+  IP4_COPY_ADDRESS (&UdpConfig.StationAddress, &Config->StationIp);\r
+  IP4_COPY_ADDRESS (&UdpConfig.SubnetMask, &Config->SubnetMask);\r
   UdpConfig.StationPort        = Instance->McastPort;\r
   UdpConfig.RemotePort         = 0;\r
 \r
   Ip = HTONL (Instance->ServerIp);\r
-  CopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+  IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip);\r
 \r
   Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);\r
 \r
@@ -420,20 +443,20 @@ Mtftp4RrqConfigMcastPort (
     return Status;\r
   }\r
 \r
-  if (!Config->UseDefaultSetting && \r
+  if (!Config->UseDefaultSetting &&\r
       !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) {\r
     //\r
     // The station IP address is manually configured and the Gateway IP is not 0.\r
     // Add the default route for this UDP instance.\r
     //\r
     Status = McastIo->Protocol.Udp4->Routes (\r
-                                       McastIo->Protocol.Udp4, \r
+                                       McastIo->Protocol.Udp4,\r
                                        FALSE,\r
                                        &mZeroIp4Addr,\r
                                        &mZeroIp4Addr,\r
                                        &Config->GatewayIp\r
                                        );\r
-                             \r
+\r
     if (EFI_ERROR (Status)) {\r
       McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);\r
       return Status;\r
@@ -444,15 +467,15 @@ Mtftp4RrqConfigMcastPort (
   // join the multicast group\r
   //\r
   Ip = HTONL (Instance->McastIp);\r
-  CopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+  IP4_COPY_ADDRESS (&Group, &Ip);\r
 \r
   return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group);\r
 }\r
 \r
 \r
 /**\r
-  Function to process the OACK. \r
-  \r
+  Function to process the OACK.\r
+\r
   It will first validate the OACK packet, then update the various negotiated parameters.\r
 \r
   @param  Instance              The download MTFTP session\r
@@ -479,6 +502,7 @@ Mtftp4RrqHandleOack (
   MTFTP4_OPTION             Reply;\r
   EFI_STATUS                Status;\r
   INTN                      Expected;\r
+  EFI_UDP4_PROTOCOL         *Udp4;\r
 \r
   *Completed = FALSE;\r
 \r
@@ -498,7 +522,7 @@ Mtftp4RrqHandleOack (
   //\r
   ZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
 \r
-  Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);\r
+  Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply);\r
 \r
   if (EFI_ERROR (Status) ||\r
       !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {\r
@@ -520,7 +544,7 @@ Mtftp4RrqHandleOack (
 \r
     //\r
     // Save the multicast info. Always update the Master, only update the\r
-    // multicast IP address, block size, timeoute at the first time. If IP\r
+    // multicast IP address, block size, window size, timeoute at the first time. If IP\r
     // address is updated, create a UDP child to receive the multicast.\r
     //\r
     Instance->Master = Reply.Master;\r
@@ -541,13 +565,31 @@ Mtftp4RrqHandleOack (
       //\r
       Instance->McastIp      = Reply.McastIp;\r
       Instance->McastPort    = Reply.McastPort;\r
-      Instance->McastUdpPort = UdpIoCreateIo (\r
-                                 Instance->Service->Controller,\r
-                                 Instance->Service->Image,\r
-                                 Mtftp4RrqConfigMcastPort,\r
-                                 UDP_IO_UDP4_VERSION,\r
-                                 Instance\r
-                                 );\r
+      if (Instance->McastUdpPort == NULL) {\r
+        Instance->McastUdpPort = UdpIoCreateIo (\r
+                                   Instance->Service->Controller,\r
+                                   Instance->Service->Image,\r
+                                   Mtftp4RrqConfigMcastPort,\r
+                                   UDP_IO_UDP4_VERSION,\r
+                                   Instance\r
+                                   );\r
+        if (Instance->McastUdpPort != NULL) {\r
+          Status = gBS->OpenProtocol (\r
+                          Instance->McastUdpPort->UdpHandle,\r
+                          &gEfiUdp4ProtocolGuid,\r
+                          (VOID **) &Udp4,\r
+                          Instance->Service->Image,\r
+                          Instance->Handle,\r
+                          EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                          );\r
+          if (EFI_ERROR (Status)) {\r
+            UdpIoFreeIo (Instance->McastUdpPort);\r
+            Instance->McastUdpPort = NULL;\r
+            return EFI_DEVICE_ERROR;\r
+          }\r
+        }\r
+      }\r
+\r
 \r
       if (Instance->McastUdpPort == NULL) {\r
         return EFI_DEVICE_ERROR;\r
@@ -564,31 +606,39 @@ Mtftp4RrqHandleOack (
 \r
         return Status;\r
       }\r
-    \r
+\r
       //\r
       // Update the parameters used.\r
       //\r
       if (Reply.BlkSize != 0) {\r
         Instance->BlkSize = Reply.BlkSize;\r
       }\r
-      \r
+\r
+      if (Reply.WindowSize != 0) {\r
+        Instance->WindowSize = Reply.WindowSize;\r
+      }\r
+\r
       if (Reply.Timeout != 0) {\r
         Instance->Timeout = Reply.Timeout;\r
-      }  \r
-    }    \r
-    \r
+      }\r
+    }\r
+\r
   } else {\r
     Instance->Master = TRUE;\r
-    \r
+\r
     if (Reply.BlkSize != 0) {\r
       Instance->BlkSize = Reply.BlkSize;\r
     }\r
 \r
+    if (Reply.WindowSize != 0) {\r
+      Instance->WindowSize = Reply.WindowSize;\r
+    }\r
+\r
     if (Reply.Timeout != 0) {\r
       Instance->Timeout = Reply.Timeout;\r
     }\r
   }\r
-  \r
+\r
   //\r
   // Send an ACK to (Expected - 1) which is 0 for unicast download,\r
   // or tell the server we want to receive the Expected block.\r
@@ -678,6 +728,7 @@ Mtftp4RrqInput (
 \r
   } else {\r
     Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
+    ASSERT (Packet != NULL);\r
   }\r
 \r
   Opcode = NTOHS (Packet->OpCode);\r
@@ -734,7 +785,7 @@ Mtftp4RrqInput (
   case EFI_MTFTP4_OPCODE_ERROR:\r
     Status = EFI_TFTP_ERROR;\r
     break;\r
-    \r
+\r
   default:\r
     break;\r
   }\r