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 + -
显示快捷键?