X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FNetwork%2FMtftp4Dxe%2FMtftp4Rrq.c;h=24c965afb5807771b1bbb8b520d0fce5189171ef;hb=c0fd7f734e2d33e22215899b40a47b843129541d;hp=4a15aeb9707afb2dc31f4816c3e376367b3a5c25;hpb=766c7483c335931b190a78d78d62e5a5e69dc8b9;p=mirror_edk2.git diff --git a/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c b/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c index 4a15aeb970..24c965afb5 100644 --- a/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c +++ b/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c @@ -1,14 +1,9 @@ /** @file Routines to process Rrq (download). - -Copyright (c) 2006 - 2009, Intel Corporation
-All rights reserved. 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
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +(C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -26,6 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ VOID +EFIAPI Mtftp4RrqInput ( IN NET_BUF *UdpPacket, IN UDP_END_POINT *EndPoint, @@ -35,9 +31,9 @@ Mtftp4RrqInput ( /** - Start the MTFTP session to download. - - It will first initialize some of the internal states then build and send a RRQ + Start the MTFTP session to download. + + It will first initialize some of the internal states then build and send a RRQ reqeuest packet, at last, it will start receive for the downloading. @param Instance The Mtftp session @@ -97,6 +93,9 @@ Mtftp4RrqSendAck ( { EFI_MTFTP4_PACKET *Ack; NET_BUF *Packet; + EFI_STATUS Status; + + Status = EFI_SUCCESS; Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER)); if (Packet == NULL) { @@ -113,7 +112,12 @@ Mtftp4RrqSendAck ( Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK); Ack->Ack.Block[0] = HTONS (BlkNo); - return Mtftp4SendPacket (Instance, Packet); + Status = Mtftp4SendPacket (Instance, Packet); + if (!EFI_ERROR (Status)) { + Instance->AckedBlock = Instance->TotalBlock; + } + + return Status; } @@ -144,15 +148,19 @@ Mtftp4RrqSaveBlock ( UINT16 Block; UINT64 Start; UINT32 DataLen; + UINT64 BlockCounter; + BOOLEAN Completed; - Token = Instance->Token; - Block = NTOHS (Packet->Data.Block); - DataLen = Len - MTFTP4_DATA_HEAD_LEN; + Completed = FALSE; + Token = Instance->Token; + Block = NTOHS (Packet->Data.Block); + DataLen = Len - MTFTP4_DATA_HEAD_LEN; // // This is the last block, save the block no // if (DataLen < Instance->BlkSize) { + Completed = TRUE; Instance->LastBlock = Block; Mtftp4SetLastBlockNum (&Instance->Blocks, Block); } @@ -160,8 +168,11 @@ Mtftp4RrqSaveBlock ( // // Remove this block number from the file hole. If Mtftp4RemoveBlockNum // 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 BlockCounter is memorised as + // continuous block counter. // - Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block); + Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block, Completed, &BlockCounter); if (Status == EFI_NOT_FOUND) { return EFI_SUCCESS; @@ -184,7 +195,7 @@ Mtftp4RrqSaveBlock ( } if (Token->Buffer != NULL) { - Start = MultU64x32 (Block - 1, Instance->BlkSize); + Start = MultU64x32 (BlockCounter - 1, Instance->BlkSize); if (Start + DataLen <= Token->BufferSize) { CopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen); @@ -192,7 +203,7 @@ Mtftp4RrqSaveBlock ( // // Update the file size when received the last block // - if (Instance->LastBlock == Block) { + if ((Instance->LastBlock == Block) && Completed) { Token->BufferSize = Start + DataLen; } @@ -219,8 +230,8 @@ Mtftp4RrqSaveBlock ( /** - Function to process the received data packets. - + Function to process the received data packets. + It will save the block then send back an ACK if it is active. @param Instance The downloading MTFTP session @@ -248,19 +259,22 @@ Mtftp4RrqHandleData ( INTN Expected; *Completed = FALSE; + Status = EFI_SUCCESS; BlockNum = NTOHS (Packet->Data.Block); Expected = Mtftp4GetNextBlockNum (&Instance->Blocks); 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 (Master) and received an unexpected packet, transmit + // the ACK for the block we received, then restart receiving the + // expected one. If we are passive (Slave), save the block. // if (Instance->Master && (Expected != BlockNum)) { - Mtftp4Retransmit (Instance); - return EFI_SUCCESS; + // + // If Expected is 0, (UINT16) (Expected - 1) is also the expected Ack number (65535). + // + return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1)); } Status = Mtftp4RrqSaveBlock (Instance, Packet, Len); @@ -269,6 +283,11 @@ Mtftp4RrqHandleData ( return Status; } + // + // Record the total received and saved block number. + // + Instance->TotalBlock ++; + // // Reset the passive client's timer whenever it received a // valid data packet. @@ -300,16 +319,19 @@ Mtftp4RrqHandleData ( BlockNum = (UINT16) (Expected - 1); } - Mtftp4RrqSendAck (Instance, BlockNum); + if (Instance->WindowSize == (Instance->TotalBlock - Instance->AckedBlock) || Expected < 0) { + Status = Mtftp4RrqSendAck (Instance, BlockNum); + } + } - return EFI_SUCCESS; + return Status; } /** Validate whether the options received in the server's OACK packet is valid. - + The options are valid only if: 1. The server doesn't include options not requested by us 2. The server can only use smaller blksize than that is requested @@ -340,11 +362,13 @@ Mtftp4RrqOackValid ( } // - // Server can only specify a smaller block size to be used and + // Server can only specify a smaller block size and window size to be used and // return the timeout matches that requested. // if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0)&& (Reply->BlkSize > Request->BlkSize)) || - (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout))) { + (((Reply->Exist & MTFTP4_WINDOWSIZE_EXIST) != 0)&& (Reply->WindowSize > Request->WindowSize)) || + (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout)) + ) { return FALSE; } @@ -379,6 +403,7 @@ Mtftp4RrqOackValid ( **/ EFI_STATUS +EFIAPI Mtftp4RrqConfigMcastPort ( IN UDP_IO *McastIo, IN VOID *Context @@ -404,13 +429,13 @@ Mtftp4RrqConfigMcastPort ( UdpConfig.ReceiveTimeout = 0; UdpConfig.TransmitTimeout = 0; UdpConfig.UseDefaultAddress = Config->UseDefaultSetting; - UdpConfig.StationAddress = Config->StationIp; - UdpConfig.SubnetMask = Config->SubnetMask; + IP4_COPY_ADDRESS (&UdpConfig.StationAddress, &Config->StationIp); + IP4_COPY_ADDRESS (&UdpConfig.SubnetMask, &Config->SubnetMask); UdpConfig.StationPort = Instance->McastPort; UdpConfig.RemotePort = 0; Ip = HTONL (Instance->ServerIp); - CopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS)); + IP4_COPY_ADDRESS (&UdpConfig.RemoteAddress, &Ip); Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig); @@ -418,20 +443,20 @@ Mtftp4RrqConfigMcastPort ( return Status; } - if (!Config->UseDefaultSetting && + if (!Config->UseDefaultSetting && !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) { // // The station IP address is manually configured and the Gateway IP is not 0. // Add the default route for this UDP instance. // Status = McastIo->Protocol.Udp4->Routes ( - McastIo->Protocol.Udp4, + McastIo->Protocol.Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &Config->GatewayIp ); - + if (EFI_ERROR (Status)) { McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL); return Status; @@ -442,15 +467,15 @@ Mtftp4RrqConfigMcastPort ( // join the multicast group // Ip = HTONL (Instance->McastIp); - CopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS)); + IP4_COPY_ADDRESS (&Group, &Ip); return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group); } /** - Function to process the OACK. - + Function to process the OACK. + It will first validate the OACK packet, then update the various negotiated parameters. @param Instance The download MTFTP session @@ -477,6 +502,7 @@ Mtftp4RrqHandleOack ( MTFTP4_OPTION Reply; EFI_STATUS Status; INTN Expected; + EFI_UDP4_PROTOCOL *Udp4; *Completed = FALSE; @@ -496,7 +522,7 @@ Mtftp4RrqHandleOack ( // ZeroMem (&Reply, sizeof (MTFTP4_OPTION)); - Status = Mtftp4ParseOptionOack (Packet, Len, &Reply); + Status = Mtftp4ParseOptionOack (Packet, Len, Instance->Operation, &Reply); if (EFI_ERROR (Status) || !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) { @@ -518,7 +544,7 @@ Mtftp4RrqHandleOack ( // // 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->Master = Reply.Master; @@ -539,13 +565,31 @@ Mtftp4RrqHandleOack ( // Instance->McastIp = Reply.McastIp; Instance->McastPort = Reply.McastPort; - Instance->McastUdpPort = UdpIoCreateIo ( - Instance->Service->Controller, - Instance->Service->Image, - Mtftp4RrqConfigMcastPort, - UDP_IO_UDP4_VERSION, - Instance - ); + if (Instance->McastUdpPort == NULL) { + Instance->McastUdpPort = UdpIoCreateIo ( + Instance->Service->Controller, + Instance->Service->Image, + Mtftp4RrqConfigMcastPort, + UDP_IO_UDP4_VERSION, + Instance + ); + if (Instance->McastUdpPort != NULL) { + Status = gBS->OpenProtocol ( + Instance->McastUdpPort->UdpHandle, + &gEfiUdp4ProtocolGuid, + (VOID **) &Udp4, + Instance->Service->Image, + Instance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + UdpIoFreeIo (Instance->McastUdpPort); + Instance->McastUdpPort = NULL; + return EFI_DEVICE_ERROR; + } + } + } + if (Instance->McastUdpPort == NULL) { return EFI_DEVICE_ERROR; @@ -562,31 +606,39 @@ Mtftp4RrqHandleOack ( return Status; } - + // // Update the parameters used. // if (Reply.BlkSize != 0) { Instance->BlkSize = Reply.BlkSize; } - + + if (Reply.WindowSize != 0) { + Instance->WindowSize = Reply.WindowSize; + } + if (Reply.Timeout != 0) { Instance->Timeout = Reply.Timeout; - } - } - + } + } + } else { Instance->Master = TRUE; - + if (Reply.BlkSize != 0) { Instance->BlkSize = Reply.BlkSize; } + if (Reply.WindowSize != 0) { + Instance->WindowSize = Reply.WindowSize; + } + if (Reply.Timeout != 0) { Instance->Timeout = Reply.Timeout; } } - + // // Send an ACK to (Expected - 1) which is 0 for unicast download, // or tell the server we want to receive the Expected block. @@ -605,6 +657,7 @@ Mtftp4RrqHandleOack ( **/ VOID +EFIAPI Mtftp4RrqInput ( IN NET_BUF *UdpPacket, IN UDP_END_POINT *EndPoint, @@ -675,6 +728,7 @@ Mtftp4RrqInput ( } else { Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL); + ASSERT (Packet != NULL); } Opcode = NTOHS (Packet->OpCode); @@ -731,7 +785,7 @@ Mtftp4RrqInput ( case EFI_MTFTP4_OPCODE_ERROR: Status = EFI_TFTP_ERROR; break; - + default: break; }