X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FNetwork%2FMtftp4Dxe%2FMtftp4Rrq.c;h=24c965afb5807771b1bbb8b520d0fce5189171ef;hp=f226ac0085e5da6724d5740d06d66607b7906d00;hb=c0fd7f734e2d33e22215899b40a47b843129541d;hpb=e48e37fce2611df7a52aff271835ff72ee396d9b diff --git a/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c b/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c index f226ac0085..24c965afb5 100644 --- a/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c +++ b/MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c @@ -1,40 +1,40 @@ /** @file + Routines to process Rrq (download). -Copyright (c) 2006 - 2007, 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 +(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 -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ -Module Name: - Mtftp4Rrq.c +#include "Mtftp4Impl.h" -Abstract: - Routines to process Rrq (download) +/** + The packet process callback for MTFTP download. + @param UdpPacket The packet received + @param EndPoint The local/remote access point of the packet + @param IoStatus The status of the receiving + @param Context Opaque parameter, which is the MTFTP session **/ - -#include "Mtftp4Impl.h" - VOID +EFIAPI Mtftp4RrqInput ( IN NET_BUF *UdpPacket, - IN UDP_POINTS *Points, + IN UDP_END_POINT *EndPoint, IN EFI_STATUS IoStatus, IN VOID *Context ); /** - 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. + 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 @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ @@ -93,9 +93,11 @@ Mtftp4RrqSendAck ( { EFI_MTFTP4_PACKET *Ack; NET_BUF *Packet; + EFI_STATUS Status; - Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER)); + Status = EFI_SUCCESS; + Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER)); if (Packet == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -105,11 +107,17 @@ Mtftp4RrqSendAck ( sizeof (EFI_MTFTP4_ACK_HEADER), FALSE ); + ASSERT (Ack != NULL); 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; } @@ -130,9 +138,9 @@ Mtftp4RrqSendAck ( **/ EFI_STATUS Mtftp4RrqSaveBlock ( - IN MTFTP4_PROTOCOL *Instance, - IN EFI_MTFTP4_PACKET *Packet, - IN UINT32 Len + IN OUT MTFTP4_PROTOCOL *Instance, + IN EFI_MTFTP4_PACKET *Packet, + IN UINT32 Len ) { EFI_MTFTP4_TOKEN *Token; @@ -140,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); } @@ -156,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; @@ -180,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); @@ -188,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; } @@ -215,8 +230,9 @@ Mtftp4RrqSaveBlock ( /** - Function to process the received data packets. It will save the block - then send back an ACK if it is active. + 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 @param Packet The packet received @@ -231,11 +247,11 @@ Mtftp4RrqSaveBlock ( **/ EFI_STATUS Mtftp4RrqHandleData ( - IN MTFTP4_PROTOCOL *Instance, - IN EFI_MTFTP4_PACKET *Packet, - IN UINT32 Len, - IN BOOLEAN Multicast, - OUT BOOLEAN *Completed + IN MTFTP4_PROTOCOL *Instance, + IN EFI_MTFTP4_PACKET *Packet, + IN UINT32 Len, + IN BOOLEAN Multicast, + OUT BOOLEAN *Completed ) { EFI_STATUS Status; @@ -243,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); @@ -264,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. @@ -295,15 +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 @@ -314,7 +342,8 @@ Mtftp4RrqHandleData ( @param Reply The options in the OACK packet @param Request The requested options - @return TRUE if the options in the OACK is OK, otherwise FALSE. + @retval TRUE The options in the OACK is OK. + @retval FALSE The options in the OACK is invalid. **/ BOOLEAN @@ -333,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) && (Reply->BlkSize > Request->BlkSize)) || - ((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) { + if ((((Reply->Exist & MTFTP4_BLKSIZE_EXIST) != 0)&& (Reply->BlkSize > Request->BlkSize)) || + (((Reply->Exist & MTFTP4_WINDOWSIZE_EXIST) != 0)&& (Reply->WindowSize > Request->WindowSize)) || + (((Reply->Exist & MTFTP4_TIMEOUT_EXIST) != 0) && (Reply->Timeout != Request->Timeout)) + ) { return FALSE; } @@ -346,7 +377,7 @@ Mtftp4RrqOackValid ( // setting. But if it use the specific multicast channel, it can't // change the setting. // - if ((Reply->Exist & MTFTP4_MCAST_EXIST) && (This->McastIp != 0)) { + if (((Reply->Exist & MTFTP4_MCAST_EXIST) != 0) && (This->McastIp != 0)) { if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) { return FALSE; } @@ -363,18 +394,18 @@ Mtftp4RrqOackValid ( /** Configure a UDP IO port to receive the multicast. - @param McastIo The UDP IO port to configure + @param McastIo The UDP IO to configure @param Context The opaque parameter to the function which is the MTFTP session. - @retval EFI_SUCCESS The udp child is successfully configured. + @retval EFI_SUCCESS The UDP child is successfully configured. @retval Others Failed to configure the UDP child. **/ -STATIC EFI_STATUS +EFIAPI Mtftp4RrqConfigMcastPort ( - IN UDP_IO_PORT *McastIo, + IN UDP_IO *McastIo, IN VOID *Context ) { @@ -398,28 +429,36 @@ 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->Udp->Configure (McastIo->Udp, &UdpConfig); + Status = McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, &UdpConfig); if (EFI_ERROR (Status)) { return Status; } - if (!Config->UseDefaultSetting && !EFI_IP4_EQUAL (&mZeroIp4Addr, &Config->GatewayIp)) { + 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->Udp->Routes (McastIo->Udp, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &Config->GatewayIp); + Status = McastIo->Protocol.Udp4->Routes ( + McastIo->Protocol.Udp4, + FALSE, + &mZeroIp4Addr, + &mZeroIp4Addr, + &Config->GatewayIp + ); + if (EFI_ERROR (Status)) { - McastIo->Udp->Configure (McastIo->Udp, NULL); + McastIo->Protocol.Udp4->Configure (McastIo->Protocol.Udp4, NULL); return Status; } } @@ -428,15 +467,16 @@ Mtftp4RrqConfigMcastPort ( // join the multicast group // Ip = HTONL (Instance->McastIp); - CopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS)); + IP4_COPY_ADDRESS (&Group, &Ip); - return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group); + return McastIo->Protocol.Udp4->Groups (McastIo->Protocol.Udp4, TRUE, &Group); } /** - Function to process the OACK. It will first validate the OACK - packet, then update the various negotiated parameters. + Function to process the OACK. + + It will first validate the OACK packet, then update the various negotiated parameters. @param Instance The download MTFTP session @param Packet The packet received @@ -452,16 +492,17 @@ Mtftp4RrqConfigMcastPort ( **/ EFI_STATUS Mtftp4RrqHandleOack ( - IN MTFTP4_PROTOCOL *Instance, - IN EFI_MTFTP4_PACKET *Packet, - IN UINT32 Len, - IN BOOLEAN Multicast, - OUT BOOLEAN *Completed + IN OUT MTFTP4_PROTOCOL *Instance, + IN EFI_MTFTP4_PACKET *Packet, + IN UINT32 Len, + IN BOOLEAN Multicast, + OUT BOOLEAN *Completed ) { MTFTP4_OPTION Reply; EFI_STATUS Status; INTN Expected; + EFI_UDP4_PROTOCOL *Udp4; *Completed = FALSE; @@ -481,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)) { @@ -499,11 +540,11 @@ Mtftp4RrqHandleOack ( return EFI_TFTP_ERROR; } - if (Reply.Exist & MTFTP4_MCAST_EXIST) { + if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 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->Master = Reply.Master; @@ -524,12 +565,31 @@ Mtftp4RrqHandleOack ( // Instance->McastIp = Reply.McastIp; Instance->McastPort = Reply.McastPort; - Instance->McastUdpPort = UdpIoCreatePort ( - Instance->Service->Controller, - Instance->Service->Image, - Mtftp4RrqConfigMcastPort, - 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; @@ -546,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. @@ -583,17 +651,16 @@ Mtftp4RrqHandleOack ( The packet process callback for MTFTP download. @param UdpPacket The packet received - @param Points The local/remote access point of the packet + @param EndPoint The local/remote access point of the packet @param IoStatus The status of the receiving @param Context Opaque parameter, which is the MTFTP session - @return None - **/ VOID +EFIAPI Mtftp4RrqInput ( IN NET_BUF *UdpPacket, - IN UDP_POINTS *Points, + IN UDP_END_POINT *EndPoint, IN EFI_STATUS IoStatus, IN VOID *Context ) @@ -624,7 +691,7 @@ Mtftp4RrqInput ( // // Find the port this packet is from to restart receive correctly. // - Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp); + Multicast = (BOOLEAN) (EndPoint->LocalAddr.Addr[0] == Instance->McastIp); if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) { goto ON_EXIT; @@ -636,11 +703,11 @@ Mtftp4RrqInput ( // is required to use the same port as RemotePort to multicast the // data. // - if (Points->RemotePort != Instance->ConnectedPort) { + if (EndPoint->RemotePort != Instance->ConnectedPort) { if (Instance->ConnectedPort != 0) { goto ON_EXIT; } else { - Instance->ConnectedPort = Points->RemotePort; + Instance->ConnectedPort = EndPoint->RemotePort; } } @@ -661,6 +728,7 @@ Mtftp4RrqInput ( } else { Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL); + ASSERT (Packet != NULL); } Opcode = NTOHS (Packet->OpCode); @@ -717,6 +785,9 @@ Mtftp4RrqInput ( case EFI_MTFTP4_OPCODE_ERROR: Status = EFI_TFTP_ERROR; break; + + default: + break; } ON_EXIT: @@ -726,7 +797,7 @@ ON_EXIT: // receive, otherwise end the session. // if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) { - gBS->FreePool (Packet); + FreePool (Packet); } if (UdpPacket != NULL) {