singrdk/base/boot/Singldr/pxe.cpp

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;
}