]> 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 3f64bf05d916ea533b0ddee704d647113e8c02c6..24c965afb5807771b1bbb8b520d0fce5189171ef 100644 (file)
@@ -1,14 +1,9 @@
 /** @file\r
   Routines to process Rrq (download).\r
-  \r
-Copyright (c) 2006 - 2007, 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
@@ -20,24 +15,25 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
   The packet process callback for MTFTP download.\r
 \r
   @param  UdpPacket             The packet received\r
-  @param  Points                The local/remote access point of the packet\r
+  @param  EndPoint              The local/remote access point of the packet\r
   @param  IoStatus              The status of the receiving\r
   @param  Context               Opaque parameter, which is the MTFTP session\r
 \r
 **/\r
 VOID\r
+EFIAPI\r
 Mtftp4RrqInput (\r
   IN NET_BUF                *UdpPacket,\r
-  IN UDP_POINTS             *Points,\r
+  IN UDP_END_POINT          *EndPoint,\r
   IN EFI_STATUS             IoStatus,\r
   IN VOID                   *Context\r
   );\r
 \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
@@ -97,9 +93,11 @@ Mtftp4RrqSendAck (
 {\r
   EFI_MTFTP4_PACKET         *Ack;\r
   NET_BUF                   *Packet;\r
+  EFI_STATUS                Status;\r
 \r
-  Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
+  Status = EFI_SUCCESS;\r
 \r
+  Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
   if (Packet == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -109,11 +107,17 @@ Mtftp4RrqSendAck (
                                 sizeof (EFI_MTFTP4_ACK_HEADER),\r
                                 FALSE\r
                                 );\r
+  ASSERT (Ack != NULL);\r
 \r
   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
@@ -144,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
@@ -160,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
@@ -184,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
@@ -192,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
@@ -219,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
@@ -248,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
@@ -269,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
@@ -300,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
@@ -340,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
@@ -370,7 +394,7 @@ Mtftp4RrqOackValid (
 /**\r
   Configure a UDP IO port to receive the multicast.\r
 \r
-  @param  McastIo               The UDP IO port to configure\r
+  @param  McastIo               The UDP IO to configure\r
   @param  Context               The opaque parameter to the function which is the\r
                                 MTFTP session.\r
 \r
@@ -379,8 +403,9 @@ Mtftp4RrqOackValid (
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 Mtftp4RrqConfigMcastPort (\r
-  IN UDP_IO_PORT            *McastIo,\r
+  IN UDP_IO                 *McastIo,\r
   IN VOID                   *Context\r
   )\r
 {\r
@@ -404,36 +429,36 @@ 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->Udp->Configure (McastIo->Udp, &UdpConfig);\r
+  Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig);\r
 \r
   if (EFI_ERROR (Status)) {\r
     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->Udp->Routes (\r
-                             McastIo->Udp, \r
-                             FALSE,\r
-                             &mZeroIp4Addr,\r
-                             &mZeroIp4Addr,\r
-                             &Config->GatewayIp\r
-                             );\r
-                             \r
+    Status = McastIo->Protocol.Udp4->Routes (\r
+                                       McastIo->Protocol.Udp4,\r
+                                       FALSE,\r
+                                       &mZeroIp4Addr,\r
+                                       &mZeroIp4Addr,\r
+                                       &Config->GatewayIp\r
+                                       );\r
+\r
     if (EFI_ERROR (Status)) {\r
-      McastIo->Udp->Configure (McastIo->Udp, NULL);\r
+      McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL);\r
       return Status;\r
     }\r
   }\r
@@ -442,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->Udp->Groups (McastIo->Udp, TRUE, &Group);\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
@@ -477,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
@@ -496,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
@@ -518,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
@@ -539,12 +565,31 @@ Mtftp4RrqHandleOack (
       //\r
       Instance->McastIp      = Reply.McastIp;\r
       Instance->McastPort    = Reply.McastPort;\r
-      Instance->McastUdpPort = UdpIoCreatePort (\r
-                                 Instance->Service->Controller,\r
-                                 Instance->Service->Image,\r
-                                 Mtftp4RrqConfigMcastPort,\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
@@ -561,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
@@ -598,15 +651,16 @@ Mtftp4RrqHandleOack (
   The packet process callback for MTFTP download.\r
 \r
   @param  UdpPacket             The packet received\r
-  @param  Points                The local/remote access point of the packet\r
+  @param  EndPoint              The local/remote access point of the packet\r
   @param  IoStatus              The status of the receiving\r
   @param  Context               Opaque parameter, which is the MTFTP session\r
 \r
 **/\r
 VOID\r
+EFIAPI\r
 Mtftp4RrqInput (\r
   IN NET_BUF                *UdpPacket,\r
-  IN UDP_POINTS             *Points,\r
+  IN UDP_END_POINT          *EndPoint,\r
   IN EFI_STATUS             IoStatus,\r
   IN VOID                   *Context\r
   )\r
@@ -637,7 +691,7 @@ Mtftp4RrqInput (
   //\r
   // Find the port this packet is from to restart receive correctly.\r
   //\r
-  Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);\r
+  Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp);\r
 \r
   if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
     goto ON_EXIT;\r
@@ -649,11 +703,11 @@ Mtftp4RrqInput (
   // is required to use the same port as RemotePort to multicast the\r
   // data.\r
   //\r
-  if (Points->RemotePort != Instance->ConnectedPort) {\r
+  if (EndPoint->RemotePort != Instance->ConnectedPort) {\r
     if (Instance->ConnectedPort != 0) {\r
       goto ON_EXIT;\r
     } else {\r
-      Instance->ConnectedPort = Points->RemotePort;\r
+      Instance->ConnectedPort = EndPoint->RemotePort;\r
     }\r
   }\r
 \r
@@ -674,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
@@ -730,7 +785,7 @@ Mtftp4RrqInput (
   case EFI_MTFTP4_OPCODE_ERROR:\r
     Status = EFI_TFTP_ERROR;\r
     break;\r
-    \r
+\r
   default:\r
     break;\r
   }\r
@@ -742,7 +797,7 @@ ON_EXIT:
   // receive, otherwise end the session.\r
   //\r
   if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
-    gBS->FreePool (Packet);\r
+    FreePool (Packet);\r
   }\r
 \r
   if (UdpPacket != NULL) {\r