pxe_bc_mtftp.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,396 行 · 第 1/5 页

C
2,396
字号

    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
      //
      EfiZeroMem (&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 (!EfiCompareMem (
              &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 (!EfiCompareMem (
                    &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;
  Filter.IpList[0]  = Private->EfiBc.Mode->StationIp;
  Filter.IpList[1]  = MtftpInfoPtr->MCastIp;

  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;

    }
    //
    // special !!! do not leave enabled in saved version on Source Safe
    // Following code put in in order to create a special version for regression
    // test of MTFTP server to make sure it handles mulitple opens correctly.
    // This code should NOT be enabled normally.
    //
#ifdef SpecialNowaitVersion
#pragma message ("This is special version for MTFTP regression test")
    if (StartBlock || !LastBlock)
#endif
      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 && BufferSize < 0) {
        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,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?