512 lines
11 KiB
C
512 lines
11 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
tftp.c
|
||
|
||
Abstract:
|
||
|
||
Boot loader TFTP routines.
|
||
|
||
Author:
|
||
|
||
Chuck Lenzmeier (chuckl) December 27, 1996
|
||
|
||
Revision History:
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// This removes macro redefinitions which appear because we define __RPC_DOS__,
|
||
// but rpc.h defines __RPC_WIN32__
|
||
//
|
||
|
||
#pragma warning(disable:4005)
|
||
|
||
//
|
||
// As of 12/17/98, SECURITY_DOS is *not* defined - adamba
|
||
//
|
||
|
||
#if defined(SECURITY_DOS)
|
||
//
|
||
// These appear because we defined SECURITY_DOS
|
||
//
|
||
|
||
#define __far
|
||
#define __pascal
|
||
#define __loadds
|
||
#endif
|
||
|
||
#include <security.h>
|
||
#include <rpc.h>
|
||
#include <spseal.h>
|
||
|
||
#if defined(_X86_)
|
||
#include <bldrx86.h>
|
||
#endif
|
||
|
||
#if defined(SECURITY_DOS)
|
||
//
|
||
// PSECURITY_STRING is not supposed to be used when SECURITY_DOS is
|
||
// defined -- it should be a WCHAR*. Unfortunately ntlmsp.h breaks
|
||
// this rule and even uses the SECURITY_STRING structure, which there
|
||
// is really no equivalent for in 16-bit mode.
|
||
//
|
||
|
||
typedef SEC_WCHAR * SECURITY_STRING; // more-or-less the intention where it is used
|
||
typedef SEC_WCHAR * PSECURITY_STRING;
|
||
#endif
|
||
|
||
#include <ntlmsp.h>
|
||
|
||
#if DBG
|
||
ULONG NetDebugFlag =
|
||
DEBUG_ERROR |
|
||
DEBUG_CONN_ERROR |
|
||
//DEBUG_LOUD |
|
||
//DEBUG_REAL_LOUD |
|
||
//DEBUG_STATISTICS |
|
||
//DEBUG_SEND_RECEIVE |
|
||
//DEBUG_TRACE |
|
||
//DEBUG_ARP |
|
||
//DEBUG_INITIAL_BREAK |
|
||
0;
|
||
#endif
|
||
|
||
//
|
||
// Global variables
|
||
//
|
||
|
||
CONNECTION NetTftpConnection;
|
||
|
||
UCHAR NetTftpPacket[3][MAXIMUM_TFTP_PACKET_LENGTH];
|
||
|
||
//
|
||
// Local declarations.
|
||
//
|
||
|
||
NTSTATUS
|
||
TftpGet (
|
||
IN PCONNECTION Connection,
|
||
IN PTFTP_REQUEST Request
|
||
);
|
||
|
||
NTSTATUS
|
||
TftpPut (
|
||
IN PCONNECTION Connection,
|
||
IN PTFTP_REQUEST Request
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
TftpGetPut (
|
||
IN PTFTP_REQUEST Request
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PCONNECTION connection = NULL;
|
||
ULONG FileSize;
|
||
ULONG basePage;
|
||
#if 0 && DBG
|
||
LARGE_INTEGER startTime;
|
||
LARGE_INTEGER endTime;
|
||
LARGE_INTEGER elapsedTime;
|
||
LARGE_INTEGER frequency;
|
||
ULONG seconds;
|
||
ULONG secondsFraction;
|
||
ULONG bps;
|
||
ULONG bpsFraction;
|
||
#endif
|
||
|
||
#ifndef EFI
|
||
//
|
||
// We don't need to do any of this initialization if
|
||
// we're in EFI.
|
||
//
|
||
|
||
FileSize = Request->MaximumLength;
|
||
|
||
status = ConnInitialize(
|
||
&connection,
|
||
Request->Operation,
|
||
Request->ServerIpAddress,
|
||
TFTP_PORT,
|
||
Request->RemoteFileName,
|
||
0,
|
||
&FileSize
|
||
);
|
||
if ( !NT_SUCCESS(status) ) {
|
||
return status;
|
||
}
|
||
|
||
#if 0 && DBG
|
||
IF_DEBUG(STATISTICS) {
|
||
startTime = KeQueryPerformanceCounter( &frequency );
|
||
}
|
||
#endif
|
||
|
||
if ( Request->Operation == TFTP_RRQ ) {
|
||
|
||
if ( Request->MemoryAddress != NULL ) {
|
||
|
||
if ( Request->MaximumLength < FileSize ) {
|
||
ConnError(
|
||
connection,
|
||
connection->RemoteHost,
|
||
connection->RemotePort,
|
||
TFTP_ERROR_UNDEFINED,
|
||
"File too big"
|
||
);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// NB: (ChuckL) Removed code added by MattH to check for
|
||
// allocation >= 1/3 of (BlUsableLimit - BlUsableBase)
|
||
// because calling code now sets BlUsableLimit to 1 GB
|
||
// or higher.
|
||
//
|
||
|
||
|
||
status = BlAllocateAlignedDescriptor(
|
||
Request->MemoryType,
|
||
0,
|
||
BYTES_TO_PAGES(FileSize),
|
||
0,
|
||
&basePage
|
||
);
|
||
|
||
if (status != ESUCCESS) {
|
||
ConnError(
|
||
connection,
|
||
connection->RemoteHost,
|
||
connection->RemotePort,
|
||
TFTP_ERROR_UNDEFINED,
|
||
"File too big"
|
||
);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Request->MemoryAddress = (PUCHAR)(KSEG0_BASE | (basePage << PAGE_SHIFT));
|
||
Request->MaximumLength = FileSize;
|
||
DPRINT( REAL_LOUD, ("TftpGetPut: allocated %d bytes at 0x%08x\n",
|
||
Request->MaximumLength, Request->MemoryAddress) );
|
||
}
|
||
|
||
status = TftpGet( connection, Request );
|
||
|
||
} else {
|
||
|
||
status = TftpPut( connection, Request );
|
||
}
|
||
|
||
#else // #ifndef EFI
|
||
|
||
if ( Request->Operation == TFTP_RRQ ) {
|
||
|
||
status = TftpGet( connection, Request );
|
||
} else {
|
||
|
||
status = TftpPut( connection, Request );
|
||
}
|
||
|
||
if( status != STATUS_SUCCESS ) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
#endif // #ifndef EFI
|
||
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
return status;
|
||
}
|
||
|
||
return status;
|
||
|
||
} // TftpGetPut
|
||
|
||
|
||
//#if 0
|
||
#ifdef EFI
|
||
|
||
extern VOID
|
||
FlipToPhysical (
|
||
);
|
||
|
||
extern VOID
|
||
FlipToVirtual (
|
||
);
|
||
|
||
NTSTATUS
|
||
TftpGet (
|
||
IN OUT PCONNECTION Connection,
|
||
IN PTFTP_REQUEST Request
|
||
)
|
||
{
|
||
EFI_STATUS Status;
|
||
CHAR16 *Size = NULL;
|
||
PVOID MyBuffer = NULL;
|
||
EFI_IP_ADDRESS MyServerIpAddress;
|
||
INTN Count = 0;
|
||
INTN BufferSizeX = sizeof(CHAR16);
|
||
ULONG basePage;
|
||
UINTN BlockSize = 512;
|
||
|
||
//
|
||
// They sent us an IP address as a ULONG. We need to convert
|
||
// that into an EFI_IP_ADDRESS.
|
||
//
|
||
for( Count = 0; Count < 4; Count++ ) {
|
||
MyServerIpAddress.v4.Addr[Count] = PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
|
||
}
|
||
|
||
|
||
//
|
||
// Get the file size, allocate some memory, then get the file.
|
||
//
|
||
FlipToPhysical();
|
||
Status = PXEClient->Mtftp( PXEClient,
|
||
EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
|
||
Size,
|
||
TRUE,
|
||
&BufferSizeX,
|
||
&BlockSize,
|
||
&MyServerIpAddress,
|
||
Request->RemoteFileName,
|
||
0,
|
||
FALSE );
|
||
FlipToVirtual();
|
||
|
||
|
||
if( Status != EFI_SUCCESS ) {
|
||
|
||
return (NTSTATUS)Status;
|
||
|
||
}
|
||
|
||
Status = BlAllocateAlignedDescriptor(
|
||
Request->MemoryType,
|
||
0,
|
||
(ULONG) BYTES_TO_PAGES(BufferSizeX),
|
||
0,
|
||
&basePage
|
||
);
|
||
|
||
if ( Status != ESUCCESS ) {
|
||
|
||
if( BdDebuggerEnabled ) {
|
||
DbgPrint( "TftpGet: BlAllocate failed! (%d)\n", Status );
|
||
}
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Request->MemoryAddress = (PUCHAR)(KSEG0_BASE | ((ULONGLONG)basePage << PAGE_SHIFT) );
|
||
Request->MaximumLength = (ULONG)BufferSizeX;
|
||
|
||
//
|
||
// Make sure we send EFI a physical address.
|
||
//
|
||
MyBuffer = (PVOID)((ULONGLONG)(Request->MemoryAddress) & ~KSEG0_BASE);
|
||
|
||
FlipToPhysical();
|
||
Status = PXEClient->Mtftp( PXEClient,
|
||
EFI_PXE_BASE_CODE_TFTP_READ_FILE,
|
||
MyBuffer,
|
||
TRUE,
|
||
&BufferSizeX,
|
||
NULL,
|
||
&MyServerIpAddress,
|
||
Request->RemoteFileName,
|
||
0,
|
||
FALSE );
|
||
FlipToVirtual();
|
||
|
||
if( Status != EFI_SUCCESS ) {
|
||
|
||
if( BdDebuggerEnabled ) {
|
||
DbgPrint( "TftpGet: GetFile failed! (%d)\n", Status );
|
||
}
|
||
return (NTSTATUS)Status;
|
||
|
||
}
|
||
|
||
|
||
|
||
Request->BytesTransferred = (ULONG)BufferSizeX;
|
||
|
||
return (NTSTATUS)Status;
|
||
|
||
} // TftpGet
|
||
|
||
|
||
NTSTATUS
|
||
TftpPut (
|
||
IN OUT PCONNECTION Connection,
|
||
IN PTFTP_REQUEST Request
|
||
)
|
||
{
|
||
EFI_STATUS Status;
|
||
EFI_IP_ADDRESS MyServerIpAddress;
|
||
INTN Count = 0;
|
||
PVOID MyBuffer = NULL;
|
||
|
||
|
||
//
|
||
// They sent us an IP address as a ULONG. We need to convert
|
||
// that into an EFI_IP_ADDRESS.
|
||
//
|
||
for( Count = 0; Count < 4; Count++ ) {
|
||
MyServerIpAddress.v4.Addr[Count] = PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
|
||
}
|
||
|
||
//
|
||
// Make sure we send EFI a physical address.
|
||
//
|
||
MyBuffer = (PVOID)((ULONGLONG)(Request->MemoryAddress) & ~KSEG0_BASE);
|
||
|
||
FlipToPhysical();
|
||
Status = PXEClient->Mtftp( PXEClient,
|
||
EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
|
||
MyBuffer,
|
||
TRUE,
|
||
(UINTN *)(&Request->MaximumLength),
|
||
NULL,
|
||
&MyServerIpAddress,
|
||
Request->RemoteFileName,
|
||
0,
|
||
FALSE );
|
||
FlipToVirtual();
|
||
|
||
if( Status != EFI_SUCCESS ) {
|
||
|
||
if( BdDebuggerEnabled ) {
|
||
DbgPrint( "TftpPut: WriteFile failed! (%d)\n", Status );
|
||
}
|
||
|
||
}
|
||
|
||
return (NTSTATUS)Status;
|
||
|
||
} // TftpPut
|
||
|
||
#else //#ifdef EFI
|
||
|
||
NTSTATUS
|
||
TftpGet (
|
||
IN OUT PCONNECTION Connection,
|
||
IN PTFTP_REQUEST Request
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PTFTP_PACKET packet;
|
||
ULONG length;
|
||
ULONG offset;
|
||
PUCHAR packetData;
|
||
ULONG lastProgressPercent = -1;
|
||
ULONG currentProgressPercent;
|
||
|
||
DPRINT( TRACE, ("TftpGet\n") );
|
||
|
||
offset = 0;
|
||
|
||
if ( Request->ShowProgress ) {
|
||
BlUpdateProgressBar(0);
|
||
}
|
||
|
||
do {
|
||
|
||
status = ConnReceive( Connection, &packet );
|
||
if ( !NT_SUCCESS(status) ) {
|
||
break;
|
||
}
|
||
|
||
length = Connection->CurrentLength - 4;
|
||
|
||
packetData = packet->Data;
|
||
|
||
if ( (offset + length) > Request->MaximumLength ) {
|
||
length = Request->MaximumLength - offset;
|
||
}
|
||
|
||
RtlCopyMemory( Request->MemoryAddress + offset, packetData, length );
|
||
|
||
offset += length;
|
||
|
||
if ( Request->ShowProgress ) {
|
||
currentProgressPercent = (ULONG)(((ULONGLONG)offset * 100) / Request->MaximumLength);
|
||
if ( currentProgressPercent != lastProgressPercent ) {
|
||
BlUpdateProgressBar( currentProgressPercent );
|
||
}
|
||
lastProgressPercent = currentProgressPercent;
|
||
}
|
||
|
||
//
|
||
// End the loop when we get a packet smaller than the max size --
|
||
// the extra check is to handle the first packet (length == offset)
|
||
// since we get NTLMSSP_MESSAGE_SIGNATURE_SIZE bytes less.
|
||
//
|
||
|
||
} while ( (length == Connection->BlockSize));
|
||
|
||
Request->BytesTransferred = offset;
|
||
|
||
return status;
|
||
|
||
} // TftpGet
|
||
|
||
|
||
NTSTATUS
|
||
TftpPut (
|
||
IN OUT PCONNECTION Connection,
|
||
IN PTFTP_REQUEST Request
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PTFTP_PACKET packet;
|
||
ULONG length;
|
||
ULONG offset;
|
||
|
||
DPRINT( TRACE, ("TftpPut\n") );
|
||
|
||
offset = 0;
|
||
|
||
do {
|
||
|
||
packet = ConnPrepareSend( Connection );
|
||
|
||
length = Connection->BlockSize;
|
||
if ( (offset + length) > Request->MaximumLength ) {
|
||
length = Request->MaximumLength - offset;
|
||
}
|
||
|
||
RtlCopyMemory( packet->Data, Request->MemoryAddress + offset, length );
|
||
|
||
status = ConnSend( Connection, length );
|
||
if ( !NT_SUCCESS(status) ) {
|
||
break;
|
||
}
|
||
|
||
offset += length;
|
||
|
||
} while ( length == Connection->BlockSize );
|
||
|
||
Request->BytesTransferred = offset;
|
||
|
||
if ( NT_SUCCESS(status) ) {
|
||
status = ConnWaitForFinalAck( Connection );
|
||
}
|
||
|
||
return status;
|
||
|
||
} // TftpPut
|
||
#endif // #if defined(_IA64_)
|