Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15693 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			605 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			605 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Mtftp6 Wrq process functions implementation.
 | |
| 
 | |
|   Copyright (c) 2009 - 2014, 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.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Mtftp6Impl.h"
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Build and send a Mtftp6 data packet for upload.
 | |
| 
 | |
|   @param[in]  Instance              The pointer to the Mtftp6 instance.
 | |
|   @param[in]  BlockNum              The block num to be sent.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the packet.
 | |
|   @retval EFI_SUCCESS           The data packet was sent.
 | |
|   @retval EFI_ABORTED           The user aborted this process.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Mtftp6WrqSendBlock (
 | |
|   IN MTFTP6_INSTANCE        *Instance,
 | |
|   IN UINT16                 BlockNum
 | |
|   )
 | |
| {
 | |
|   EFI_MTFTP6_PACKET         *Packet;
 | |
|   EFI_MTFTP6_TOKEN          *Token;
 | |
|   NET_BUF                   *UdpPacket;
 | |
|   EFI_STATUS                Status;
 | |
|   UINT16                    DataLen;
 | |
|   UINT8                     *DataBuf;
 | |
|   UINT64                    Start;
 | |
| 
 | |
|   //
 | |
|   // Allocate net buffer to create data packet.
 | |
|   //
 | |
|   UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP6_DATA_HEAD_LEN);
 | |
| 
 | |
