/*++ 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 #define PhysToSeg(x) (USHORT)((ULONG)(x) >> 4) & 0xffff #define PhysToOff(x) (USHORT)((ULONG)(x) & 0x0f) #include #include #include #include #include #include #include USHORT NetUnicastUdpDestinationPort = 0; #if 0 USHORT NetMulticastUdpDestinationPort; ULONG NetMulticastUdpDestinationAddress; USHORT NetMulticastUdpSourcePort; ULONG NetMulticastUdpSourceAddress; #endif #if 0 && DBG #include 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; }