Changed old event definitions reference to these new event definitions. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2729 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2380 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2380 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| 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
 | |
| 
 | |
| 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:
 | |
| 
 | |
|     pxe_bc_mtftp.c
 | |
| 
 | |
| Abstract:
 | |
|   TFTP and MTFTP (multicast TFTP) implementation.
 | |
| 
 | |
| Revision History
 | |
| 
 | |
| --*/
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // The following #define is used to create a version that does not wait to
 | |
| // open after a listen.  This is just for a special regression test of MTFTP
 | |
| // server to make sure multiple opens are handled correctly.  Normally this
 | |
| // next line should be a comment.
 | |
| // #define SpecialNowaitVersion    // comment out for normal operation
 | |
| //
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| 
 | |
| #include "Bc.h"
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| UINT64
 | |
| Swap64 (
 | |
|   UINT64 n
 | |
|   )
 | |
| {
 | |
|   union {
 | |
|     UINT64  n;
 | |
|     UINT8   b[8];
 | |
|   } u;
 | |
| 
 | |
|   UINT8 t;
 | |
| 
 | |
|   u.n     = n;
 | |
| 
 | |
|   t       = u.b[0];
 | |
|   u.b[0]  = u.b[7];
 | |
|   u.b[7]  = t;
 | |
| 
 | |
|   t       = u.b[1];
 | |
|   u.b[1]  = u.b[6];
 | |
|   u.b[6]  = t;
 | |
| 
 | |
|   t       = u.b[2];
 | |
|   u.b[2]  = u.b[5];
 | |
|   u.b[5]  = t;
 | |
| 
 | |
|   t       = u.b[3];
 | |
|   u.b[3]  = u.b[4];
 | |
|   u.b[4]  = t;
 | |
| 
 | |
|   return u.n;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| TftpUdpRead (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   UINT16                      Operation,
 | |
|   VOID                        *HeaderPtr,
 | |
|   UINTN                       *BufferSizePtr,
 | |
|   VOID                        *BufferPtr,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_IP_ADDRESS              *OurIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *OurPortPtr,
 | |
|   UINT16                      Timeout
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Read TFTP packet.  If TFTP ERROR packet is read, fill in TFTP error
 | |
|   information in Mode structure and return TFTP_ERROR status.
 | |
| 
 | |
| Parameters:
 | |
|   Private :=
 | |
|   Operation :=
 | |
|   HeaderPtr :=
 | |
|   BufferSizePtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr :=
 | |
|   ServerPortPtr :=
 | |
|   OurIpPtr :=
 | |
|   OurPortPtr :=
 | |
|   Timeout :=
 | |
| 
 | |
| Returns:
 | |
|   EFI_SUCCESS :=
 | |
|   EFI_TFTP_ERROR :=
 | |
|   other :=
 | |
| --*/
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_MODE  *PxeBcMode;
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_EVENT               TimeoutEvent;
 | |
|   UINTN                   HeaderSize;
 | |
| 
 | |
|   //
 | |
|   //
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_TIMER,
 | |
|                   TPL_CALLBACK,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   &TimeoutEvent
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->SetTimer (
 | |
|                   TimeoutEvent,
 | |
|                   TimerRelative,
 | |
|                   Timeout * 10000000 + 1000000
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   //
 | |
|   //
 | |
|   HeaderSize = Private->BigBlkNumFlag ? sizeof (struct Tftpv4Ack8) : sizeof (struct Tftpv4Ack);
 | |
| 
 | |
| #define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
 | |
| 
 | |
|   Status = UdpRead (
 | |
|             Private,
 | |
|             Operation,
 | |
|             OurIpPtr,
 | |
|             OurPortPtr,
 | |
|             ServerIpPtr,
 | |
|             ServerPortPtr,
 | |
|             &HeaderSize,
 | |
|             HeaderPtr,
 | |
|             BufferSizePtr,
 | |
|             BufferPtr,
 | |
|             TimeoutEvent
 | |
|             );
 | |
| 
 | |
|   if (Status != EFI_SUCCESS || ERROR_MESSAGE_PTR->OpCode != HTONS (TFTP_ERROR)) {
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // got an error packet
 | |
|   // write one byte error code followed by error message
 | |
|   //
 | |
|   PxeBcMode                       = Private->EfiBc.Mode;
 | |
|   PxeBcMode->TftpErrorReceived    = TRUE;
 | |
|   PxeBcMode->TftpError.ErrorCode  = (UINT8) NTOHS (ERROR_MESSAGE_PTR->ErrCode);
 | |
|   HeaderSize                      = EFI_MIN (*BufferSizePtr, sizeof PxeBcMode->TftpError.ErrorString);
 | |
|   CopyMem (PxeBcMode->TftpError.ErrorString, BufferPtr, HeaderSize);
 | |
| 
 | |
|   gBS->CloseEvent (TimeoutEvent);
 | |
|   return EFI_TFTP_ERROR;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| VOID
 | |
| SendError (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *OurPortPtr
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Send TFTP ERROR message to TFTP server
 | |
| 
 | |
| Parameters:
 | |
|   Private :=
 | |
|   ServerIpPtr :=
 | |
|   ServerPortPtr :=
 | |
|   OurPortPtr :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   struct Tftpv4Error  *ErrStr;
 | |
|   UINTN               Len;
 | |
| 
 | |
|   ErrStr            = (VOID *) Private->TftpErrorBuffer;
 | |
|   Len               = sizeof *ErrStr;
 | |
| 
 | |
|   ErrStr->OpCode    = HTONS (TFTP_ERROR);
 | |
|   ErrStr->ErrCode   = HTONS (TFTP_ERR_OPTION);
 | |
|   ErrStr->ErrMsg[0] = 0;
 | |
| 
 | |
|   UdpWrite (
 | |
|     Private,
 | |
|     EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
 | |
|     ServerIpPtr,
 | |
|     ServerPortPtr,
 | |
|     0,
 | |
|     0,
 | |
|     OurPortPtr,
 | |
|     0,
 | |
|     0,
 | |
|     &Len,
 | |
|     ErrStr
 | |
|     );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| SendAckAndGetData (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_IP_ADDRESS              *ReplyIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *OurPortPtr,
 | |
|   UINT16                      Timeout,
 | |
|   UINTN                       *ReplyLenPtr,
 | |
|   UINT8                       *PxeBcMode,
 | |
|   UINT64                      *BlockNumPtr,
 | |
|   BOOLEAN                     AckOnly
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Send TFTP ACK packet to server and read next DATA packet.
 | |
| 
 | |
| Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   ServerIpPtr := Pointer to TFTP server IP address
 | |
|   ServerPortPtr := Pointer to TFTP server UDP port
 | |
|   ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
 | |
|   OurPortPtr := Pointer to TFTP client UDP port
 | |
|   Timeout :=
 | |
|   ReplyLenPtr := Pointer to packet length
 | |
|   PxeBcMode := Pointer to packet buffer
 | |
|   BlockNumPtr := Pointer to block number
 | |
|   AckOnly := TRUE == Send last ack - do not wait for reply
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   struct Tftpv4Data DataBuffer;
 | |
|   struct Tftpv4Ack  *Ack2Ptr;
 | |
|   struct Tftpv4Ack8 *Ack8Ptr;
 | |
|   EFI_STATUS        Status;
 | |
|   UINTN             Len;
 | |
| 
 | |
|   Ack2Ptr = (VOID *) Private->TftpAckBuffer;
 | |
|   Ack8Ptr = (VOID *) Private->TftpAckBuffer;
 | |
| 
 | |
|   if (Private->BigBlkNumFlag) {
 | |
|     Len               = sizeof (struct Tftpv4Ack8);
 | |
| 
 | |
|     Ack8Ptr->OpCode   = HTONS (TFTP_ACK8);
 | |
|     Ack8Ptr->BlockNum = Swap64 (*BlockNumPtr);
 | |
| 
 | |
|     Status = UdpWrite (
 | |
|               Private,
 | |
|               EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
 | |
|               ServerIpPtr,
 | |
|               ServerPortPtr,
 | |
|               0,
 | |
|               0,
 | |
|               OurPortPtr,
 | |
|               0,
 | |
|               0,
 | |
|               &Len,
 | |
|               Ack8Ptr
 | |
|               );
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   } else {
 | |
|     Len               = sizeof (struct Tftpv4Ack);
 | |
| 
 | |
|     Ack2Ptr->OpCode   = HTONS (TFTP_ACK);
 | |
|     Ack2Ptr->BlockNum = HTONS ((UINT16) *BlockNumPtr);
 | |
| 
 | |
|     Status = UdpWrite (
 | |
|               Private,
 | |
|               EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
 | |
|               ServerIpPtr,
 | |
|               ServerPortPtr,
 | |
|               0,
 | |
|               0,
 | |
|               OurPortPtr,
 | |
|               0,
 | |
|               0,
 | |
|               &Len,
 | |
|               Ack2Ptr
 | |
|               );
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (AckOnly) {
 | |
|     //
 | |
|     // ACK of last packet.  This is just a courtesy.
 | |
|     // Do not wait for response.
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // read reply
 | |
|   //
 | |
|   Status = TftpUdpRead (
 | |
|             Private,
 | |
|             0,
 | |
|             &DataBuffer,
 | |
|             ReplyLenPtr,
 | |
|             PxeBcMode,
 | |
|             ServerIpPtr,
 | |
|             ServerPortPtr,
 | |
|             ReplyIpPtr,
 | |
|             OurPortPtr,
 | |
|             Timeout
 | |
|             );
 | |
| 
 | |
|   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // got a good reply (so far)
 | |
|   // check for next data packet
 | |
|   //
 | |
|   if (!Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA)) {
 | |
|     if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|       SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
 | |
|     }
 | |
| 
 | |
|     *BlockNumPtr = NTOHS (DataBuffer.Header.BlockNum);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA8)) {
 | |
|     if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|       SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
 | |
|     }
 | |
| 
 | |
|     *BlockNumPtr = Swap64 (*(UINT64 *) &DataBuffer.Header.BlockNum);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_PROTOCOL_ERROR;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| LockStepReceive (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   UINTN                       PacketSize,
 | |
|   UINT64                      *BufferSizePtr,
 | |
|   UINT64                      Offset,
 | |
|   UINT8                       *BufferPtr,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_IP_ADDRESS              *ReplyIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *OurPortPtr,
 | |
|   UINT64                      LastBlock,
 | |
|   UINT16                      Timeout,
 | |
|   IN BOOLEAN                  DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Read rest of file after successfull M/TFTP request.
 | |
| 
 | |
| Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   PacketSize := Pointer to packet size
 | |
|   BufferSizePtr := Pointer to buffer (file) size
 | |
|   Offset := Offset into buffer of next packet
 | |
|   BufferPtr := Pointer to receive buffer
 | |
|   ServerIpPtr := Pointer to TFTP server IP address
 | |
|   ServerPortPtr := Pointer to TFTP server UDP port
 | |
|   ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
 | |
|   OurPortPtr := Pointer to TFTP client UDP port
 | |
|   LastBlock := Last block number received
 | |
|   Timeout :=
 | |
|   DontUseBuffer := TRUE == throw away data, just count # of bytes
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT64      BlockNum;
 | |
|   UINT64      BufferSize;
 | |
|   UINTN       Retries;
 | |
|   UINTN       SaveLen;
 | |
|   UINTN       ReplyLen;
 | |
| 
 | |
|   ReplyLen  = PacketSize;
 | |
|   BlockNum  = LastBlock;
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "\nLockStepReceive()  PacketSize = %d", PacketSize));
 | |
| 
 | |
|   if (DontUseBuffer) {
 | |
|     BufferSize = PacketSize;
 | |
|   } else {
 | |
|     BufferSize = *BufferSizePtr - Offset;
 | |
|     BufferPtr += Offset;
 | |
|   }
 | |
| 
 | |
|   while (ReplyLen >= 512 && ReplyLen == PacketSize) {
 | |
|     if (BufferSize < PacketSize) {
 | |
|       ReplyLen = (UINTN) ((BufferSize > 0) ? BufferSize : 0);
 | |
|     }
 | |
| 
 | |
|     SaveLen = ReplyLen;
 | |
| 
 | |
|     //
 | |
|     // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
 | |
|     //
 | |
|     Retries = NUM_ACK_RETRIES;
 | |
| 
 | |
|     do {
 | |
|       ReplyLen = SaveLen;
 | |
| 
 | |
|       Status = SendAckAndGetData (
 | |
|                 Private,
 | |
|                 ServerIpPtr,
 | |
|                 ServerPortPtr,
 | |
|                 ReplyIpPtr,
 | |
|                 OurPortPtr,
 | |
|                 Timeout,
 | |
|                 (UINTN *) &ReplyLen,
 | |
|                 BufferPtr,
 | |
|                 &BlockNum,
 | |
|                 FALSE
 | |
|                 );
 | |
| 
 | |
|       if (!EFI_ERROR (Status) || Status == EFI_BUFFER_TOO_SMALL) {
 | |
|         if (BlockNum == LastBlock) {
 | |
|           DEBUG ((EFI_D_NET, "\nresend"));
 | |
|           //
 | |
|           // a resend - continue
 | |
|           //
 | |
|           Status = EFI_TIMEOUT;
 | |
|         } else if (Private->BigBlkNumFlag) {
 | |
|           if (BlockNum != ++LastBlock) {
 | |
|             DEBUG ((EFI_D_NET, "\nLockStepReceive()  Exit #1a"));
 | |
|             //
 | |
|             // not correct blocknum - error
 | |
|             //
 | |
|             return EFI_PROTOCOL_ERROR;
 | |
|           }
 | |
|         } else {
 | |
|           LastBlock = (LastBlock + 1) & 0xFFFF;
 | |
|           if (BlockNum != LastBlock) {
 | |
|             DEBUG ((EFI_D_NET, "\nLockStepReceive()  Exit #1b"));
 | |
|             return EFI_PROTOCOL_ERROR;
 | |
|             //
 | |
|             // not correct blocknum - error
 | |
|             //
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } while (Status == EFI_TIMEOUT && --Retries);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|         SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
 | |
|       }
 | |
| 
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (DontUseBuffer) {
 | |
|       BufferSize += ReplyLen;
 | |
|     } else {
 | |
|       BufferPtr += ReplyLen;
 | |
|       BufferSize -= ReplyLen;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // while (ReplyLen == PacketSize);
 | |
|   //
 | |
|   if (DontUseBuffer) {
 | |
|     if (BufferSizePtr != NULL) {
 | |
|       *BufferSizePtr = (BufferSize - PacketSize);
 | |
|     }
 | |
|   } else {
 | |
|     *BufferSizePtr -= BufferSize;
 | |
|   }
 | |
| 
 | |
|   /* Send ACK of last packet. */
 | |
|   ReplyLen = 0;
 | |
| 
 | |
|   SendAckAndGetData (
 | |
|     Private,
 | |
|     ServerIpPtr,
 | |
|     ServerPortPtr,
 | |
|     ReplyIpPtr,
 | |
|     OurPortPtr,
 | |
|     Timeout,
 | |
|     (UINTN *) &ReplyLen,
 | |
|     BufferPtr,
 | |
|     &BlockNum,
 | |
|     TRUE
 | |
|     );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // some literals
 | |
| //
 | |
| STATIC UINT8                      Mode[]          = MODE_BINARY;
 | |
| STATIC UINT8                      BlockSizeOp[]   = OP_BLKSIZE;
 | |
| STATIC UINT8                      TsizeOp[]       = OP_TFRSIZE;
 | |
| STATIC UINT8                      OverwriteOp[]   = OP_OVERWRITE;
 | |
| STATIC UINT8                      BigBlkNumOp[]   = OP_BIGBLKNUM;
 | |
| STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort = TFTP_OPEN_PORT;
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| UINT8 *
 | |
| FindOption (
 | |
|   UINT8 *OptionPtr,
 | |
|   INTN  OpLen,
 | |
|   UINT8 *OackPtr,
 | |
|   INTN  OackSize
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Check TFTP OACK packet for option.
 | |
| 
 | |
| Parameters:
 | |
|   OptionPtr := Pointer to option string to find
 | |
|   OpLen := Length of option string
 | |
|   OackPtr := Pointer to OACK data
 | |
|   OackSize := Length of OACK data
 | |
| 
 | |
| Returns:
 | |
|   Pointer to value field if option found or NULL if not found.
 | |
| --*/
 | |
| {
 | |
|   if ((OackSize -= OpLen) <= 0) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     if (!CompareMem (OackPtr, OptionPtr, OpLen)) {
 | |
|       return OackPtr + OpLen;
 | |
|     }
 | |
| 
 | |
|     ++OackPtr;
 | |
|   } while (--OackSize);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| #define BKSZOP      1 // block size
 | |
| #define TSIZEOP     2 // transfer size
 | |
| #define OVERWRITEOP 4 // overwrite
 | |
| #define BIGBLKNUMOP 8 // big block numbers
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| TftpRwReq (
 | |
|   UINT16                      Req,
 | |
|   UINT16                      Options,
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *OurPortPtr,
 | |
|   UINT8                       *FilenamePtr,
 | |
|   UINTN                       *PacketSizePtr,
 | |
|   VOID                        *Buffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Send TFTP RRQ/WRQ packet.
 | |
| 
 | |
| Parameters:
 | |
|   Req := Type of request to send
 | |
|   Options := One or more of the #define values above
 | |
|   Private := Pointer to PxeBc interface
 | |
|   ServerIpPtr := Pointer to TFTP server IP address
 | |
|   ServerPortPtr := Pointer to TFTP server UDP port
 | |
|   OurPortPtr := Pointer to TFTP client UDP port
 | |
|   FilenamePtr := Pointer to TFTP file or directory name
 | |
|   PacketSizePtr := Pointer to block size
 | |
|   Buffer :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   union {
 | |
|     UINT8             Data[514];
 | |
|     struct Tftpv4Req  ReqStr;
 | |
|   } *u;
 | |
| 
 | |
|   UINT16  OpFlags;
 | |
|   INTN    Len;
 | |
|   INTN    TotalLen;
 | |
|   UINT8   *Ptr;
 | |
| 
 | |
|   if (*OurPortPtr == 0) {
 | |
|     OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;
 | |
|   } else {
 | |
|     OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT;
 | |
|   }
 | |
|   //
 | |
|   // build the basic request - opcode, filename, mode
 | |
|   //
 | |
|   u                 = Buffer;
 | |
|   u->ReqStr.OpCode  = HTONS (Req);
 | |
|   TotalLen = sizeof (Mode) + sizeof (u->ReqStr.OpCode) + (Len = 1 + AsciiStrLen ((CHAR8 *)FilenamePtr));
 | |
| 
 | |
|   CopyMem (u->ReqStr.FileName, FilenamePtr, Len);
 | |
|   Ptr = (UINT8 *) (u->ReqStr.FileName + Len);
 | |
| 
 | |
|   CopyMem (Ptr, Mode, sizeof (Mode));
 | |
|   Ptr += sizeof (Mode);
 | |
| 
 | |
|   if (Options & BKSZOP) {
 | |
|     CopyMem (Ptr, BlockSizeOp, sizeof (BlockSizeOp));
 | |
|     UtoA10 (*PacketSizePtr, Ptr + sizeof (BlockSizeOp));
 | |
| 
 | |
|     TotalLen += (Len = 1 + AsciiStrLen ((CHAR8 *)Ptr + sizeof (BlockSizeOp)) + sizeof (BlockSizeOp));
 | |
| 
 | |
|     Ptr += Len;
 | |
|   }
 | |
| 
 | |
|   if (Options & TSIZEOP) {
 | |
|     CopyMem (Ptr, TsizeOp, sizeof (TsizeOp));
 | |
|     CopyMem (Ptr + sizeof (TsizeOp), "0", 2);
 | |
|     TotalLen += sizeof (TsizeOp) + 2;
 | |
|     Ptr += sizeof (TsizeOp) + 2;
 | |
|   }
 | |
| 
 | |
|   if (Options & OVERWRITEOP) {
 | |
|     CopyMem (Ptr, OverwriteOp, sizeof (OverwriteOp));
 | |
|     CopyMem (Ptr + sizeof (OverwriteOp), "1", 2);
 | |
|     TotalLen += sizeof (OverwriteOp) + 2;
 | |
|     Ptr += sizeof (OverwriteOp) + 2;
 | |
|   }
 | |
| 
 | |
|   if (Options & BIGBLKNUMOP) {
 | |
|     CopyMem (Ptr, BigBlkNumOp, sizeof (BigBlkNumOp));
 | |
|     CopyMem (Ptr + sizeof (BigBlkNumOp), "8", 2);
 | |
|     TotalLen += sizeof (BigBlkNumOp) + 2;
 | |
|     Ptr += sizeof (BigBlkNumOp) + 2;
 | |
|   }
 | |
|   //
 | |
|   // send it
 | |
|   //
 | |
|   return UdpWrite (
 | |
|           Private,
 | |
|           OpFlags,
 | |
|           ServerIpPtr,
 | |
|           ServerPortPtr,
 | |
|           0,
 | |
|           0,
 | |
|           OurPortPtr,
 | |
|           0,
 | |
|           0,
 | |
|           (UINTN *) &TotalLen,
 | |
|           u
 | |
|           );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| TftpRwReqwResp (
 | |
|   UINT16                      Req,
 | |
|   UINT16                      Options,
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   VOID                        *HeaderPtr,
 | |
|   UINTN                       *PacketSizePtr,
 | |
|   UINTN                       *ReplyLenPtr,
 | |
|   VOID                        *BufferPtr,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerReplyPortPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *OurPortPtr,
 | |
|   UINT8                       *FilenamePtr,
 | |
|   UINT16                      Timeout
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Start TFTP session.  Issue request and wait for response.
 | |
|   Retry three times on error.  If failed using options,
 | |
|   retry three times w/o options on error.
 | |
| 
 | |
| Parameters:
 | |
|   Req := TFTP request type
 | |
|   Options := TFTP option bits
 | |
|   Private := Pointer to PxeBc interface
 | |
|   HeaderPtr :=
 | |
|   PacketSizePtr := Pointer to block size
 | |
|   ReplyLenPtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr := Pointer to TFTP server IP address
 | |
|   ServerPortPtr := Pointer to TFTP server UDP port
 | |
|   ServerReplyPortPtr :=
 | |
|   OurPortPtr := Pointer to TFTP client UDP Port
 | |
|   FilenamePtr := Pointer to file or directory name
 | |
|   Timeout :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       SaveReplyLen;
 | |
|   INTN        Retries;
 | |
|   UINT8       Buffer[514];
 | |
| 
 | |
|   SaveReplyLen            = *ReplyLenPtr;
 | |
|   Retries                 = 3;
 | |
|   Private->BigBlkNumFlag  = FALSE;
 | |
|   *OurPortPtr             = 0;
 | |
|   //
 | |
|   // generate random
 | |
|   //
 | |
|   do {
 | |
|     if (*OurPortPtr != 0) {
 | |
|       if (++ *OurPortPtr == 0) {
 | |
|         *OurPortPtr = PXE_RND_PORT_LOW;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // send request from our Ip = StationIp
 | |
|     //
 | |
|     if ((Status = TftpRwReq (
 | |
|                     Req,
 | |
|                     Options,
 | |
|                     Private,
 | |
|                     ServerIpPtr,
 | |
|                     ServerPortPtr,
 | |
|                     OurPortPtr,
 | |
|                     FilenamePtr,
 | |
|                     PacketSizePtr,
 | |
|                     Buffer
 | |
|                     )) != EFI_SUCCESS) {
 | |
|       DEBUG (
 | |
|         (EFI_D_WARN,
 | |
|         "\nTftpRwReqwResp()  Exit #1  %xh (%r)",
 | |
|         Status,
 | |
|         Status)
 | |
|         );
 | |
| 
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // read reply to our Ip = StationIp
 | |
|     //
 | |
|     *ReplyLenPtr = SaveReplyLen;
 | |
| 
 | |
|     Status = TftpUdpRead (
 | |
|               Private,
 | |
|               EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|               HeaderPtr,
 | |
|               ReplyLenPtr,
 | |
|               BufferPtr,
 | |
|               ServerIpPtr,
 | |
|               ServerReplyPortPtr,
 | |
|               0,
 | |
|               OurPortPtr,
 | |
|               Timeout
 | |
|               );
 | |
|   } while (Status == EFI_TIMEOUT && --Retries);
 | |
| 
 | |
|   if (!Options || Status != EFI_TFTP_ERROR) {
 | |
|     DEBUG (
 | |
|       (EFI_D_WARN,
 | |
|       "\nTftpRwReqwResp()  Exit #2  %xh (%r)",
 | |
|       Status,
 | |
|       Status)
 | |
|       );
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = TftpRwReqwResp (
 | |
|             Req,
 | |
|             0,
 | |
|             Private,
 | |
|             HeaderPtr,
 | |
|             PacketSizePtr,
 | |
|             ReplyLenPtr,
 | |
|             BufferPtr,
 | |
|             ServerIpPtr,
 | |
|             ServerPortPtr,
 | |
|             ServerReplyPortPtr,
 | |
|             OurPortPtr,
 | |
|             FilenamePtr,
 | |
|             Timeout
 | |
|             );
 | |
| 
 | |
|   DEBUG ((EFI_D_WARN, "\nTftpRwReqwResp()  Exit #3  %xh (%r)", Status, Status));
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // mtftp listen
 | |
| // read on mcast ip, cport, from sport, for data packet
 | |
| // returns success if gets multicast last packet or all up to last block
 | |
| // if not missing, then finished
 | |
| //
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MtftpListen (
 | |
|   PXE_BASECODE_DEVICE           *Private,
 | |
|   UINT64                        *BufferSizePtr,
 | |
|   UINT8                         *BufferPtr,
 | |
|   EFI_IP_ADDRESS                *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_MTFTP_INFO  *MtftpInfoPtr,
 | |
|   UINT64                        *StartBlockPtr,
 | |
|   UINTN                         *NumMissedPtr,
 | |
|   UINT16                        TransTimeout,
 | |
|   UINT16                        ListenTimeout,
 | |
|   UINT64                        FinalBlock,
 | |
|   IN BOOLEAN                    DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Listen for MTFTP traffic and save desired packets.
 | |
| 
 | |
| Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   BufferSizePtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr := Pointer to TFTP server IP address
 | |
|   MtftpInfoPtr := Pointer to MTFTP session information
 | |
|   StartBlockPtr := IN=first block we are looking for  OUT=first block received
 | |
|   NumMissedPtr := Number of blocks missed
 | |
|   TransTimeout :=
 | |
|   ListenTimeout :=
 | |
|   FinalBlock :=
 | |
|   DontUseBuffer := TRUE == throw packets away, just count bytes
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   struct Tftpv4Ack  Header;
 | |
|   UINT64            Offset;
 | |
|   UINT64            BlockNum;
 | |
|   UINT64            LastBlockNum;
 | |
|   UINT64            BufferSize;
 | |
|   UINTN             NumMissed;
 | |
|   UINTN             PacketSize;
 | |
|   UINTN             SaveReplyLen;
 | |
|   UINTN             ReplyLen;
 | |
|   UINT16            Timeout;
 | |
| 
 | |
|   LastBlockNum  = *StartBlockPtr;
 | |
|   Timeout       = ListenTimeout;
 | |
|   *NumMissedPtr = 0;
 | |
|   PacketSize    = 0;
 | |
|   BufferSize    = *BufferSizePtr;
 | |
|   ReplyLen      = MAX_TFTP_PKT_SIZE;;
 | |
| 
 | |
|   //
 | |
|   // receive
 | |
|   //
 | |
|   do {
 | |
|     if ((SaveReplyLen = ReplyLen) > BufferSize) {
 | |
|       SaveReplyLen = (UINTN) BufferSize;
 | |
|     }
 | |
| 
 | |
|     /* %%TBD - add big block number support */
 | |
| 
 | |
|     //
 | |
|     // get data - loop on resends
 | |
|     //
 | |
|     do {
 | |
|       ReplyLen = SaveReplyLen;
 | |
| 
 | |
|       if ((Status = TftpUdpRead (
 | |
|                       Private,
 | |
|                       0,
 | |
|                       &Header,
 | |
|                       &ReplyLen,
 | |
|                       BufferPtr,
 | |
|                       ServerIpPtr,
 | |
|                       &MtftpInfoPtr->SPort,
 | |
|                       &MtftpInfoPtr->MCastIp,
 | |
|                       &MtftpInfoPtr->CPort,
 | |
|                       Timeout
 | |
|                       )) != EFI_SUCCESS) {
 | |
|         return Status;
 | |
|       }
 | |
|       //
 | |
|       // make sure a data packet
 | |
|       //
 | |
|       if (Header.OpCode != HTONS (TFTP_DATA)) {
 | |
|         return EFI_PROTOCOL_ERROR;
 | |
|       }
 | |
|     } while ((BlockNum = NTOHS (Header.BlockNum)) == LastBlockNum);
 | |
| 
 | |
|     //
 | |
|     // make sure still going up
 | |
|     //
 | |
|     if (LastBlockNum > BlockNum) {
 | |
|       return EFI_PROTOCOL_ERROR;
 | |
|     }
 | |
| 
 | |
|     if (BlockNum - LastBlockNum > 0xFFFFFFFF) {
 | |
|       return EFI_PROTOCOL_ERROR;
 | |
|     } else {
 | |
|       NumMissed = (UINTN) (BlockNum - LastBlockNum - 1);
 | |
|     }
 | |
| 
 | |
|     LastBlockNum = BlockNum;
 | |
| 
 | |
|     //
 | |
|     // if first time through, some reinitialization
 | |
|     //
 | |
|     if (!PacketSize) {
 | |
|       *StartBlockPtr  = BlockNum;
 | |
|       PacketSize      = ReplyLen;
 | |
|       Timeout         = TransTimeout;
 | |
|     } else {
 | |
|       *NumMissedPtr = (UINT16) (*NumMissedPtr + NumMissed);
 | |
|     }
 | |
|     //
 | |
|     // if missed packets, update start block,
 | |
|     // etc. and move packet to proper place in buffer
 | |
|     //
 | |
|     if (NumMissed) {
 | |
|       *StartBlockPtr = BlockNum;
 | |
|       if (!DontUseBuffer) {
 | |
|         Offset = NumMissed * PacketSize;
 | |
|         CopyMem (BufferPtr + Offset, BufferPtr, ReplyLen);
 | |
|         BufferPtr += Offset;
 | |
|         BufferSize -= Offset;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!DontUseBuffer) {
 | |
|       BufferPtr += ReplyLen;
 | |
|       BufferSize -= ReplyLen;
 | |
|     }
 | |
|   } while (ReplyLen == PacketSize && BlockNum != FinalBlock);
 | |
| 
 | |
|   *BufferSizePtr = BufferSize;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MtftpOpen (
 | |
|   PXE_BASECODE_DEVICE                                               * Private,
 | |
|   UINT64                                                            *BufferSizePtr,
 | |
|   UINT8                                                             *BufferPtr,
 | |
|   UINTN                                                             *PacketSizePtr,
 | |
|   EFI_IP_ADDRESS                                                    * ServerIpPtr,
 | |
|   UINT8                                                             *FilenamePtr,
 | |
|   EFI_PXE_BASE_CODE_MTFTP_INFO                                      * MtftpInfoPtr,
 | |
|   UINT8                                                             *CompletionStatusPtr,
 | |
| #define GOTUNI 1
 | |
| #define GOTMULTI 2
 | |
|   IN BOOLEAN                    DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Open MTFTP session.
 | |
| 
 | |
| Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   BufferSizePtr := IN=buffer size  OUT=transfer size
 | |
|   BufferPtr :=
 | |
|   PacketSizePtr :=
 | |
|   ServerIpPtr :=
 | |
|   FilenamePtr :=
 | |
|   MtftpInfoPtr :=
 | |
|   CompletionStatusPtr :=
 | |
|   DontUseBuffer :=
 | |
| 
 | |
| Returns:
 | |
| // mtftp open session
 | |
| // return code EFI_SUCCESS
 | |
| //      and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
 | |
| //      and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
 | |
| //      and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
 | |
| //      (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   EFI_IP_ADDRESS    OurReplyIp;
 | |
|   struct Tftpv4Ack  Header;
 | |
|   INTN              ReplyLen;
 | |
|   INTN              Retries;
 | |
|   UINT8             *BufferPtr2;
 | |
|   UINT8             TmpBuf[514];
 | |
| 
 | |
|   Retries         = NUM_MTFTP_OPEN_RETRIES;
 | |
|   BufferPtr2      = BufferPtr;
 | |
|   *PacketSizePtr  = (UINTN) (EFI_MIN (*BufferSizePtr, MAX_TFTP_PKT_SIZE));
 | |
| 
 | |
|   do {
 | |
|     //
 | |
|     // send a read request
 | |
|     //
 | |
|     *CompletionStatusPtr = 0;
 | |
| 
 | |
|     if ((Status = TftpRwReq (
 | |
|                     TFTP_RRQ,
 | |
|                     0,
 | |
|                     Private,
 | |
|                     ServerIpPtr,
 | |
|                     &MtftpInfoPtr->SPort,
 | |
|                     &MtftpInfoPtr->CPort,
 | |
|                     FilenamePtr,
 | |
|                     PacketSizePtr,
 | |
|                     TmpBuf
 | |
|                     )) != EFI_SUCCESS) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     for (;;) {
 | |
|       //
 | |
|       // read reply
 | |
|       //
 | |
|       ZeroMem (&OurReplyIp, Private->IpLength);
 | |
|       ReplyLen = *PacketSizePtr;
 | |
| 
 | |
|       if ((Status = TftpUdpRead (
 | |
|                       Private,
 | |
|                       EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER,
 | |
|                       &Header,
 | |
|                       (UINTN *) &ReplyLen,
 | |
|                       BufferPtr2,
 | |
|                       ServerIpPtr,
 | |
|                       &MtftpInfoPtr->SPort,
 | |
|                       &OurReplyIp,
 | |
|                       &MtftpInfoPtr->CPort,
 | |
|                       MtftpInfoPtr->TransmitTimeout
 | |
|                       )) == EFI_SUCCESS) {
 | |
|         //
 | |
|         // check for first data packet
 | |
|         //
 | |
|         if (Header.OpCode != HTONS (TFTP_DATA)) {
 | |
|           return EFI_PROTOCOL_ERROR;
 | |
|         }
 | |
|         //
 | |
|         // check block num
 | |
|         //
 | |
|         if (Header.BlockNum != HTONS (1)) {
 | |
|           //
 | |
|           // it's not first
 | |
|           // if we are not the primary client,
 | |
|           // we probably got first and now second
 | |
|           // multicast but no unicast, so
 | |
|           // *CompletionStatusPtr = GOTMULTI - if this is
 | |
|           // the second, can just go on to listen
 | |
|           // starting with 2 as the last block
 | |
|           // received
 | |
|           //
 | |
|           if (Header.BlockNum != HTONS (2)) {
 | |
|             //
 | |
|             // not second
 | |
|             //
 | |
|             *CompletionStatusPtr = 0;
 | |
|           }
 | |
| 
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // now actual
 | |
|         //
 | |
|         *PacketSizePtr = ReplyLen;
 | |
|         //
 | |
|         // see if a unicast data packet
 | |
|         //
 | |
|         if (!CompareMem (
 | |
|               &OurReplyIp,
 | |
|               &Private->EfiBc.Mode->StationIp,
 | |
|               Private->IpLength
 | |
|               )) {
 | |
|           *CompletionStatusPtr |= GOTUNI;
 | |
|           //
 | |
|           // it is
 | |
|           // if already got multicast packet,
 | |
|           // got em both
 | |
|           //
 | |
|           if (*CompletionStatusPtr & GOTMULTI) {
 | |
|             break;
 | |
|           }
 | |
|         } else if (!CompareMem (
 | |
|                     &OurReplyIp,
 | |
|                     &MtftpInfoPtr->MCastIp,
 | |
|                     Private->IpLength
 | |
|                     )) {
 | |
|           //
 | |
|           // otherwise see if a multicast data packet
 | |
|           //
 | |
|           *CompletionStatusPtr |= GOTMULTI;
 | |
|           //
 | |
|           // it is
 | |
|           // got first - bump pointer so that if
 | |
|           // second multi comes along, we're OK
 | |
|           //
 | |
|           if (!DontUseBuffer) {
 | |
|             BufferPtr2 = (UINT8 *) BufferPtr + ReplyLen;
 | |
|           }
 | |
|           //
 | |
|           // if already got unicast packet,
 | |
|           // got em both
 | |
|           //
 | |
|           if (*CompletionStatusPtr & GOTUNI) {
 | |
|             break;
 | |
|           }
 | |
|         } else {
 | |
|           //
 | |
|           // else protocol error
 | |
|           //
 | |
|           return EFI_PROTOCOL_ERROR;
 | |
|         }
 | |
|       } else if (Status == EFI_TIMEOUT) {
 | |
|         //
 | |
|         // bad return code - if timed out, retry
 | |
|         //
 | |
|         break;
 | |
|       } else {
 | |
|         //
 | |
|         // else just bad - failed MTFTP open
 | |
|         //
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   } while (Status == EFI_TIMEOUT && --Retries);
 | |
| 
 | |
|   if (Status != EFI_SUCCESS) {
 | |
|     //
 | |
|     // open failed
 | |
|     //
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // got em both - go into receive mode
 | |
|   // routine to read rest of file after a successful open (TFTP or MTFTP)
 | |
|   // sends ACK and gets next data packet until short packet arrives,
 | |
|   // then sends ACK and (hopefully) times out
 | |
|   //
 | |
|   return LockStepReceive (
 | |
|           Private,
 | |
|           (UINT16) ReplyLen,
 | |
|           BufferSizePtr,
 | |
|           ReplyLen,
 | |
|           BufferPtr,
 | |
|           ServerIpPtr,
 | |
|           &MtftpInfoPtr->SPort,
 | |
|           &MtftpInfoPtr->MCastIp,
 | |
|           &MtftpInfoPtr->CPort,
 | |
|           1,
 | |
|           MtftpInfoPtr->TransmitTimeout,
 | |
|           DontUseBuffer
 | |
|           );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| MtftpDownload (
 | |
|   PXE_BASECODE_DEVICE           *Private,
 | |
|   UINT64                        *BufferSizePtr,
 | |
|   UINT8                         *BufferPtr,
 | |
|   EFI_IP_ADDRESS                *ServerIpPtr,
 | |
|   UINT8                         *FilenamePtr,
 | |
|   EFI_PXE_BASE_CODE_MTFTP_INFO  *MtftpInfoPtr,
 | |
|   IN BOOLEAN                    DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
| // mtftp
 | |
| // loop
 | |
| //  listen
 | |
| //  if did not get any packets, try MTFTP open
 | |
| //  if got all packets, return
 | |
| //  compute listen timeout and loop
 | |
| 
 | |
| Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   BufferSizePtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr :=
 | |
|   FilenamePtr :=
 | |
|   MtftpInfoPtr :=
 | |
|   DontUseBuffer :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_IP_FILTER Filter;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT64                      StartBlock;
 | |
|   UINT64                      LastBlock;
 | |
|   UINT64                      LastStartBlock;
 | |
|   UINT64                      BufferSize;
 | |
|   UINTN                       Offset;
 | |
|   UINTN                       NumMissed;
 | |
|   UINT16                      TransTimeout;
 | |
|   UINT16                      ListenTimeout;
 | |
|   UINT8                       *BufferPtrLocal;
 | |
| 
 | |
|   TransTimeout      = MtftpInfoPtr->TransmitTimeout;
 | |
|   ListenTimeout     = MtftpInfoPtr->ListenTimeout;
 | |
|   LastBlock         = 0;
 | |
|   LastStartBlock    = 0;
 | |
|   Offset            = 0;
 | |
| 
 | |
|   Filter.Filters    = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
 | |
|   Filter.IpCnt      = 2;
 | |
|   CopyMem (&Filter.IpList[0], &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));
 | |
|   CopyMem (&Filter.IpList[1], &MtftpInfoPtr->MCastIp, sizeof (EFI_IP_ADDRESS));
 | |
| 
 | |
|   if ((Status = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   for (;;) {
 | |
|     StartBlock  = LastStartBlock;
 | |
|     BufferSize  = *BufferSizePtr - Offset;
 | |
| 
 | |
|     if (DontUseBuffer) {
 | |
|     //
 | |
|     // overwrie the temp buf
 | |
|     //
 | |
|       BufferPtrLocal = BufferPtr;
 | |
|     } else {
 | |
|       BufferPtrLocal = BufferPtr + Offset;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     if (((Status = MtftpListen (
 | |
|                       Private,
 | |
|                       &BufferSize,
 | |
|                       BufferPtrLocal,
 | |
|                       ServerIpPtr,
 | |
|                       MtftpInfoPtr,
 | |
|                       &StartBlock,
 | |
|                       &NumMissed,
 | |
|                       TransTimeout,
 | |
|                       ListenTimeout,
 | |
|                       LastBlock,
 | |
|                       DontUseBuffer
 | |
|                       )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {
 | |
|       return Status;
 | |
|       //
 | |
|       // failed
 | |
|       //
 | |
|     }
 | |
|     //
 | |
|     // if none were received, start block is not reset
 | |
|     //
 | |
|     if (StartBlock == LastStartBlock) {
 | |
|       UINT8 CompStat;
 | |
| 
 | |
|       //
 | |
|       // timed out with none received - try MTFTP open
 | |
|       //
 | |
|       if ((Status = MtftpOpen (
 | |
|                       Private,
 | |
|                       BufferSizePtr,
 | |
|                       BufferPtr,
 | |
|                       &Offset,
 | |
|                       ServerIpPtr,
 | |
|                       FilenamePtr,
 | |
|                       MtftpInfoPtr,
 | |
|                       &CompStat,
 | |
|                       DontUseBuffer
 | |
|                       )) != EFI_SUCCESS) {
 | |
|         //
 | |
|         // open failure - try TFTP
 | |
|         //
 | |
|         return Status;
 | |
|       }
 | |
|       //
 | |
|       // return code EFI_SUCCESS
 | |
|       // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
 | |
|       // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
 | |
|       // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
 | |
|       // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
 | |
|       //
 | |
|       if (CompStat == (GOTUNI | GOTMULTI)) {
 | |
|       //
 | |
|       // finished - got it all
 | |
|       //
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       if (CompStat) {
 | |
|         //
 | |
|         // offset is two packet lengths
 | |
|         //
 | |
|         Offset <<= 1;
 | |
|         //
 | |
|         // last block received
 | |
|         //
 | |
|         LastStartBlock = 2;
 | |
|       } else {
 | |
|         Offset          = 0;
 | |
|         LastStartBlock  = 0;
 | |
|       }
 | |
| 
 | |
|       ListenTimeout = TransTimeout;
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // did we get the last block
 | |
|     //
 | |
|     if (Status == EFI_SUCCESS) {
 | |
|       //
 | |
|       // yes - set the file size if this was first time
 | |
|       //
 | |
|       if (!LastBlock) {
 | |
|         *BufferSizePtr -= BufferSize;
 | |
|       }
 | |
|       //
 | |
|       // if buffer was too small, finished
 | |
|       //
 | |
|       if (!DontUseBuffer) {
 | |
|         return EFI_BUFFER_TOO_SMALL;
 | |
|       }
 | |
|       //
 | |
|       // if we got them all, finished
 | |
|       //
 | |
|       if (!NumMissed && StartBlock == LastStartBlock + 1) {
 | |
|         return Status;
 | |
|       }
 | |
|       //
 | |
|       // did not get them all - set last block
 | |
|       //
 | |
|       LastBlock = (UINT16) (StartBlock - 1);
 | |
|     }
 | |
|     //
 | |
|     // compute listen timeout
 | |
|     //
 | |
|     ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));
 | |
| 
 | |
|     //
 | |
|     // reset
 | |
|     //
 | |
|     Offset          = 0;
 | |
|     LastStartBlock  = 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| TftpInfo (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   UINT64                      *BufferSizePtr,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  SrvPort,
 | |
|   UINT8                       *FilenamePtr,
 | |
|   UINTN                       *PacketSizePtr
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
| // TFTP info request routine
 | |
| // send read request with block size and transfer size options
 | |
| // get reply
 | |
| // send error to terminate session
 | |
| // if OACK received, set info
 | |
| 
 | |
| Parameters:
 | |
|   Private :=
 | |
|   BufferSizePtr :=
 | |
|   ServerIpPtr :=
 | |
|   SrvPort :=
 | |
|   FilenamePtr :=
 | |
|   PacketSizePtr :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  OurPort;
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  ServerReplyPort;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT64                      BlockNum;
 | |
|   UINTN                       Offset;
 | |
|   UINTN                       ReplyLen;
 | |
|   UINT8                       *Ptr;
 | |
| 
 | |
|   union {
 | |
|     struct Tftpv4Oack OAck2Ptr;
 | |
|     struct Tftpv4Ack  Ack2Ptr;
 | |
|     struct Tftpv4Data Datastr;
 | |
|   } u;
 | |
| 
 | |
|   OurPort         = 0;
 | |
|   ServerReplyPort = 0;
 | |
|   ReplyLen        = sizeof (u.Datastr.Data);
 | |
| 
 | |
|   //
 | |
|   // send a write request with the blocksize option -
 | |
|   // sets our IP and port - and receive reply - sets his port
 | |
|   // will retry operation up to 3 times if no response,
 | |
|   // and will retry without options on an error reply
 | |
|   //
 | |
|   if ((Status = TftpRwReqwResp (
 | |
|                   TFTP_RRQ,
 | |
|                   /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,
 | |
|                   Private,
 | |
|                   &u,
 | |
|                   PacketSizePtr,
 | |
|                   &ReplyLen,
 | |
|                   u.Datastr.Data,
 | |
|                   ServerIpPtr,
 | |
|                   &SrvPort,
 | |
|                   &ServerReplyPort,
 | |
|                   &OurPort,
 | |
|                   FilenamePtr,
 | |
|                   REQ_RESP_TIMEOUT
 | |
|                   )) != EFI_SUCCESS) {
 | |
|     DEBUG ((EFI_D_WARN, "\nTftpInfo()  Exit #1"));
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // check for good OACK
 | |
|   //
 | |
|   if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
 | |
|     //
 | |
|     // now parse it for options
 | |
|     // bigblk#
 | |
|     //
 | |
|     Ptr = FindOption (
 | |
|             BigBlkNumOp,
 | |
|             sizeof (BigBlkNumOp),
 | |
|             u.OAck2Ptr.OpAck[0].Option,
 | |
|             ReplyLen + sizeof (u.Ack2Ptr.BlockNum)
 | |
|             );
 | |
| 
 | |
|     if (Ptr != NULL) {
 | |
|       if (AtoU (Ptr) == 8) {
 | |
|         Private->BigBlkNumFlag = TRUE;
 | |
|       } else {
 | |
|         return EFI_PROTOCOL_ERROR;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // blksize
 | |
|     //
 | |
|     Ptr = FindOption (
 | |
|             BlockSizeOp,
 | |
|             sizeof (BlockSizeOp),
 | |
|             u.OAck2Ptr.OpAck[0].Option,
 | |
|             ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
 | |
|             );
 | |
| 
 | |
|     *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
 | |
| 
 | |
|     //
 | |
|     // tsize
 | |
|     //
 | |
|     Ptr = FindOption (
 | |
|             TsizeOp,
 | |
|             sizeof (TsizeOp),
 | |
|             u.OAck2Ptr.OpAck[0].Option,
 | |
|             ReplyLen
 | |
|             );
 | |
| 
 | |
|     if (Ptr != NULL) {
 | |
|       *BufferSizePtr = AtoU64 (Ptr);
 | |
| 
 | |
|       //
 | |
|       // teminate session with error
 | |
|       //
 | |
|       SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Offset    = 0;
 | |
|     BlockNum  = 0;
 | |
|   } else {
 | |
|     //
 | |
|     // if MTFTP get filesize, return unsupported
 | |
|     //
 | |
|     if (SrvPort != TftpRequestPort) {
 | |
|       SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
 | |
|       DEBUG ((EFI_D_WARN, "\nTftpInfo()  Exit #3"));
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     Offset    = ReplyLen;
 | |
|     //
 | |
|     // last block received
 | |
|     //
 | |
|     BlockNum  = 1;
 | |
|   }
 | |
|   //
 | |
|   // does not support the option - do a download with no buffer
 | |
|   //
 | |
|   *BufferSizePtr = 0;
 | |
| 
 | |
|   Status = LockStepReceive (
 | |
|             Private,
 | |
|             (UINT16) ReplyLen,
 | |
|             BufferSizePtr,
 | |
|             Offset,
 | |
|             (UINT8 *) &u,
 | |
|             ServerIpPtr,
 | |
|             &ServerReplyPort,
 | |
|             &Private->EfiBc.Mode->StationIp,
 | |
|             &OurPort,
 | |
|             BlockNum,
 | |
|             ACK_TIMEOUT,
 | |
|             TRUE
 | |
|             );
 | |
| 
 | |
|   if (Status != EFI_SUCCESS) {
 | |
|     DEBUG ((EFI_D_WARN, "\nTftpInfo()  LockStepReceive() == %Xh", Status));
 | |
|   }
 | |
| 
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| TftpDownload (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   UINT64                      *BufferSizePtr,
 | |
|   UINT8                       *BufferPtr,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   UINT8                       *FilenamePtr,
 | |
|   UINTN                       *PacketSizePtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  SrvPort,
 | |
|   UINT16                      Req,
 | |
|   IN BOOLEAN                  DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
| // tftp read session
 | |
| // send read request
 | |
| // [get OACK
 | |
| //  send ACK]
 | |
| // loop
 | |
| //  get data
 | |
| //  send ACK
 | |
| //  while data size is max
 | |
| 
 | |
| Parameters:
 | |
|   Private :=
 | |
|   BufferSizePtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr :=
 | |
|   FilenamePtr :=
 | |
|   PacketSizePtr :=
 | |
|   SrvPort :=
 | |
|   Req :=
 | |
|   DontUseBuffer :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  OurPort;
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  ServerReplyPort;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT64                      Offset;
 | |
|   UINT64                      BlockNum;
 | |
|   UINTN                       ReplyLen;
 | |
|   UINT8                       *Ptr;
 | |
| 
 | |
|   union {
 | |
|     struct Tftpv4Ack    Ack2Ptr;
 | |
|     struct Tftpv4Oack   OAck2Ptr;
 | |
|     struct Tftpv4Data   Data;
 | |
|     struct Tftpv4Ack8   Ack8Ptr;
 | |
|     struct Tftpv4Data8  Data8;
 | |
|   } U;
 | |
| 
 | |
|   OurPort         = 0;
 | |
|   ServerReplyPort = 0;
 | |
|   ReplyLen        = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);
 | |
| 
 | |
|   //
 | |
|   // send a read request with the blocksize option - sets our IP and port
 | |
|   // - and receive reply - sets his port will retry operation up to 3
 | |
|   // times if no response, and will retry without options on an error
 | |
|   // reply
 | |
|   //
 | |
|   if ((Status = TftpRwReqwResp (
 | |
|                   Req,
 | |
|                   /* BIGBLKNUMOP | */BKSZOP,
 | |
|                   Private,
 | |
|                   &U,
 | |
|                   PacketSizePtr,
 | |
|                   &ReplyLen,
 | |
|                   BufferPtr,
 | |
|                   ServerIpPtr,
 | |
|                   &SrvPort,
 | |
|                   &ServerReplyPort,
 | |
|                   &OurPort,
 | |
|                   FilenamePtr,
 | |
|                   REQ_RESP_TIMEOUT
 | |
|                   )) != EFI_SUCCESS) {
 | |
|     DEBUG ((EFI_D_WARN, "\nTftpDownload()  Exit #1  %xh (%r)", Status, Status));
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // check for OACK
 | |
|   //
 | |
|   if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
 | |
|     //
 | |
|     // get the OACK
 | |
|     //
 | |
|     CopyMem (U.Data.Data, BufferPtr, ReplyLen);
 | |
| 
 | |
|     Ptr = FindOption (
 | |
|             BigBlkNumOp,
 | |
|             sizeof (BigBlkNumOp),
 | |
|             U.OAck2Ptr.OpAck[0].Option,
 | |
|             ReplyLen + sizeof (U.Ack2Ptr.BlockNum)
 | |
|             );
 | |
| 
 | |
|     if (Ptr != NULL) {
 | |
|       if (AtoU (Ptr) == 8) {
 | |
|         Private->BigBlkNumFlag = TRUE;
 | |
|       } else {
 | |
|         return EFI_PROTOCOL_ERROR;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // now parse it for blocksize option
 | |
|     //
 | |
|     Ptr = FindOption (
 | |
|             BlockSizeOp,
 | |
|             sizeof (BlockSizeOp),
 | |
|             U.OAck2Ptr.OpAck[0].Option,
 | |
|             ReplyLen += sizeof (U.Ack2Ptr.BlockNum)
 | |
|             );
 | |
| 
 | |
|     ReplyLen  = (Ptr != NULL) ? AtoU (Ptr) : 512;
 | |
| 
 | |
|     Offset    = 0;
 | |
|     //
 | |
|     // last block received
 | |
|     //
 | |
|     BlockNum  = 0;
 | |
|   } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {
 | |
|     //
 | |
|     // or data
 | |
|     //
 | |
|     DEBUG ((EFI_D_WARN, "\nTftpDownload()  Exit #2  %xh (%r)", Status, Status));
 | |
| 
 | |
|     return EFI_PROTOCOL_ERROR;
 | |
|   } else {
 | |
|     //
 | |
|     // got good data packet
 | |
|     //
 | |
|     Offset    = ReplyLen;
 | |
|     //
 | |
|     // last block received
 | |
|     //
 | |
|     BlockNum  = 1;
 | |
|   }
 | |
| 
 | |
|   if (PacketSizePtr != NULL) {
 | |
|     *PacketSizePtr = ReplyLen;
 | |
|   }
 | |
|   //
 | |
|   // routine to read rest of file after a successful open (TFTP or MTFTP)
 | |
|   // sends ACK and gets next data packet until short packet arrives, then sends
 | |
|   // ACK and (hopefully) times out
 | |
|   // if first packet has been read, BufferPtr and BufferSize must reflect fact
 | |
|   //
 | |
|   Status = LockStepReceive (
 | |
|             Private,
 | |
|             ReplyLen,
 | |
|             BufferSizePtr,
 | |
|             Offset,
 | |
|             BufferPtr,
 | |
|             ServerIpPtr,
 | |
|             &ServerReplyPort,
 | |
|             &Private->EfiBc.Mode->StationIp,
 | |
|             &OurPort,
 | |
|             BlockNum,
 | |
|             ACK_TIMEOUT,
 | |
|             DontUseBuffer
 | |
|             );
 | |
| 
 | |
|   if (Status != EFI_SUCCESS) {
 | |
|     DEBUG ((EFI_D_WARN, "\nTftpDownload()  Exit #3  %xh (%r)", Status, Status));
 | |
| 
 | |
|     if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|       Status = TftpInfo (
 | |
|                 Private,
 | |
|                 BufferSizePtr,
 | |
|                 ServerIpPtr,
 | |
|                 SrvPort,
 | |
|                 FilenamePtr,
 | |
|                 PacketSizePtr
 | |
|                 );
 | |
| 
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         Status = EFI_BUFFER_TOO_SMALL;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| TftpUpload (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   UINT64              *BufferSizePtr,
 | |
|   VOID                *BufferPtr,
 | |
|   EFI_IP_ADDRESS      *ServerIpPtr,
 | |
|   UINT8               *FilenamePtr,
 | |
|   UINTN               *PacketSizePtr,
 | |
|   BOOLEAN             Overwrite
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
| // tftp write session
 | |
| // send write request
 | |
| // get OACK or ACK
 | |
| // loop
 | |
| //  send min (rest of data, max data packet)
 | |
| //  get ACK
 | |
| //  while data size is max
 | |
| 
 | |
| Parameters:
 | |
|   Private :=
 | |
|   BufferSizePtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr :=
 | |
|   FilenamePtr :=
 | |
|   PacketSizePtr :=
 | |
|   Overwrite :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   struct Tftpv4Ack            Header;
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  OurPort;
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  ServerReplyPort;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT64                      BlockNum;
 | |
|   UINT64                      TransferSize;
 | |
|   UINTN                       ReplyLen;
 | |
|   UINTN                       TransferLen;
 | |
|   UINT16                      Options;
 | |
|   UINT8                       *Ptr;
 | |
| 
 | |
|   union {
 | |
|     struct Tftpv4Oack OAck2Ptr;
 | |
|     struct Tftpv4Ack  Ack2Ptr;
 | |
|     struct Tftpv4Data Datastr;
 | |
|   } u;
 | |
| 
 | |
|   OurPort         = 0;
 | |
|   ServerReplyPort = 0;
 | |
|   TransferSize    = *BufferSizePtr;
 | |
|   ReplyLen        = sizeof (u.Datastr.Data);
 | |
|   Options         = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);
 | |
| 
 | |
|   //
 | |
|   // send a write request with the blocksize option - sets our IP and port -
 | |
|   // and receive reply - sets his port
 | |
|   // will retry operation up to 3 times if no response, and will retry without
 | |
|   // options on an error reply
 | |
|   //
 | |
|   if ((Status = TftpRwReqwResp (
 | |
|                   TFTP_WRQ,
 | |
|                   Options,
 | |
|                   Private,
 | |
|                   &u,
 | |
|                   PacketSizePtr,
 | |
|                   &ReplyLen,
 | |
|                   u.Datastr.Data,
 | |
|                   ServerIpPtr,
 | |
|                   &TftpRequestPort,
 | |
|                   &ServerReplyPort,
 | |
|                   &OurPort,
 | |
|                   FilenamePtr,
 | |
|                   REQ_RESP_TIMEOUT
 | |
|                   )) != EFI_SUCCESS) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // check for OACK
 | |
|   //
 | |
|   if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
 | |
|     //
 | |
|     // parse it for blocksize option
 | |
|     //
 | |
|     Ptr = FindOption (
 | |
|             BlockSizeOp,
 | |
|             sizeof (BlockSizeOp),
 | |
|             u.OAck2Ptr.OpAck[0].Option,
 | |
|             ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
 | |
|             );
 | |
|     *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
 | |
|   }
 | |
|   //
 | |
|   // or ACK
 | |
|   //
 | |
|   else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {
 | |
|     //
 | |
|     // option was not supported
 | |
|     //
 | |
|     *PacketSizePtr = 512;
 | |
|   } else {
 | |
|     return EFI_PROTOCOL_ERROR;
 | |
|   }
 | |
|   //
 | |
|   // loop
 | |
|   //
 | |
|   Header.OpCode   = HTONS (TFTP_DATA);
 | |
|   BlockNum        = 1;
 | |
|   Header.BlockNum = HTONS (1);
 | |
| 
 | |
|   do {
 | |
|     UINTN HeaderSize;
 | |
|     INTN  Retries;
 | |
| 
 | |
|     Retries     = NUM_ACK_RETRIES;
 | |
|     HeaderSize  = sizeof (Header);
 | |
|     TransferLen = (UINTN) (EFI_MIN (*PacketSizePtr, TransferSize));
 | |
| 
 | |
|     //
 | |
|     // write a data packet and get an ack
 | |
|     //
 | |
|     do {
 | |
|       //
 | |
|       // write
 | |
|       //
 | |
|       if ((Status = UdpWrite (
 | |
|                       Private,
 | |
|                       EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
 | |
|                       ServerIpPtr,
 | |
|                       &ServerReplyPort,
 | |
|                       0,
 | |
|                       0,
 | |
|                       &OurPort,
 | |
|                       &HeaderSize,
 | |
|                       &Header,
 | |
|                       &TransferLen,
 | |
|                       BufferPtr
 | |
|                       )) != EFI_SUCCESS) {
 | |
|         return Status;
 | |
|       }
 | |
|       //
 | |
|       // read reply
 | |
|       //
 | |
|       ReplyLen = sizeof (u.Datastr.Data);
 | |
| 
 | |
|       if ((Status = TftpUdpRead (
 | |
|                       Private,
 | |
|                       0,
 | |
|                       &u,
 | |
|                       &ReplyLen,
 | |
|                       u.Datastr.Data,
 | |
|                       ServerIpPtr,
 | |
|                       &ServerReplyPort,
 | |
|                       0,
 | |
|                       &OurPort,
 | |
|                       ACK_TIMEOUT
 | |
|                       )) == EFI_SUCCESS) {
 | |
|         //
 | |
|         // check for ACK for this data packet
 | |
|         //
 | |
|         if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {
 | |
|           return EFI_PROTOCOL_ERROR;
 | |
|         }
 | |
| 
 | |
|         if (u.Ack2Ptr.BlockNum != Header.BlockNum) {
 | |
|           //
 | |
|           // not for this packet - continue
 | |
|           //
 | |
|           Status = EFI_TIMEOUT;
 | |
|         }
 | |
|       }
 | |
|     } while (Status == EFI_TIMEOUT && --Retries);
 | |
| 
 | |
|     if (Status != EFI_SUCCESS) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);
 | |
|     TransferSize -= TransferLen;
 | |
|     ++BlockNum;
 | |
|     Header.BlockNum = HTONS ((UINT16) BlockNum);
 | |
|   } while (TransferLen == *PacketSizePtr);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| PxeBcMtftp (
 | |
|   PXE_BASECODE_DEVICE               *Private,
 | |
|   IN EFI_PXE_BASE_CODE_TFTP_OPCODE  Operation,
 | |
|   UINT64                            *BufferSizePtr,
 | |
|   VOID                              *BufferPtr,
 | |
|   EFI_IP_ADDRESS                    *ServerIpPtr,
 | |
|   UINT8                             *FilenamePtr,
 | |
|   UINTN                             *PacketSizePtr,
 | |
|   IN EFI_PXE_BASE_CODE_MTFTP_INFO   *MtftpInfoPtr, OPTIONAL
 | |
|   IN BOOLEAN                        Overwrite,
 | |
|   IN BOOLEAN                        DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   MTFTP API entry point
 | |
| 
 | |
| Parameters:
 | |
|   Private :=
 | |
|   Operation :=
 | |
|   BufferSizePtr :=
 | |
|   BufferPtr :=
 | |
|   ServerIpPtr :=
 | |
|   FilenamePtr :=
 | |
|   PacketSizePtr :=
 | |
|   MtftpInfoPtr :=
 | |
|   Overwrite :=
 | |
|   DontUseBuffer :=
 | |
| 
 | |
| Returns:
 | |
|  *  EFI_INVALID_PARAMETER
 | |
|  *  EFI_OUT_OF_RESOURCES
 | |
|  *  EFI_BAD_BUFFER_SIZE
 | |
|  *  Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
 | |
|  *  TftpDownload() and TftpUpload().
 | |
| --*/
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_IP_FILTER Filter;
 | |
|   EFI_STATUS                  StatCode;
 | |
|   UINT64                      BufferSizeLocal;
 | |
|   UINTN                       PacketSize;
 | |
|   UINT8                       *BufferPtrLocal;
 | |
| 
 | |
|   Filter.Filters  = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
 | |
|   Filter.IpCnt    = 0;
 | |
|   Filter.reserved = 0;
 | |
| 
 | |
|   /* No error has occurred, yet. */
 | |
|   Private->EfiBc.Mode->TftpErrorReceived = FALSE;
 | |
| 
 | |
|   /* We must at least have an MTFTP server IP address and
 | |
|    * a pointer to the buffer size.
 | |
|    */
 | |
|   if (!ServerIpPtr || !BufferSizePtr) {
 | |
|     DEBUG ((EFI_D_WARN, "\nPxeBcMtftp()  Exit #1"));
 | |
| 
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;
 | |
| 
 | |
|   //
 | |
|   // make sure filter set to unicast at start
 | |
|   //
 | |
|   if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
 | |
|     DEBUG (
 | |
|       (EFI_D_NET,
 | |
|       "\nPxeBcMtftp()  Exit  IpFilter() == %Xh",
 | |
|       StatCode)
 | |
|       );
 | |
| 
 | |
|     return StatCode;
 | |
|   }
 | |
|   //
 | |
|   // set unset parms to default values
 | |
|   //
 | |
|   if (!PacketSizePtr) {
 | |
|     *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (*PacketSizePtr > *BufferSizePtr) {
 | |
|     *PacketSizePtr = (UINTN) *BufferSizePtr;
 | |
|   }
 | |
| 
 | |
|   if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {
 | |
|     *PacketSizePtr = MIN_TFTP_PKT_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {
 | |
|     *PacketSizePtr = BUFFER_ALLOCATE_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {
 | |
|     *PacketSizePtr = MAX_TFTP_PKT_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
 | |
|     StatCode = TftpInfo (
 | |
|                 Private,
 | |
|                 BufferSizePtr,
 | |
|                 ServerIpPtr,
 | |
|                 TftpRequestPort,
 | |
|                 FilenamePtr,
 | |
|                 PacketSizePtr
 | |
|                 );
 | |
| 
 | |
|     if (StatCode != EFI_SUCCESS) {
 | |
|       DEBUG (
 | |
|         (EFI_D_WARN,
 | |
|         "\nPxeBcMtftp()  Exit  TftpInfo() == %Xh",
 | |
|         StatCode)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     return StatCode;
 | |
|   }
 | |
| 
 | |
|   if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {
 | |
|     if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {
 | |
|       DEBUG ((EFI_D_WARN, "\nPxeBcMtftp()  Exit #2"));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     } else {
 | |
|       StatCode = TftpInfo (
 | |
|                   Private,
 | |
|                   BufferSizePtr,
 | |
|                   ServerIpPtr,
 | |
|                   MtftpInfoPtr->SPort,
 | |
|                   FilenamePtr,
 | |
|                   PacketSizePtr
 | |
|                   );
 | |
| 
 | |
|       gBS->Stall (10000);
 | |
| 
 | |
|       if (StatCode != EFI_SUCCESS) {
 | |
|         DEBUG (
 | |
|           (EFI_D_WARN,
 | |
|           "\nPxeBcMtftp()  Exit  TftpInfo() == %Xh",
 | |
|           StatCode)
 | |
|           );
 | |
|       }
 | |
| 
 | |
|       return StatCode;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!BufferPtr && !DontUseBuffer) {
 | |
|     //
 | |
|     // if dontusebuffer is false and no buffer???
 | |
|     //
 | |
|     DEBUG ((EFI_D_WARN, "\nPxeBcMtftp()  Exit #3"));
 | |
|     //
 | |
|     // DontUseBuffer can be true only for read_file operation
 | |
|     //
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (DontUseBuffer) {
 | |
|     BufferPtrLocal = AllocatePool (BUFFER_ALLOCATE_SIZE);
 | |
|     if (BufferPtrLocal == NULL) {
 | |
|       DEBUG ((EFI_D_NET, "\nPxeBcMtftp()  Exit #4"));
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     BufferSizeLocal = BUFFER_ALLOCATE_SIZE;
 | |
|   } else {
 | |
|     if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {
 | |
|       DEBUG ((EFI_D_WARN, "\nPxeBcMtftp()  Exit #5"));
 | |
|       return EFI_BAD_BUFFER_SIZE;
 | |
|     }
 | |
| 
 | |
|     BufferPtrLocal  = BufferPtr;
 | |
|     BufferSizeLocal = *BufferSizePtr;
 | |
|   }
 | |
| 
 | |
|   switch (Operation) {
 | |
|   case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
 | |
|     if (FilenamePtr == NULL ||
 | |
|         MtftpInfoPtr == NULL ||
 | |
|         MtftpInfoPtr->MCastIp.Addr[0] == 0 ||
 | |
|         MtftpInfoPtr->SPort == 0 ||
 | |
|         MtftpInfoPtr->CPort == 0 ||
 | |
|         MtftpInfoPtr->ListenTimeout == 0 ||
 | |
|         MtftpInfoPtr->TransmitTimeout == 0
 | |
|         ) {
 | |
|       StatCode = EFI_INVALID_PARAMETER;
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // try MTFTP - if fails, drop into TFTP read
 | |
|     //
 | |
|     if ((StatCode = MtftpDownload (
 | |
|                       Private,
 | |
|                       &BufferSizeLocal,
 | |
|                       BufferPtrLocal,
 | |
|                       ServerIpPtr,
 | |
|                       FilenamePtr,
 | |
|                       MtftpInfoPtr,
 | |
|                       DontUseBuffer
 | |
|                       )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
 | |
|       if (BufferSizePtr /* %% !DontUseBuffer */ ) {
 | |
|         *BufferSizePtr = BufferSizeLocal;
 | |
|       }
 | |
| 
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // go back to unicast
 | |
|     //
 | |
|     if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   /* fall thru */
 | |
|   case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
 | |
|     if (FilenamePtr == NULL) {
 | |
|       StatCode = EFI_INVALID_PARAMETER;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     StatCode = TftpDownload (
 | |
|                 Private,
 | |
|                 &BufferSizeLocal,
 | |
|                 BufferPtrLocal,
 | |
|                 ServerIpPtr,
 | |
|                 FilenamePtr,
 | |
|                 PacketSizePtr,
 | |
|                 TftpRequestPort,
 | |
|                 TFTP_RRQ,
 | |
|                 DontUseBuffer
 | |
|                 );
 | |
| 
 | |
|     if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
 | |
|       if (BufferSizePtr /* !DontUseBuffer */ ) {
 | |
|         *BufferSizePtr = BufferSizeLocal;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
 | |
|     if (FilenamePtr == NULL || DontUseBuffer) {
 | |
|       //
 | |
|       // not a valid option
 | |
|       //
 | |
|       StatCode = EFI_INVALID_PARAMETER;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     StatCode = TftpUpload (
 | |
|                 Private,
 | |
|                 BufferSizePtr,
 | |
|                 BufferPtr,
 | |
|                 ServerIpPtr,
 | |
|                 FilenamePtr,
 | |
|                 PacketSizePtr,
 | |
|                 Overwrite
 | |
|                 );
 | |
| 
 | |
|     if (StatCode != EFI_SUCCESS) {
 | |
|       DEBUG (
 | |
|         (EFI_D_WARN,
 | |
|         "\nPxeBcMtftp()  Exit #6  %xh (%r)",
 | |
|         StatCode,
 | |
|         StatCode)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     return StatCode;
 | |
| 
 | |
|   case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
 | |
|     if (FilenamePtr == NULL || DontUseBuffer) {
 | |
|       //
 | |
|       // not a valid option
 | |
|       //
 | |
|       StatCode = EFI_INVALID_PARAMETER;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     StatCode = TftpDownload (
 | |
|                 Private,
 | |
|                 BufferSizePtr,
 | |
|                 BufferPtr,
 | |
|                 ServerIpPtr,
 | |
|                 FilenamePtr,
 | |
|                 PacketSizePtr,
 | |
|                 TftpRequestPort,
 | |
|                 TFTP_DIR,
 | |
|                 DontUseBuffer
 | |
|                 );
 | |
| 
 | |
|     if (StatCode != EFI_SUCCESS) {
 | |
|       DEBUG (
 | |
|         (EFI_D_WARN,
 | |
|         "\nPxeBcMtftp()  Exit #7  %xh (%r)",
 | |
|         StatCode,
 | |
|         StatCode)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     return StatCode;
 | |
| 
 | |
|   case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
 | |
|     if (DontUseBuffer) {
 | |
|       StatCode = EFI_INVALID_PARAMETER;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {
 | |
|       DEBUG (
 | |
|         (EFI_D_WARN,
 | |
|         "\nPxeBcMtftp()  Exit #9  %xh (%r)",
 | |
|         EFI_INVALID_PARAMETER,
 | |
|         EFI_INVALID_PARAMETER)
 | |
|         );
 | |
| 
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     StatCode = TftpDownload (
 | |
|                 Private,
 | |
|                 BufferSizePtr,
 | |
|                 BufferPtr,
 | |
|                 ServerIpPtr,
 | |
|                 (UINT8 *) "/",
 | |
|                 PacketSizePtr,
 | |
|                 MtftpInfoPtr->SPort,
 | |
|                 TFTP_DIR,
 | |
|                 DontUseBuffer
 | |
|                 );
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     StatCode = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (DontUseBuffer) {
 | |
|     FreePool (BufferPtrLocal);
 | |
|   }
 | |
| 
 | |
|   if (StatCode != EFI_SUCCESS) {
 | |
|     DEBUG (
 | |
|       (EFI_D_WARN,
 | |
|       "\nPxeBcMtftp()  Exit #8  %xh (%r)",
 | |
|       StatCode,
 | |
|       StatCode)
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   gBS->Stall (10000);
 | |
| 
 | |
|   return StatCode;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BcMtftp (
 | |
|   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
 | |
|   IN EFI_PXE_BASE_CODE_TFTP_OPCODE    Operation,
 | |
|   IN OUT VOID                         *BufferPtr,
 | |
|   IN BOOLEAN                          Overwrite,
 | |
|   IN OUT UINT64                       *BufferSizePtr,
 | |
|   IN UINTN                            *BlockSizePtr OPTIONAL,
 | |
|   IN EFI_IP_ADDRESS                   * ServerIpPtr,
 | |
|   IN UINT8                            *FilenamePtr,
 | |
|   IN EFI_PXE_BASE_CODE_MTFTP_INFO     * MtftpInfoPtr OPTIONAL,
 | |
|   IN BOOLEAN                          DontUseBuffer
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   MTFTP API entry point.
 | |
| 
 | |
| Parameters:
 | |
|   This :=
 | |
|   Operation :=
 | |
|   BufferPtr :=
 | |
|   Overwrite :=
 | |
|   BufferSizePtr :=
 | |
|   BlockSizePtr :=
 | |
|   ServerIpPtr :=
 | |
|   FilenamePtr :=
 | |
|   MtftpInfoPtr :=
 | |
|   DontUseBuffer :=
 | |
| 
 | |
| Returns:
 | |
|  *  EFI_INVALID_PARAMETER
 | |
|  *  Status is also returned from PxeBcMtftp();
 | |
| --*/
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_IP_FILTER Filter;
 | |
|   EFI_STATUS                  StatCode;
 | |
|   PXE_BASECODE_DEVICE         *Private;
 | |
| 
 | |
|   //
 | |
|   // Lock the instance data and make sure started
 | |
|   //
 | |
|   StatCode = EFI_SUCCESS;
 | |
| 
 | |
|   if (This == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
 | |
| 
 | |
|   if (Private == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   EfiAcquireLock (&Private->Lock);
 | |
| 
 | |
|   if (This->Mode == NULL || !This->Mode->Started) {
 | |
|     DEBUG ((EFI_D_ERROR, "BC was not started."));
 | |
|     EfiReleaseLock (&Private->Lock);
 | |
|     return EFI_NOT_STARTED;
 | |
|   }
 | |
|   //
 | |
|   // Issue BC command
 | |
|   //
 | |
|   Filter.Filters  = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
 | |
|   Filter.IpCnt    = 0;
 | |
|   Filter.reserved = 0;
 | |
| 
 | |
|   DEBUG ((EFI_D_WARN, "\nBcMtftp()  Op=%d  Buf=%Xh", Operation, BufferPtr));
 | |
| 
 | |
|   StatCode = PxeBcMtftp (
 | |
|               Private,
 | |
|               Operation,
 | |
|               BufferSizePtr,
 | |
|               BufferPtr,
 | |
|               ServerIpPtr,
 | |
|               FilenamePtr,
 | |
|               BlockSizePtr,
 | |
|               MtftpInfoPtr,
 | |
|               Overwrite,
 | |
|               DontUseBuffer
 | |
|               );
 | |
| 
 | |
|   //
 | |
|   // restore to unicast
 | |
|   //
 | |
|   IpFilter (Private, &Filter);
 | |
| 
 | |
|   //
 | |
|   // Unlock the instance data
 | |
|   //
 | |
|   EfiReleaseLock (&Private->Lock);
 | |
|   return StatCode;
 | |
| }
 | |
| 
 | |
| /* eof - PxeBcMtftp.c */
 |