windows-nt/Source/XPSP1/NT/base/boot/tftplib/i386/rom.c
2020-09-26 16:20:57 +08:00

474 lines
12 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:
rom.c
Abstract:
Boot loader ROM routines.
Author:
Chuck Lenzmeier (chuckl) December 27, 1996
Revision History:
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
#include <bldrx86.h>
#define PhysToSeg(x) (USHORT)((ULONG)(x) >> 4) & 0xffff
#define PhysToOff(x) (USHORT)((ULONG)(x) & 0x0f)
#include <pxe_cmn.h>
#include <pxe_api.h>
#include <tftp_api.h>
#include <udp_api.h>
#include <undi_api.h>
#include <dhcp.h>
#include <pxe.h>
USHORT NetUnicastUdpDestinationPort = 0;
#if 0
USHORT NetMulticastUdpDestinationPort;
ULONG NetMulticastUdpDestinationAddress;
USHORT NetMulticastUdpSourcePort;
ULONG NetMulticastUdpSourceAddress;
#endif
#if 0 && DBG
#include <stdio.h>
VOID
RomDumpRawData (
IN PUCHAR DataStart,
IN ULONG DataLength,
IN ULONG Offset
);
ULONG RomMaxDumpLength = 64;
#endif
#if 0
//
// chuckl: Don't do this. We added it as part of a solution a problem
// with DEC cards and the boot floppy. We disabled broadcasts in
// startrom\i386\main.c so that the card wouldn't overflow and lock up,
// but we need to have broadcasts enabled in case the server needs to
// ARP us. The purpose of this routine is to enable/disable broadcasts
// during the receive loop, but that seems to put Compaq cards to sleep.
// So we need to leave broadcasts enabled all the time. The DEC card
// problem will have to be fixed another way.
//
VOID
RomSetBroadcastStatus(
BOOLEAN Enable
)
{
t_PXENV_UNDI_SET_PACKET_FILTER UndiSetPF;
USHORT status;
UndiSetPF.Status = 0;
if (Enable) {
UndiSetPF.filter = FLTR_DIRECTED | FLTR_BRDCST;
} else {
UndiSetPF.filter = FLTR_DIRECTED;
}
status = NETPC_ROM_SERVICES( PXENV_UNDI_SET_PACKET_FILTER, &UndiSetPF );
if ((status != 0) || (UndiSetPF.Status != 0)) {
DPRINT( ERROR, ("RomSetBroadcastStatus: set packet filter failed %lx, %lx\n", status, UndiSetPF.Status ));
}
}
#endif
VOID
RomSetReceiveStatus (
IN USHORT UnicastUdpDestinationPort
#if 0
,
IN USHORT MulticastUdpDestinationPort,
IN ULONG MulticastUdpDestinationAddress,
IN USHORT MulticastUdpSourcePort,
IN ULONG MulticastUdpSourceAddress
#endif
)
{
USHORT status;
PUCHAR multicastAddress;
union {
t_PXENV_UDP_OPEN UdpOpen;
t_PXENV_UNDI_SHUTDOWN UndiShutdown;
} command;
if ( UnicastUdpDestinationPort != 0 ) {
//
// If we haven't opened UDP in the ROM yet, do so now.
//
if ( NetUnicastUdpDestinationPort == 0 ) {
command.UdpOpen.Status = 0;
*(UINT32 *)command.UdpOpen.SrcIp = 0;
status = NETPC_ROM_SERVICES( PXENV_UDP_OPEN, &command );
if ( status != 0 ) {
DPRINT( ERROR, ("RomSetReceiveStatus: error %d from UDP_OPEN\n", status) );
}
}
NetUnicastUdpDestinationPort = UnicastUdpDestinationPort;
#if 0
NetMulticastUdpDestinationPort = MulticastUdpDestinationPort;
NetMulticastUdpDestinationAddress = MulticastUdpDestinationAddress;
NetMulticastUdpSourceAddress = MulticastUdpSourceAddress;
NetMulticastUdpSourceAddress = MulticastUdpSourceAddress;
#endif
} else {
//
// This is a loader shutdown notification. Shut the NIC down.
//
// NB: This is irreversible!
//
command.UndiShutdown.Status = 0;
status = NETPC_ROM_SERVICES( PXENV_UNDI_SHUTDOWN, &command );
}
return;
} // RomSetReceiveStatus
ULONG
RomSendUdpPacket (
IN PVOID Buffer,
IN ULONG Length,
IN ULONG RemoteHost,
IN USHORT RemotePort
)
{
USHORT status;
t_PXENV_UDP_WRITE command;
UCHAR tmpBuffer[MAXIMUM_TFTP_PACKET_LENGTH];
#if 0 && DBG
DPRINT( SEND_RECEIVE, ("RomSendUdpPacket: sending this packet:\n") );
IF_DEBUG(SEND_RECEIVE) {
RomDumpRawData( Buffer, Length, 0 );
}
#endif
Length = ( MAXIMUM_TFTP_PACKET_LENGTH < Length ) ? MAXIMUM_TFTP_PACKET_LENGTH : Length;
RtlCopyMemory( tmpBuffer, Buffer, Length );
command.Status = 0;
//
// Determine whether we need to send via the gateway.
//
if ( (RemoteHost & NetLocalSubnetMask) == (NetLocalIpAddress & NetLocalSubnetMask) ) {
*(UINT32 *)command.GatewayIp = 0;
} else {
*(UINT32 *)command.GatewayIp = NetGatewayIpAddress;
}
*(UINT32 *)command.DestIp = RemoteHost;
command.DestPort = RemotePort;
command.SrcPort = NetUnicastUdpDestinationPort;
command.BufferSize = (USHORT)Length;
command.BufferOffset = PhysToOff(tmpBuffer);
command.BufferSegment = PhysToSeg(tmpBuffer);
//DbgPrint( "UDP write pktaddr %lx = %x:%x\n", tmpBuffer, command.BufferSegment, command.BufferOffset );
status = NETPC_ROM_SERVICES( PXENV_UDP_WRITE, &command );
//DbgPrint( "UDP write status = %x\n", command.Status );
if ( status == 0 ) {
return Length;
} else {
return 0;
}
} // RomSendUdpPacket
ULONG
RomReceiveUdpPacket (
IN PVOID Buffer,
IN ULONG Length,
IN ULONG Timeout,
OUT PULONG RemoteHost,
OUT PUSHORT RemotePort
)
{
USHORT status;
t_PXENV_UDP_READ command;
ULONG startTime;
UCHAR tmpBuffer[MAXIMUM_TFTP_PACKET_LENGTH];
//
// Turn on broadcasts while in the receive loop, in case
// the other end needs to ARP to find us.
//
#if 0
RomSetBroadcastStatus(TRUE);
#endif
startTime = SysGetRelativeTime();
if ( Timeout < 2 ) Timeout = 2;
while ( (SysGetRelativeTime() - startTime) < Timeout ) {
command.Status = 0;
*(UINT32 *)command.SrcIp = 0;
*(UINT32 *)command.DestIp = 0;
command.SrcPort = 0;
command.DestPort = 0;
command.BufferSize = (USHORT)Length;
command.BufferOffset = PhysToOff(tmpBuffer);
command.BufferSegment = PhysToSeg(tmpBuffer);
//DbgPrint( "UDP read pktaddr %lx = %x:%x\n", tmpBuffer, command.BufferSegment, command.BufferOffset );
status = NETPC_ROM_SERVICES( PXENV_UDP_READ, &command );
if ( *(UINT32 *)command.SrcIp == 0 ) {
continue;
}
//DbgPrint( "UDP read status = %x, src ip/port = %d.%d.%d.%d/%d, length = %x\n", command.Status,
// command.SrcIp[0], command.SrcIp[1], command.SrcIp[2], command.SrcIp[3],
// SWAP_WORD(command.SrcPort), command.BufferSize );
//DbgPrint( " dest ip/port = %d.%d.%d.%d/%d\n",
// command.DestIp[0], command.DestIp[1], command.DestIp[2], command.DestIp[3],
// SWAP_WORD(command.DestPort) );
#if 0
if ( (command.DestIp[0] < 224) || (command.DestIp[0] > 239) ) {
#endif
//
// This is a directed IP packet.
//
if ( !COMPARE_IP_ADDRESSES(command.DestIp, &NetLocalIpAddress) ||
(command.DestPort != NetUnicastUdpDestinationPort)
) {
// DPRINT( ERROR, (" Directed UDP packet to wrong port\n") );
continue;
}
#if 0
} else {
//
// This is a multicast IP packet.
//
if ( !COMPARE_IP_ADDRESSES(command.SrcIp, &NetMulticastUdpSourceAddress) ||
!COMPARE_IP_ADDRESSES(command.DestIp, &NetMulticastUdpDestinationAddress) ||
(command.SrcPort != NetMulticastUdpSourcePort) ||
(command.DestPort != NetMulticastUdpDestinationPort) ) {
DPRINT( ERROR, (" Multicast UDP packet with wrong source/destination\n") );
continue;
}
}
#endif
//
// We want this packet.
//
goto packet_received;
}
//
// Timeout.
//
DPRINT( SEND_RECEIVE, ("RomReceiveUdpPacket: timeout\n") );
#if 0
RomSetBroadcastStatus(FALSE); // turn off broadcast reception
#endif
return 0;
packet_received:
//
// Packet received.
//
RtlCopyMemory( Buffer, tmpBuffer, command.BufferSize );
*RemoteHost = *(UINT32 *)command.SrcIp;
*RemotePort = command.SrcPort;
#if 0 && DBG
if ( command.BufferSize != 0 ) {
DPRINT( SEND_RECEIVE, ("RomReceiveUdpPacket: received this packet:\n") );
IF_DEBUG(SEND_RECEIVE) {
RomDumpRawData( Buffer, command.BufferSize, 0 );
}
}
#endif
#if 0
RomSetBroadcastStatus(FALSE); // turn off broadcast reception
#endif
return command.BufferSize;
} // RomReceiveUdpPacket
ULONG
RomGetNicType (
OUT t_PXENV_UNDI_GET_NIC_TYPE *NicType
)
{
return NETPC_ROM_SERVICES( PXENV_UNDI_GET_NIC_TYPE, NicType );
}
#if 0 && DBG
VOID
RomDumpRawData (
IN PUCHAR DataStart,
IN ULONG DataLength,
IN ULONG Offset
)
{
ULONG lastByte;
UCHAR lineBuffer[88];
PUCHAR bufferPtr;
if ( DataLength > RomMaxDumpLength ) {
DataLength = RomMaxDumpLength;
}
for ( lastByte = Offset + DataLength; Offset < lastByte; Offset += 16 ) {
ULONG i;
bufferPtr = lineBuffer;
sprintf( bufferPtr, " %08x %04x: ", &DataStart[Offset], Offset );
bufferPtr += 18;
for ( i = 0; i < 16 && Offset + i < lastByte; i++ ) {
sprintf( bufferPtr, "%02x", (UCHAR)DataStart[Offset + i] & (UCHAR)0xFF );
bufferPtr += 2;
if ( i == 7 ) {
*bufferPtr++ = '-';
} else {
*bufferPtr++ = ' ';
}
}
//
// Print enough spaces so that the ASCII display lines up.
//
for ( ; i < 16; i++ ) {
*bufferPtr++ = ' ';
*bufferPtr++ = ' ';
*bufferPtr++ = ' ';
}
*bufferPtr++ = ' ';
*bufferPtr++ = ' ';
*bufferPtr++ = '*';
for ( i = 0; i < 16 && Offset + i < lastByte; i++ ) {
if ( isprint( DataStart[Offset + i] ) ) {
*bufferPtr++ = (CCHAR)DataStart[Offset + i];
} else {
*bufferPtr++ = '.';
}
}
*bufferPtr = 0;
DbgPrint( "%s*\n", lineBuffer );
}
return;
} // RomDumpRawData
#endif // DBG
ARC_STATUS
RomMtftpReadFile (
IN PUCHAR FileName,
IN PVOID Buffer,
IN ULONG BufferLength,
IN ULONG ServerIPAddress, // network byte order
IN ULONG MCastIPAddress, // network byte order
IN USHORT MCastCPort, // network byte order
IN USHORT MCastSPort, // network byte order
IN USHORT Timeout,
IN USHORT Delay,
OUT PULONG DownloadSize
)
{
USHORT status;
t_PXENV_TFTP_READ_FILE tftp;
t_PXENV_UDP_CLOSE udpclose;
if (DownloadSize != NULL) {
*DownloadSize = 0;
}
memset( &tftp, 0 , sizeof( tftp ) );
strcpy(tftp.FileName, FileName);
tftp.BufferSize = BufferLength;
tftp.BufferOffset = (UINT32)Buffer;
if ( (ServerIPAddress & NetLocalSubnetMask) == (NetLocalIpAddress & NetLocalSubnetMask) ) {
*((UINT32 *)tftp.GatewayIPAddress) = 0;
} else {
*((UINT32 *)tftp.GatewayIPAddress) = NetGatewayIpAddress;
}
*((UINT32 *)tftp.ServerIPAddress) = ServerIPAddress;
*((UINT32 *)tftp.McastIPAddress) = MCastIPAddress;
tftp.TFTPClntPort = MCastCPort;
tftp.TFTPSrvPort = MCastSPort;
tftp.TFTPOpenTimeOut = Timeout;
tftp.TFTPReopenDelay = Delay;
// make sure that any UDP sessions are already closed.
status = NETPC_ROM_SERVICES( PXENV_UDP_CLOSE, &udpclose );
status = NETPC_ROM_SERVICES( PXENV_TFTP_READ_FILE, &tftp );
if (status != PXENV_EXIT_SUCCESS) {
return EINVAL;
}
if (DownloadSize != NULL) {
*DownloadSize = tftp.BufferSize;
}
return ESUCCESS;
}