Windows-Server-2003/base/boot/tftplib/tftp.c

512 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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_)