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