pxe_bc_mtftp.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,396 行 · 第 1/5 页
C
2,396 行
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,
(INT8 *) &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
//
EfiCopyMem (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;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?