pxe_bc_mtftp.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,396 行 · 第 1/5 页
C
2,396 行
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 (!EfiCompareMem (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 + EfiAsciiStrLen (FilenamePtr));
EfiCopyMem (u->ReqStr.FileName, FilenamePtr, Len);
Ptr = (UINT8 *) (u->ReqStr.FileName + Len);
EfiCopyMem (Ptr, Mode, sizeof (Mode));
Ptr += sizeof (Mode);
if (Options & BKSZOP) {
EfiCopyMem (Ptr, BlockSizeOp, sizeof (BlockSizeOp));
UtoA10 (*PacketSizePtr, Ptr + sizeof (BlockSizeOp));
TotalLen += (Len = 1 + EfiAsciiStrLen (Ptr + sizeof (BlockSizeOp)) + sizeof (BlockSizeOp));
Ptr += Len;
}
if (Options & TSIZEOP) {
EfiCopyMem (Ptr, TsizeOp, sizeof (TsizeOp));
EfiCopyMem (Ptr + sizeof (TsizeOp), "0", 2);
TotalLen += sizeof (TsizeOp) + 2;
Ptr += sizeof (TsizeOp) + 2;
}
if (Options & OVERWRITEOP) {
EfiCopyMem (Ptr, OverwriteOp, sizeof (OverwriteOp));
EfiCopyMem (Ptr + sizeof (OverwriteOp), "1", 2);
TotalLen += sizeof (OverwriteOp) + 2;
Ptr += sizeof (OverwriteOp) + 2;
}
if (Options & BIGBLKNUMOP) {
EfiCopyMem (Ptr, BigBlkNumOp, sizeof (BigBlkNumOp));
EfiCopyMem (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) {
if ((SaveReplyLen = (UINTN) BufferSize) < 0) {
//
// make sure we do not overrun buffer
//
SaveReplyLen = 0;
}
}
/* %%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;
EfiCopyMem (BufferPtr + Offset, BufferPtr, ReplyLen);
BufferPtr += Offset;
BufferSize -= Offset;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?