|   if (UdpPacket == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Packet = (EFI_MTFTP6_PACKET *) NetbufAllocSpace (
 | |
|                                    UdpPacket,
 | |
|                                    MTFTP6_DATA_HEAD_LEN,
 | |
|                                    FALSE
 | |
|                                    );
 | |
|   ASSERT (Packet != NULL);
 | |
| 
 | |
|   Packet->Data.OpCode = HTONS (EFI_MTFTP6_OPCODE_DATA);
 | |
|   Packet->Data.Block  = HTONS (BlockNum);
 | |
| 
 | |
|   //
 | |
|   // Read the block from either the buffer or PacketNeeded callback
 | |
|   //
 | |
|   Token   = Instance->Token;
 | |
|   DataLen = Instance->BlkSize;
 | |
| 
 | |
|   if (Token->Buffer != NULL) {
 | |
|     Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
 | |
| 
 | |
|     if (Token->BufferSize < Start + Instance->BlkSize) {
 | |
|       DataLen           = (UINT16) (Token->BufferSize - Start);
 | |
|       Instance->LastBlk = BlockNum;
 | |
|       Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
 | |
|     }
 | |
| 
 | |
|     if (DataLen > 0) {
 | |
|       NetbufAllocSpace (UdpPacket, DataLen, FALSE);
 | |
|       CopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
|     //
 | |
|     // Get data from PacketNeeded
 | |
|     //
 | |
|     DataBuf = NULL;
 | |
|     Status  = Token->PacketNeeded (&Instance->Mtftp6, Token, &DataLen, (VOID*) &DataBuf);
 | |
| 
 | |
|     if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
 | |
|       if (DataBuf != NULL) {
 | |
|         gBS->FreePool (DataBuf);
 | |
|       }
 | |
|       //
 | |
|       // The received packet has already been freed.
 | |
|       //
 | |
|       Mtftp6SendError (
 | |
|         Instance,
 | |
|         EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
 | |
|         (UINT8 *) "User aborted the transfer"
 | |
|         );
 | |
| 
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     if (DataLen < Instance->BlkSize) {
 | |
|       Instance->LastBlk = BlockNum;
 | |
|       Mtftp6SetLastBlockNum (&Instance->BlkList, BlockNum);
 | |
|     }
 | |
| 
 | |
|     if (DataLen > 0) {
 | |
|       NetbufAllocSpace (UdpPacket, DataLen, FALSE);
 | |
|       CopyMem (Packet->Data.Data, DataBuf, DataLen);
 | |
|       gBS->FreePool (DataBuf);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Reset current retry count of the instance.
 | |
|   //
 | |
|   Instance->CurRetry = 0;
 | |
| 
 | |
|   return Mtftp6TransmitPacket (Instance, UdpPacket);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Function to handle received ACK packet. If the ACK number matches the
 | |
|   expected block number, with more data pending, send the next
 | |
|   block. Otherwise, tell the caller that we are done.
 | |
| 
 | |
|   @param[in]  Instance              The pointer to the Mtftp6 instance.
 | |
|   @param[in]  Packet                The pointer to the received packet.
 | |
|   @param[in]  Len                   The length of the packet.
 | |
|   @param[out] UdpPacket             The net buf of received packet.
 | |
|   @param[out] IsCompleted           If TRUE, the upload has been completed.
 | |
|                                     Otherwise, the upload has not been completed.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The ACK packet successfully processed.
 | |
|   @retval EFI_TFTP_ERROR        The block number loops back.
 | |
|   @retval Others                Failed to transmit the next data packet.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Mtftp6WrqHandleAck (
 | |
|   IN  MTFTP6_INSTANCE       *Instance,
 | |
|   IN  EFI_MTFTP6_PACKET     *Packet,
 | |
|   IN  UINT32                Len,
 | |
|   OUT NET_BUF               **UdpPacket,
 | |
|   OUT BOOLEAN               *IsCompleted
 | |
|   )
 | |
| {
 | |
|   UINT16                    AckNum;
 | |
|   INTN                      Expected;
 | |
|   UINT64                    TotalBlock;
 | |
| 
 | |
|   *IsCompleted = FALSE;
 | |
|   AckNum       = NTOHS (Packet->Ack.Block[0]);
 | |
|   Expected     = Mtftp6GetNextBlockNum (&Instance->BlkList);
 | |
| 
 | |
|   ASSERT (Expected >= 0);
 | |
| 
 | |
|   //
 | |
|   // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp6WrqInput
 | |
|   // restart receive.
 | |
|   //
 | |
|   if (Expected != AckNum) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove the acked block number, if this is the last block number,
 | |
|   // tell the Mtftp6WrqInput to finish the transfer. This is the last
 | |
|   // block number if the block range are empty..
 | |
|   //
 | |
|   Mtftp6RemoveBlockNum (&Instance->BlkList, AckNum, *IsCompleted, &TotalBlock);
 | |
| 
 | |
|   Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
 | |
| 
 | |
|   if (Expected < 0) {
 | |
|     //
 | |
|     // The block range is empty. It may either because the the last
 | |
|     // block has been ACKed, or the sequence number just looped back,
 | |
|     // that is, there is more than 0xffff blocks.
 | |
|     //
 | |
|     if (Instance->LastBlk == AckNum) {
 | |
|       ASSERT (Instance->LastBlk >= 1);
 | |
|       *IsCompleted = TRUE;
 | |
|       return EFI_SUCCESS;
 | |
| 
 | |
|     } else {
 | |
|       //
 | |
|       // Free the received packet before send new packet in ReceiveNotify,
 | |
|       // since the udpio might need to be reconfigured.
 | |
|       //
 | |
|       NetbufFree (*UdpPacket);
 | |
|       *UdpPacket = NULL;
 | |
|       //
 | |
|       // Send the Mtftp6 error message if block number rolls back.
 | |
|       //
 | |
|       Mtftp6SendError (
 | |
|         Instance,
 | |
|         EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
 | |
|         (UINT8 *) "Block number rolls back, not supported, try blksize option"
 | |
|         );
 | |
| 
 | |
|       return EFI_TFTP_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free the receive buffer before send new packet since it might need
 | |
|   // reconfigure udpio.
 | |
|   //
 | |
|   NetbufFree (*UdpPacket);
 | |
|   *UdpPacket = NULL;
 | |
| 
 | |
|   return Mtftp6WrqSendBlock (Instance, (UINT16) Expected);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check whether the received OACK is valid. The OACK is valid
 | |
|   only if:
 | |
|   1. It only include options requested by us.
 | |
|   2. It can only include a smaller block size.
 | |
|   3. It can't change the proposed time out value.
 | |
|   4. Other requirements of the individal MTFTP6 options as required.
 | |
| 
 | |
|   @param[in]  ReplyInfo             The pointer to options information in reply packet.
 | |
|   @param[in]  RequestInfo           The pointer to requested options information.
 | |
| 
 | |
|   @retval     TRUE                  If the option in OACK is valid.
 | |
|   @retval     FALSE                 If the option is invalid.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| Mtftp6WrqOackValid (
 | |
|   IN MTFTP6_EXT_OPTION_INFO     *ReplyInfo,
 | |
|   IN MTFTP6_EXT_OPTION_INFO     *RequestInfo
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // It is invalid for server to return options we don't request
 | |
|   //
 | |
|   if ((ReplyInfo->BitMap & ~RequestInfo->BitMap) != 0) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Server can only specify a smaller block size 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_TIMEOUT_BIT) != 0) && (ReplyInfo->Timeout != RequestInfo->Timeout))
 | |
|       ) {
 | |
| 
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the OACK packet for Wrq.
 | |
| 
 | |
|   @param[in]  Instance              The pointer to the Mtftp6 instance.
 | |
|   @param[in]  Packet                The pointer to the received packet.
 | |
|   @param[in]  Len                   The length of the packet.
 | |
|   @param[out] UdpPacket             The net buf of received packet.
 | |
|   @param[out] IsCompleted           If TRUE, the upload has been completed.
 | |
|                                     Otherwise, the upload has not been completed.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The OACK packet successfully processed.
 | |
|   @retval EFI_TFTP_ERROR        An TFTP communication error happened.
 | |
|   @retval Others                Failed to process the OACK packet.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Mtftp6WrqHandleOack (
 | |
|   IN  MTFTP6_INSTANCE       *Instance,
 | |
|   IN  EFI_MTFTP6_PACKET     *Packet,
 | |
|   IN  UINT32                Len,
 | |
|   OUT NET_BUF               **UdpPacket,
 | |
|   OUT BOOLEAN               *IsCompleted
 | |
|   )
 | |
| {
 | |
|   EFI_MTFTP6_OPTION         *Options;
 | |
|   UINT32                    Count;
 | |
|   MTFTP6_EXT_OPTION_INFO    ExtInfo;
 | |
|   EFI_MTFTP6_PACKET         Dummy;
 | |
|   EFI_STATUS                Status;
 | |
|   INTN                      Expected;
 | |
| 
 | |
|   *IsCompleted = FALSE;
 | |
|   Options = NULL;
 | |
| 
 | |
|   //
 | |
|   // Ignore the OACK if already started the upload
 | |
|   //
 | |
|   Expected = Mtftp6GetNextBlockNum (&Instance->BlkList);
 | |
| 
 | |
|   if (Expected != 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Parse and validate the options from server
 | |
|   //
 | |
|   ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));
 | |
| 
 | |
|   Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   ASSERT (Options != NULL);
 | |
| 
 | |
|   Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &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.
 | |
|     //
 | |
|     if (Status != EFI_OUT_OF_RESOURCES) {
 | |
|       //
 | |
|       // Free the received packet before send new packet in ReceiveNotify,
 | |
|       // since the udpio might need to be reconfigured.
 | |
|       //
 | |
|       NetbufFree (*UdpPacket);
 | |
|       *UdpPacket = NULL;
 | |
|       //
 | |
|       // Send the Mtftp6 error message if invalid Oack packet received.
 | |
|       //
 | |
|       Mtftp6SendError (
 | |
|         Instance,
 | |
|         EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
 | |
|         (UINT8 *) "Mal-formated OACK packet"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     return EFI_TFTP_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (ExtInfo.BlkSize != 0) {
 | |
|     Instance->BlkSize = ExtInfo.BlkSize;
 | |
|   }
 | |
| 
 | |
|   if (ExtInfo.Timeout != 0) {
 | |
|     Instance->Timeout = ExtInfo.Timeout;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Build a bogus ACK0 packet then pass it to the Mtftp6WrqHandleAck,
 | |
|   // which will start the transmission of the first data block.
 | |
|   //
 | |
|   Dummy.Ack.OpCode   = HTONS (EFI_MTFTP6_OPCODE_ACK);
 | |
|   Dummy.Ack.Block[0] = 0;
 | |
| 
 | |
|   return Mtftp6WrqHandleAck (
 | |
|            Instance,
 | |
|            &Dummy,
 | |
|            sizeof (EFI_MTFTP6_ACK_HEADER),
 | |
|            UdpPacket,
 | |
|            IsCompleted
 | |
|            );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   The packet process callback for Mtftp6 upload.
 | |
| 
 | |
|   @param[in]  UdpPacket             The pointer to the packet received.
 | |
|   @param[in]  UdpEpt                The pointer to the Udp6 access point.
 | |
|   @param[in]  IoStatus              The status from Udp6 instance.
 | |
|   @param[in]  Context               The pointer to the context.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| Mtftp6WrqInput (
 | |
|   IN NET_BUF                *UdpPacket,
 | |
|   IN UDP_END_POINT          *UdpEpt,
 | |
|   IN EFI_STATUS             IoStatus,
 | |
|   IN VOID                   *Context
 | |
|   )
 | |
| {
 | |
|   MTFTP6_INSTANCE           *Instance;
 | |
|   EFI_MTFTP6_PACKET         *Packet;
 | |
|   BOOLEAN                   IsCompleted;
 | |
|   EFI_STATUS                Status;
 | |
|   UINT32                    TotalNum;
 | |
|   UINT32                    Len;
 | |
|   UINT16                    Opcode;
 | |
| 
 | |
|   Instance = (MTFTP6_INSTANCE *) Context;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);
 | |
| 
 | |
|   IsCompleted = FALSE;
 | |
|   Packet      = NULL;
 | |
|   Status      = EFI_SUCCESS;
 | |
|   TotalNum    = 0;
 | |
| 
 | |
|   //
 | |
|   // Return error status if Udp6 instance failed to receive.
 | |
|   //
 | |
|   if (EFI_ERROR (IoStatus)) {
 | |
|     Status = IoStatus;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   ASSERT (UdpPacket != NULL);
 | |
| 
 | |
|   if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Client send initial request to server's listening port. Server
 | |
|   // will select a UDP port to communicate with the client.
 | |
|   //
 | |
|   if (UdpEpt->RemotePort != Instance->ServerDataPort) {
 | |
|     if (Instance->ServerDataPort != 0) {
 | |
|       goto ON_EXIT;
 | |
|     } else {
 | |
|       Instance->ServerDataPort = UdpEpt->RemotePort;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Copy the MTFTP packet to a continuous buffer if it isn't already so.
 | |
|   //
 | |
|   Len      = UdpPacket->TotalSize;
 | |
|   TotalNum = UdpPacket->BlockOpNum;
 | |
| 
 | |
|   if (TotalNum > 1) {
 | |
|     Packet = AllocateZeroPool (Len);
 | |
| 
 | |
|     if (Packet == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
 | |
| 
 | |
|   } else {
 | |
|     Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
 | |
|     ASSERT (Packet != NULL);
 | |
|   }
 | |
| 
 | |
|   Opcode = NTOHS (Packet->OpCode);
 | |
| 
 | |
|   //
 | |
|   // Callback to the user's CheckPacket if provided. Abort the transmission
 | |
|   // if CheckPacket returns an EFI_ERROR code.
 | |
|   //
 | |
|   if (Instance->Token->CheckPacket != NULL &&
 | |
|       (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR)
 | |
|       ) {
 | |
| 
 | |
|     Status = Instance->Token->CheckPacket (
 | |
|                                 &Instance->Mtftp6,
 | |
|                                 Instance->Token,
 | |
|                                 (UINT16) Len,
 | |
|                                 Packet
 | |
|                                 );
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Send an error message to the server to inform it
 | |
|       //
 | |
|       if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
 | |
|         //
 | |
|         // Free the received packet before send new packet in ReceiveNotify,
 | |
|         // since the udpio might need to be reconfigured.
 | |
|         //
 | |
|         NetbufFree (UdpPacket);
 | |
|         UdpPacket = NULL;
 | |
|         //
 | |
|         // Send the Mtftp6 error message if user aborted the current session.
 | |
|         //
 | |
|         Mtftp6SendError (
 | |
|           Instance,
 | |
|           EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
 | |
|           (UINT8 *) "User aborted the transfer"
 | |
|           );
 | |
|       }
 | |
| 
 | |
|       Status = EFI_ABORTED;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Switch the process routines by the operation code.
 | |
|   //
 | |
|   switch (Opcode) {
 | |
|   case EFI_MTFTP6_OPCODE_ACK:
 | |
|     if (Len != MTFTP6_OPCODE_LEN + MTFTP6_BLKNO_LEN) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     //
 | |
|     // Handle the Ack packet of Wrq.
 | |
|     //
 | |
|     Status = Mtftp6WrqHandleAck (Instance, Packet, Len, &UdpPacket, &IsCompleted);
 | |
|     break;
 | |
| 
 | |
|   case EFI_MTFTP6_OPCODE_OACK:
 | |
|     if (Len <= MTFTP6_OPCODE_LEN) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     //
 | |
|     // Handle the Oack packet of Wrq.
 | |
|     //
 | |
|     Status = Mtftp6WrqHandleOack (Instance, Packet, Len, &UdpPacket, &IsCompleted);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     //
 | |
|     // Drop and return eror if received error message.
 | |
|     //
 | |
|     Status = EFI_TFTP_ERROR;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   //
 | |
|   // Free the resources, then if !EFI_ERROR (Status) and not completed,
 | |
|   // restart the receive, otherwise end the session.
 | |
|   //
 | |
|   if (Packet != NULL && TotalNum > 1) {
 | |
|     FreePool (Packet);
 | |
|   }
 | |
| 
 | |
|   if (UdpPacket != NULL) {
 | |
|     NetbufFree (UdpPacket);
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (Status) && !IsCompleted) {
 | |
|     Status = UdpIoRecvDatagram (
 | |
|                Instance->UdpIo,
 | |
|                Mtftp6WrqInput,
 | |
|                Instance,
 | |
|                0
 | |
|                );
 | |
|   }
 | |
|   //
 | |
|   // Clean up the current session if failed to continue.
 | |
|   //
 | |
|   if (EFI_ERROR (Status) || IsCompleted) {
 | |
|     Mtftp6OperationClean (Instance, Status);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start the Mtftp6 instance to upload. It will first init some states,
 | |
|   then send the WRQ request packet, and start to receive the packet.
 | |
| 
 | |
|   @param[in]  Instance              The pointer to the Mtftp6 instance.
 | |
|   @param[in]  Operation             The operation code of the current packet.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The Mtftp6 was started to upload.
 | |
|   @retval Others                Failed to start to upload.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Mtftp6WrqStart (
 | |
|   IN MTFTP6_INSTANCE        *Instance,
 | |
|   IN UINT16                 Operation
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   //
 | |
|   // The valid block number range are [0, 0xffff]. For example:
 | |
|   // the client sends an WRQ request to the server, the server
 | |
|   // ACK with an ACK0 to let client start transfer the first
 | |
|   // packet.
 | |
|   //
 | |
|   Status = Mtftp6InitBlockRange (&Instance->BlkList, 0, 0xffff);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = Mtftp6SendRequest (Instance, Operation);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return UdpIoRecvDatagram (
 | |
|            Instance->UdpIo,
 | |
|            Mtftp6WrqInput,
 | |
|            Instance,
 | |
|            0
 | |
|            );
 | |
| }
 | |
| 
 |