303 lines
9.4 KiB
C++
303 lines
9.4 KiB
C++
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// pxe.cpp - Get files via PXE from SINGLDR
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#include "pxe.h"
|
||
|
#include "fnames.h"
|
||
|
|
||
|
#pragma warning(disable: 4505) // Compiler generated constructor unreferenced
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Private Functions
|
||
|
|
||
|
// The only way to talk to the hardware for PXE boot:
|
||
|
void PxeCall(int16 api, LPVOID args)
|
||
|
{
|
||
|
if (s_fpPxenv) {
|
||
|
__asm {
|
||
|
mov bx, api;
|
||
|
les di, args;
|
||
|
call s_fpPxenv;
|
||
|
}
|
||
|
}
|
||
|
else if (s_fpPxe) {
|
||
|
(*s_fpPxe)(api, args);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static uint32 parse_ip_addr(LPCHAR psz)
|
||
|
{
|
||
|
uint32 addr = 0;
|
||
|
uint16 num = 0;
|
||
|
for (; (*psz >= '0' && *psz <= '9') || *psz == '.'; psz++) {
|
||
|
if (*psz >= '0' && *psz <= '9') {
|
||
|
num = num * 10 + (*psz - '0');
|
||
|
}
|
||
|
else if (*psz == '.') {
|
||
|
addr = (addr >> 8) + ((uint32)num << 24);
|
||
|
num = 0;
|
||
|
}
|
||
|
}
|
||
|
addr = (addr >> 8) + ((uint32)num << 24);
|
||
|
return addr;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Public Functions
|
||
|
|
||
|
int PxeDevice::OpenDevice() __far
|
||
|
{
|
||
|
reply = (DHCP_PACKET __far *)alloc(1500, 4);
|
||
|
|
||
|
// Get PXE Configuration.
|
||
|
if (pxe->Signature[0] == '!' &&
|
||
|
pxe->Signature[1] == 'P' &&
|
||
|
pxe->Signature[2] == 'X' &&
|
||
|
pxe->Signature[3] == 'E') {
|
||
|
|
||
|
printf("PXE Signature : %c%c%c%c %d\n",
|
||
|
pxe->Signature[0],
|
||
|
pxe->Signature[1],
|
||
|
pxe->Signature[2],
|
||
|
pxe->Signature[3],
|
||
|
pxe->StructRev);
|
||
|
s_fpPxe = pxe->EntryPoint;
|
||
|
}
|
||
|
else if (pxenv->Signature[0] == 'P' &&
|
||
|
pxenv->Signature[1] == 'X' &&
|
||
|
pxenv->Signature[2] == 'E' &&
|
||
|
pxenv->Signature[3] == 'N' &&
|
||
|
pxenv->Signature[4] == 'V' &&
|
||
|
pxenv->Signature[5] == '+')
|
||
|
{
|
||
|
printf("PXE Signature: %c%c%c%c%c%c version %d.%d\n",
|
||
|
pxenv->Signature[0],
|
||
|
pxenv->Signature[1],
|
||
|
pxenv->Signature[2],
|
||
|
pxenv->Signature[3],
|
||
|
pxenv->Signature[4],
|
||
|
pxenv->Signature[5],
|
||
|
pxenv->Version >> 8,
|
||
|
pxenv->Version&0xff);
|
||
|
|
||
|
s_fpPxenv = pxenv->EntryPoint;
|
||
|
}
|
||
|
|
||
|
reply = (DHCP_PACKET __far *)alloc(1500, 4);
|
||
|
CmdLine = (uint16 __far *)alloc(2048, 2);
|
||
|
|
||
|
for (int j = 3; j > 0; j--) {
|
||
|
CHAR szTemp[128]; // Needed so string is near pointer.
|
||
|
PXENV_GET_CACHED_INFO pgci;
|
||
|
pgci.PacketType = (UINT16)j; //CACHED_REPLY;
|
||
|
pgci.Buffer = reply;
|
||
|
pgci.BufferSize = 1500;
|
||
|
pgci.BufferLimit = 1500;
|
||
|
memzero(reply, 1500);
|
||
|
|
||
|
printf(" PXE GetCachedInfo (Type=%d):\n", j);
|
||
|
PxeCall(GET_CACHED_INFO, &pgci);
|
||
|
|
||
|
if (pgci.Status != 0) {
|
||
|
printf(" Error 0x%04x on request.\n", pgci.Status);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
printf(" client: %d.%d.%d.%d, dhcp: %d.%d.%d.%d, gate: %d.%d.%d.%d (%d bytes)\n",
|
||
|
((uint8 __far *)&reply->yiaddr)[0],
|
||
|
((uint8 __far *)&reply->yiaddr)[1],
|
||
|
((uint8 __far *)&reply->yiaddr)[2],
|
||
|
((uint8 __far *)&reply->yiaddr)[3],
|
||
|
((uint8 __far *)&reply->siaddr)[0],
|
||
|
((uint8 __far *)&reply->siaddr)[1],
|
||
|
((uint8 __far *)&reply->siaddr)[2],
|
||
|
((uint8 __far *)&reply->siaddr)[3],
|
||
|
((uint8 __far *)&reply->giaddr)[0],
|
||
|
((uint8 __far *)&reply->giaddr)[1],
|
||
|
((uint8 __far *)&reply->giaddr)[2],
|
||
|
((uint8 __far *)&reply->giaddr)[3],
|
||
|
pgci.BufferSize);
|
||
|
if (reply->sname[0] != '\0') {
|
||
|
strcpy(szTemp, reply->sname);
|
||
|
printf(" server: [%s]\n", szTemp);
|
||
|
}
|
||
|
if (reply->file[0] != '\0') {
|
||
|
strcpy(szTemp, reply->file);
|
||
|
printf(" file: [%s]\n", szTemp);
|
||
|
}
|
||
|
if (reply->cookie[0] == 0x63 &&
|
||
|
reply->cookie[1] == 0x82 &&
|
||
|
reply->cookie[2] == 0x53 &&
|
||
|
reply->cookie[3] == 0x63) {
|
||
|
|
||
|
DHCP_OPTIONS __far *options = &reply->options;
|
||
|
DHCP_OPTIONS __far *optionsEnd
|
||
|
= (DHCP_OPTIONS __far *)reply + pgci.BufferSize;
|
||
|
|
||
|
while (options < optionsEnd) {
|
||
|
if (options->Code == DHCP_OPTION_COOKIE_SERVERS) {
|
||
|
uint16 __far * pwzCmdLine = CmdLine;
|
||
|
for (int i = 0; i < options->Length; i++) {
|
||
|
*pwzCmdLine++ = options->Data[i];
|
||
|
}
|
||
|
*pwzCmdLine++ = '\0';
|
||
|
printf(" cmd: %s\n", CmdLine);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (options->Code == 0) {
|
||
|
options = (DHCP_OPTIONS __far *)(((CHAR __far *)options) + 1);
|
||
|
}
|
||
|
else {
|
||
|
options = (DHCP_OPTIONS __far *)(((CHAR __far *)options)
|
||
|
+ options->Length + 2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
printf(" cookie: %02x %02x %02x %02x\n",
|
||
|
reply->cookie[0],
|
||
|
reply->cookie[1],
|
||
|
reply->cookie[2],
|
||
|
reply->cookie[3]);
|
||
|
}
|
||
|
|
||
|
if (reply->sname[0] != '\0') {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ServerIP = parse_ip_addr(reply->sname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int PxeDevice::CloseDevice() __far
|
||
|
{
|
||
|
// create a packet that will fail
|
||
|
PXENV_TFTP_GET_FSIZE ptfg;
|
||
|
LPCHAR terminate = "end.:"; // request an invalid filename :)
|
||
|
memzero(&ptfg, sizeof(ptfg));
|
||
|
strcpy(ptfg.FileName, terminate);
|
||
|
ptfg.Status = ~0u;
|
||
|
ptfg.GatewayIpAddress = reply->giaddr;
|
||
|
ptfg.ServerIpAddress = ServerIP;
|
||
|
|
||
|
printf(" Size: %d.%d.%d.%d [%s] (to close)\n",
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[0],
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[1],
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[2],
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[3],
|
||
|
ptfg.FileName);
|
||
|
|
||
|
PxeCall(TFTP_GET_FSIZE, &ptfg);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int PxeDevice::GetFileProperties(LPCHAR /* filename */,
|
||
|
FilePtr /* file */,
|
||
|
FilePtr /* directory */) __far
|
||
|
{
|
||
|
// We could call PxeCall(TFTP_GET_FSIZE here, but some PXE
|
||
|
// implementations fetch the entire file to determine its
|
||
|
// size. Instead we rely on size information in Singboot.ini.
|
||
|
|
||
|
#if DEPRECATED
|
||
|
// consume leading '/' chars in filename
|
||
|
LPCHAR fname = filename;
|
||
|
while (fname[0]=='/') {
|
||
|
fname++;
|
||
|
}
|
||
|
|
||
|
// build the message packet
|
||
|
PXENV_TFTP_GET_FSIZE ptfg;
|
||
|
memzero(&ptfg, sizeof(ptfg));
|
||
|
|
||
|
FNameToCStr(fname, ptfg.FileName, sizeof(ptfg.FileName));
|
||
|
|
||
|
ptfg.Status = ~0u;
|
||
|
ptfg.GatewayIpAddress = reply->giaddr;
|
||
|
ptfg.ServerIpAddress = ServerIP;
|
||
|
|
||
|
PxeCall(TFTP_GET_FSIZE, &ptfg);
|
||
|
|
||
|
if (ptfg.Status != 0) {
|
||
|
printf("PXE: Size: %d.%d.%d.%d ",
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[0],
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[1],
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[2],
|
||
|
((uint8 __far *)&ptfg.ServerIpAddress)[3]);
|
||
|
PutFName(filename);
|
||
|
printf("\n Error 0x%04x on request.\n", ptfg.Status);
|
||
|
return -1;
|
||
|
}
|
||
|
// file->Size = ptfg.FileSize;
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
INT16 PxeDevice::ReadFileLow(LPCHAR filename,
|
||
|
FilePtr /* file */,
|
||
|
uint8 __far * buffer) __far
|
||
|
{
|
||
|
// consume leading '/' chars
|
||
|
LPCHAR fname = filename;
|
||
|
while (fname[0] == '/') {
|
||
|
fname++;
|
||
|
}
|
||
|
|
||
|
// build the message packet
|
||
|
PXENV_TFTP_READ_FILE ptrf;
|
||
|
memzero(&ptrf, sizeof(ptrf));
|
||
|
strcpy(ptrf.FileName, fname);
|
||
|
ptrf.Status = ~0u;
|
||
|
ptrf.BufferSize = 0x8000;
|
||
|
ptrf.Buffer = PointerToUint32(buffer);
|
||
|
ptrf.GatewayIpAddress = reply->giaddr;
|
||
|
ptrf.ServerIpAddress = ServerIP;
|
||
|
|
||
|
PxeCall(TFTP_READ_FILE, &ptrf);
|
||
|
|
||
|
if (ptrf.Status != 0) {
|
||
|
printf("PXE: Loading low: %s", filename);
|
||
|
printf("\n Error 0x%04x on request.\n", ptrf.Status);
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UINT32 PxeDevice::ReadFileHigh(LPCHAR filename,
|
||
|
FilePtr file,
|
||
|
uint32 destinationAddress,
|
||
|
uint32 cbDestinationAddress) __far
|
||
|
{
|
||
|
// consume leading '/' chars
|
||
|
LPCHAR fname = filename;
|
||
|
while (fname[0] == '/') {
|
||
|
fname++;
|
||
|
}
|
||
|
|
||
|
// build the message packet
|
||
|
PXENV_TFTP_READ_FILE ptrf;
|
||
|
memzero(&ptrf, sizeof(ptrf));
|
||
|
FNameToCStr(fname, ptrf.FileName, sizeof(ptrf.FileName));
|
||
|
ptrf.Status = ~0u;
|
||
|
ptrf.BufferSize = cbDestinationAddress;
|
||
|
ptrf.Buffer = destinationAddress;
|
||
|
ptrf.GatewayIpAddress = reply->giaddr;
|
||
|
ptrf.ServerIpAddress = ServerIP;
|
||
|
|
||
|
PxeCall(TFTP_READ_FILE, &ptrf);
|
||
|
|
||
|
if (ptrf.Status != 0) {
|
||
|
printf("PXE: Loading high: %s", ptrf.FileName);
|
||
|
printf("\n Error 0x%04x on request.\n", ptrf.Status);
|
||
|
return -1;
|
||
|
}
|
||
|
return file->Size;
|
||
|
}
|