mirror of https://github.com/acidanthera/audk.git
2384 lines
60 KiB
C
2384 lines
60 KiB
C
/** @file
|
|
|
|
Copyright (c) 2004 - 2007, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
bc.c
|
|
|
|
Abstract:
|
|
|
|
|
|
**/
|
|
|
|
#include "Bc.h"
|
|
|
|
//
|
|
//
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PxeBcDriverSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PxeBcDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PxeBcDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
);
|
|
|
|
extern
|
|
VOID
|
|
InitArpHeader (
|
|
VOID
|
|
);
|
|
extern
|
|
VOID
|
|
OptionsStrucInit (
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// helper routines
|
|
//
|
|
|
|
/**
|
|
Convert number to ASCII value
|
|
|
|
@param Number Numeric value to convert to decimal ASCII value.
|
|
@param Buffer Buffer to place ASCII version of the Number
|
|
@param Length Length of Buffer.
|
|
|
|
@retval none none
|
|
|
|
**/
|
|
VOID
|
|
CvtNum (
|
|
IN UINTN Number,
|
|
IN UINT8 *Buffer,
|
|
IN INTN Length
|
|
)
|
|
{
|
|
UINTN Remainder;
|
|
|
|
while (Length--) {
|
|
Remainder = Number % 10;
|
|
Number /= 10;
|
|
Buffer[Length] = (UINT8) ('0' + Remainder);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Convert number to decimal ASCII value at Buffer location
|
|
|
|
@param Number Numeric value to convert to decimal ASCII value.
|
|
@param Buffer Buffer to place ASCII version of the Number
|
|
|
|
@retval none none
|
|
|
|
**/
|
|
VOID
|
|
UtoA10 (
|
|
IN UINTN Number,
|
|
IN UINT8 *Buffer
|
|
)
|
|
{
|
|
INTN Index;
|
|
UINT8 BuffArray[31];
|
|
|
|
BuffArray[30] = 0;
|
|
CvtNum (Number, BuffArray, 30);
|
|
|
|
for (Index = 0; Index < 30; ++Index) {
|
|
if (BuffArray[Index] != '0') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
CopyMem (Buffer, BuffArray + Index, 31 - Index);
|
|
}
|
|
|
|
|
|
/**
|
|
Convert ASCII numeric string to a UINTN value
|
|
|
|
@param Number Numeric value to convert to decimal ASCII value.
|
|
@param Buffer Buffer to place ASCII version of the Number
|
|
|
|
@retval Value UINTN value of the ASCII string.
|
|
|
|
**/
|
|
UINTN
|
|
AtoU (
|
|
IN UINT8 *Buffer
|
|
)
|
|
{
|
|
UINTN Value;
|
|
INT8 Character;
|
|
|
|
Value = 0;
|
|
Character = *Buffer++;
|
|
do {
|
|
Value = Value * 10 + Character - '0';
|
|
Character = *Buffer++;
|
|
} while (Character);
|
|
|
|
return Value;
|
|
}
|
|
|
|
|
|
/**
|
|
Convert ASCII numeric string to a UINTN value
|
|
|
|
@param Number Numeric value to convert to decimal ASCII value.
|
|
@param Buffer Buffer to place ASCII version of the Number
|
|
|
|
@retval Value UINTN value of the ASCII string.
|
|
|
|
**/
|
|
UINT64
|
|
AtoU64 (
|
|
IN UINT8 *Buffer
|
|
)
|
|
{
|
|
UINT64 Value;
|
|
UINT8 Character;
|
|
|
|
Value = 0;
|
|
while ((Character = *Buffer++) != '\0') {
|
|
Value = MultU64x32 (Value, 10) + (Character - '0');
|
|
}
|
|
|
|
return Value;
|
|
}
|
|
//
|
|
// random number generator
|
|
//
|
|
#define RANDOM_MULTIPLIER 2053
|
|
#define RANDOM_ADD_IN_VALUE 19
|
|
|
|
VOID
|
|
SeedRandom (
|
|
IN PXE_BASECODE_DEVICE *Private,
|
|
IN UINT16 InitialSeed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize the Seed for the random number generator
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
none -
|
|
|
|
--*/
|
|
{
|
|
if (Private != NULL) {
|
|
Private->RandomSeed = InitialSeed;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Generate and return a pseudo-random number
|
|
|
|
|
|
@retval Number UINT16 random number
|
|
|
|
**/
|
|
UINT16
|
|
Random (
|
|
IN PXE_BASECODE_DEVICE *Private
|
|
)
|
|
{
|
|
UINTN Number;
|
|
|
|
if (Private != NULL) {
|
|
Number = -(INTN) Private->RandomSeed * RANDOM_MULTIPLIER + RANDOM_ADD_IN_VALUE;
|
|
|
|
return Private->RandomSeed = (UINT16) Number;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
//
|
|
// calculate the internet checksum (RFC 1071)
|
|
// return 16 bit ones complement of ones complement sum of 16 bit words
|
|
//
|
|
|
|
/**
|
|
Calculate the internet checksum (see RFC 1071)
|
|
|
|
@param Packet Buffer which contains the data to be checksummed
|
|
@param Length Length to be checksummed
|
|
|
|
@retval Checksum Returns the 16 bit ones complement of ones
|
|
complement sum of 16 bit words
|
|
|
|
**/
|
|
UINT16
|
|
IpChecksum (
|
|
IN UINT16 *Packet,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
UINT32 Sum;
|
|
UINT8 Odd;
|
|
|
|
Sum = 0;
|
|
Odd = (UINT8) (Length & 1);
|
|
Length >>= 1;
|
|
while (Length--) {
|
|
Sum += *Packet++;
|
|
}
|
|
|
|
if (Odd) {
|
|
Sum += *(UINT8 *) Packet;
|
|
}
|
|
|
|
Sum = (Sum & 0xffff) + (Sum >> 16);
|
|
//
|
|
// in case above carried
|
|
//
|
|
Sum += Sum >> 16;
|
|
|
|
return (UINT16) (~ (UINT16) Sum);
|
|
}
|
|
|
|
|
|
/**
|
|
Calculate the internet checksum (see RFC 1071)
|
|
on a non contiguous header and data
|
|
|
|
@param Header Buffer which contains the data to be checksummed
|
|
@param HeaderLen Length to be checksummed
|
|
@param Message Buffer which contains the data to be checksummed
|
|
@param MessageLen Length to be checksummed
|
|
|
|
@retval Checksum Returns the 16 bit ones complement of ones
|
|
complement sum of 16 bit words
|
|
|
|
**/
|
|
UINT16
|
|
IpChecksum2 (
|
|
IN UINT16 *Header,
|
|
IN UINTN HeaderLen,
|
|
IN UINT16 *Message,
|
|
IN UINTN MessageLen
|
|
)
|
|
{
|
|
UINT32 Sum;
|
|
UINT16 HeaderChecksum;
|
|
UINT16 MessageChecksum;
|
|
|
|
HeaderChecksum = (UINT16)~IpChecksum (Header, HeaderLen);
|
|
MessageChecksum = (UINT16)~IpChecksum (Message, MessageLen);
|
|
Sum = HeaderChecksum + MessageChecksum;
|
|
|
|
//
|
|
// in case above carried
|
|
//
|
|
Sum += Sum >> 16;
|
|
|
|
return (UINT16) (~ (UINT16) Sum);
|
|
}
|
|
|
|
|
|
/**
|
|
Adjust the internet checksum (see RFC 1071) on a single word update.
|
|
|
|
@param OldChkSum Checksum previously calculated
|
|
@param OldWord Value
|
|
@param NewWord New Value
|
|
|
|
@retval Checksum Returns the 16 bit ones complement of ones
|
|
complement sum of 16 bit words
|
|
|
|
**/
|
|
UINT16
|
|
UpdateChecksum (
|
|
IN UINT16 OldChksum,
|
|
IN UINT16 OldWord,
|
|
IN UINT16 NewWord
|
|
)
|
|
{
|
|
UINT32 sum;
|
|
|
|
sum = ~OldChksum + NewWord - OldWord;
|
|
//
|
|
// in case above carried
|
|
//
|
|
sum += sum >> 16;
|
|
return (UINT16) (~ (UINT16) sum);
|
|
}
|
|
|
|
|
|
/**
|
|
See if a callback is in play
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
|
|
@retval 0 Callbacks are active on the handle
|
|
@retval 1 Callbacks are not active on the handle
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
SetMakeCallback (
|
|
IN PXE_BASECODE_DEVICE *Private
|
|
)
|
|
{
|
|
Private->EfiBc.Mode->MakeCallbacks = (BOOLEAN) (gBS->HandleProtocol (
|
|
Private->Handle,
|
|
&gEfiPxeBaseCodeCallbackProtocolGuid,
|
|
(VOID *) &Private->CallbackProtocolPtr
|
|
) == EFI_SUCCESS);
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nMode->MakeCallbacks == %d ",
|
|
Private->EfiBc.Mode->MakeCallbacks)
|
|
);
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nPrivate->CallbackProtocolPtr == %xh ",
|
|
Private->CallbackProtocolPtr)
|
|
);
|
|
|
|
if (Private->CallbackProtocolPtr != NULL) {
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nCallbackProtocolPtr->Revision = %xh ",
|
|
Private->CallbackProtocolPtr->Revision)
|
|
);
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nCallbackProtocolPtr->Callback = %xh ",
|
|
Private->CallbackProtocolPtr->Callback)
|
|
);
|
|
}
|
|
|
|
return Private->EfiBc.Mode->MakeCallbacks;
|
|
}
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
/**
|
|
Routine which does an SNP->Receive over a timeout period and doing callbacks
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
@param Function What PXE function to callback
|
|
@param TimeoutEvent Timer event that will trigger when we have waited
|
|
too long for an incoming packet
|
|
@param HeaderSizePtr Pointer to the size of the Header size
|
|
@param BufferSizePtr Pointer to the size of the Buffer size
|
|
@param ProtocolPtr The protocol to sniff for (namely, UDP/TCP/etc)
|
|
|
|
@retval 0 Something was returned
|
|
@retval !0 Like there was nothing to receive
|
|
(EFI_TIMEOUT/NOT_READY)
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WaitForReceive (
|
|
IN PXE_BASECODE_DEVICE *Private,
|
|
IN EFI_PXE_BASE_CODE_FUNCTION Function,
|
|
IN EFI_EVENT TimeoutEvent,
|
|
IN OUT UINTN *HeaderSizePtr,
|
|
IN OUT UINTN *BufferSizePtr,
|
|
IN OUT UINT16 *ProtocolPtr
|
|
)
|
|
{
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
|
|
EFI_PXE_CALLBACK CallbackPtr;
|
|
EFI_STATUS StatCode;
|
|
EFI_EVENT CallbackEvent;
|
|
|
|
//
|
|
// Initialize pointer to SNP interface
|
|
//
|
|
SnpPtr = Private->SimpleNetwork;
|
|
|
|
//
|
|
// Initialize pointer to PxeBc callback routine - if any
|
|
//
|
|
CallbackPtr = (Private->EfiBc.Mode->MakeCallbacks) ? Private->CallbackProtocolPtr->Callback : NULL;
|
|
|
|
//
|
|
// Create callback event and set timer
|
|
//
|
|
StatCode = gBS->CreateEvent (
|
|
EVT_TIMER,
|
|
TPL_CALLBACK,
|
|
NULL,
|
|
NULL,
|
|
&CallbackEvent
|
|
);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// every 100 milliseconds
|
|
//
|
|
StatCode = gBS->SetTimer (
|
|
CallbackEvent,
|
|
TimerPeriodic,
|
|
1000000
|
|
);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
gBS->CloseEvent (CallbackEvent);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// Loop until a packet is received or a receive error is detected or
|
|
// a callback abort is detected or a timeout event occurs.
|
|
//
|
|
for (;;)
|
|
{
|
|
//
|
|
// Poll for received packet.
|
|
//
|
|
*BufferSizePtr = BUFFER_ALLOCATE_SIZE;
|
|
|
|
StatCode = SnpPtr->Receive (
|
|
SnpPtr,
|
|
HeaderSizePtr,
|
|
BufferSizePtr,
|
|
Private->ReceiveBufferPtr,
|
|
0,
|
|
0,
|
|
ProtocolPtr
|
|
);
|
|
|
|
if (!EFI_ERROR (StatCode)) {
|
|
//
|
|
// Packet was received. Make received callback then return.
|
|
//
|
|
if (CallbackPtr != NULL) {
|
|
StatCode = CallbackPtr (
|
|
Private->CallbackProtocolPtr,
|
|
Function,
|
|
TRUE,
|
|
(UINT32) *BufferSizePtr,
|
|
(EFI_PXE_BASE_CODE_PACKET *) Private->ReceiveBufferPtr
|
|
);
|
|
|
|
if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
|
|
StatCode = EFI_ABORTED;
|
|
} else {
|
|
StatCode = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (StatCode != EFI_NOT_READY) {
|
|
break;
|
|
}
|
|
//
|
|
// Check for callback event.
|
|
//
|
|
if (!EFI_ERROR (gBS->CheckEvent (CallbackEvent))) {
|
|
//
|
|
// Make periodic callback if callback pointer is initialized.
|
|
//
|
|
if (CallbackPtr != NULL) {
|
|
StatCode = CallbackPtr (
|
|
Private->CallbackProtocolPtr,
|
|
Function,
|
|
FALSE,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Abort if directed to by callback routine.
|
|
//
|
|
if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
|
|
StatCode = EFI_ABORTED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Check for timeout event.
|
|
//
|
|
if (TimeoutEvent == 0) {
|
|
StatCode = EFI_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
|
|
StatCode = EFI_TIMEOUT;
|
|
break;
|
|
}
|
|
//
|
|
// Check IGMP timer events.
|
|
//
|
|
IgmpCheckTimers (Private);
|
|
}
|
|
|
|
gBS->CloseEvent (CallbackEvent);
|
|
|
|
return StatCode;
|
|
}
|
|
|
|
|
|
/**
|
|
Routine which does an SNP->Transmit of a buffer
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
@param HeaderPtr Pointer to the buffer
|
|
@param PacketPtr Pointer to the packet to send
|
|
@param PacketLen The length of the entire packet to send
|
|
@param HardwareAddr Pointer to the MAC address of the destination
|
|
@param MediaProtocol What type of frame to create (RFC 1700) - IE.
|
|
Ethernet
|
|
@param Function What PXE function to callback
|
|
|
|
@retval 0 Something was sent
|
|
@retval !0 An error was encountered during sending of a packet
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SendPacket (
|
|
PXE_BASECODE_DEVICE *Private,
|
|
VOID *HeaderPtr,
|
|
VOID *PacketPtr,
|
|
INTN PacketLen,
|
|
VOID *HardwareAddr,
|
|
UINT16 MediaProtocol,
|
|
IN EFI_PXE_BASE_CODE_FUNCTION Function
|
|
)
|
|
{
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
|
|
EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
|
|
EFI_PXE_CALLBACK CallbackPtr;
|
|
EFI_STATUS StatCode;
|
|
EFI_EVENT TimeoutEvent;
|
|
UINT32 IntStatus;
|
|
VOID *TxBuf;
|
|
|
|
//
|
|
//
|
|
//
|
|
CallbackPtr = Private->EfiBc.Mode->MakeCallbacks ? Private->CallbackProtocolPtr->Callback : 0;
|
|
|
|
SnpPtr = Private->SimpleNetwork;
|
|
SnpModePtr = SnpPtr->Mode;
|
|
|
|
//
|
|
// clear prior interrupt status
|
|
//
|
|
StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, 0);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nSendPacket() Exit #1 %xh (%r)",
|
|
StatCode,
|
|
StatCode)
|
|
);
|
|
return StatCode;
|
|
}
|
|
|
|
Private->DidTransmit = FALSE;
|
|
|
|
if (CallbackPtr != NULL) {
|
|
if (CallbackPtr (
|
|
Private->CallbackProtocolPtr,
|
|
Function,
|
|
FALSE,
|
|
(UINT32) PacketLen,
|
|
PacketPtr
|
|
) != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nSendPacket() Exit #2 %xh (%r)",
|
|
EFI_ABORTED,
|
|
EFI_ABORTED)
|
|
);
|
|
return EFI_ABORTED;
|
|
}
|
|
}
|
|
//
|
|
// put packet in transmit queue
|
|
// headersize should be zero if not filled in
|
|
//
|
|
StatCode = gBS->CreateEvent (
|
|
EVT_TIMER,
|
|
TPL_CALLBACK,
|
|
NULL,
|
|
NULL,
|
|
&TimeoutEvent
|
|
);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_ERROR,
|
|
"Could not create transmit timeout event. %r\n",
|
|
StatCode)
|
|
);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// 5 milliseconds
|
|
//
|
|
StatCode = gBS->SetTimer (
|
|
TimeoutEvent,
|
|
TimerRelative,
|
|
50000
|
|
);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_ERROR,
|
|
"Could not set transmit timeout event timer. %r\n",
|
|
StatCode)
|
|
);
|
|
gBS->CloseEvent (TimeoutEvent);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
for (;;) {
|
|
StatCode = SnpPtr->Transmit (
|
|
SnpPtr,
|
|
(UINTN) SnpPtr->Mode->MediaHeaderSize,
|
|
(UINTN) (PacketLen + SnpPtr->Mode->MediaHeaderSize),
|
|
HeaderPtr,
|
|
&SnpModePtr->CurrentAddress,
|
|
(EFI_MAC_ADDRESS *) HardwareAddr,
|
|
&MediaProtocol
|
|
);
|
|
|
|
if (StatCode != EFI_NOT_READY) {
|
|
break;
|
|
}
|
|
|
|
if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
|
|
StatCode = EFI_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
gBS->CloseEvent (TimeoutEvent);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nSendPacket() Exit #3 %xh (%r)",
|
|
StatCode,
|
|
StatCode)
|
|
);
|
|
return StatCode;
|
|
}
|
|
//
|
|
// remove transmit buffer from snp's unused queue
|
|
// done this way in case someday things are buffered and we don't get it back
|
|
// immediately
|
|
//
|
|
StatCode = gBS->CreateEvent (
|
|
EVT_TIMER,
|
|
TPL_CALLBACK,
|
|
NULL,
|
|
NULL,
|
|
&TimeoutEvent
|
|
);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_ERROR,
|
|
"Could not create transmit status timeout event. %r\n",
|
|
StatCode)
|
|
);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// 5 milliseconds
|
|
//
|
|
StatCode = gBS->SetTimer (
|
|
TimeoutEvent,
|
|
TimerRelative,
|
|
50000
|
|
);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_ERROR,
|
|
"Could not set transmit status timeout event timer. %r\n",
|
|
StatCode)
|
|
);
|
|
gBS->CloseEvent (TimeoutEvent);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
for (;;) {
|
|
StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, &TxBuf);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nSendPacket() Exit #4 %xh (%r)",
|
|
StatCode,
|
|
StatCode)
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (IntStatus & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT) {
|
|
Private->DidTransmit = TRUE;
|
|
}
|
|
|
|
if (TxBuf != NULL) {
|
|
break;
|
|
}
|
|
|
|
if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
|
|
StatCode = EFI_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
gBS->CloseEvent (TimeoutEvent);
|
|
|
|
return StatCode;
|
|
}
|
|
//
|
|
//
|
|
//
|
|
|
|
/**
|
|
|
|
|
|
**/
|
|
EFI_BIS_PROTOCOL *
|
|
PxebcBisStart (
|
|
IN PXE_BASECODE_DEVICE *Private,
|
|
OUT BIS_APPLICATION_HANDLE *BisAppHandle,
|
|
OUT OPTIONAL EFI_BIS_DATA **BisDataSigInfo
|
|
)
|
|
{
|
|
EFI_STATUS EfiStatus;
|
|
EFI_HANDLE BisHandleBuffer;
|
|
UINTN BisHandleCount;
|
|
EFI_BIS_PROTOCOL *BisPtr;
|
|
EFI_BIS_VERSION BisInterfaceVersion;
|
|
BOOLEAN BisCheckFlag;
|
|
|
|
BisHandleCount = sizeof (EFI_HANDLE);
|
|
BisCheckFlag = FALSE;
|
|
|
|
//
|
|
// Locate BIS protocol handle (if present).
|
|
// If BIS protocol handle is not found, return NULL.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\ngBS->LocateHandle() "));
|
|
|
|
EfiStatus = gBS->LocateHandle (
|
|
ByProtocol,
|
|
&gEfiBisProtocolGuid,
|
|
NULL,
|
|
&BisHandleCount,
|
|
&BisHandleBuffer
|
|
);
|
|
|
|
if (EFI_ERROR (EfiStatus)) {
|
|
//
|
|
// Any error means that there is no BIS.
|
|
// Note - It could mean that there are more than
|
|
// one BIS protocols installed, but that scenario
|
|
// is not yet supported.
|
|
//
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nPxebcBisStart()""\n gBS->LocateHandle() %r (%xh)\n",
|
|
EfiStatus,
|
|
EfiStatus)
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (BisHandleCount != sizeof BisHandleBuffer) {
|
|
//
|
|
// This really should never happen, but I am paranoid.
|
|
//
|
|
DEBUG (
|
|
(DEBUG_NET,
|
|
"\nPxebcBisStart() BisHandleCount != %d\n",
|
|
sizeof BisHandleBuffer)
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "BIS handle found."));
|
|
|
|
//
|
|
// Locate BIS protocol interface.
|
|
// If the BIS protocol interface cannot be found, return NULL.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\ngBS->HandleProtocol() "));
|
|
|
|
EfiStatus = gBS->HandleProtocol (
|
|
BisHandleBuffer,
|
|
&gEfiBisProtocolGuid,
|
|
(VOID **) &BisPtr
|
|
);
|
|
|
|
if (EFI_ERROR (EfiStatus)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nPxebcBisStart()""\n gBS->HandleProtocol() %r (%xh)\n",
|
|
EfiStatus,
|
|
EfiStatus)
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (BisPtr == NULL) {
|
|
//
|
|
// This really should never happen.
|
|
//
|
|
DEBUG (
|
|
(DEBUG_NET,
|
|
"\nPxebcBisStart()""\n gBS->HandleProtocoL() ""BIS protocol interface pointer is NULL!\n")
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "BIS protocol interface found."));
|
|
|
|
//
|
|
// Check that all of the BIS API function pointers are not NULL.
|
|
//
|
|
if (BisPtr->Initialize == NULL ||
|
|
BisPtr->Shutdown == NULL ||
|
|
BisPtr->Free == NULL ||
|
|
BisPtr->GetBootObjectAuthorizationCertificate == NULL ||
|
|
BisPtr->GetBootObjectAuthorizationCheckFlag == NULL ||
|
|
BisPtr->GetBootObjectAuthorizationUpdateToken == NULL ||
|
|
BisPtr->GetSignatureInfo == NULL ||
|
|
BisPtr->UpdateBootObjectAuthorization == NULL ||
|
|
BisPtr->VerifyBootObject == NULL ||
|
|
BisPtr->VerifyObjectWithCredential == NULL
|
|
) {
|
|
DEBUG (
|
|
(
|
|
DEBUG_NET,
|
|
"\nPxebcBisStart()""\n BIS protocol interface is invalid."
|
|
"\n At least one BIS protocol function pointer is NULL.\n"
|
|
)
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
//
|
|
// Initialize BIS.
|
|
// If BIS does not initialize, return NULL.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\nBisPtr->Initialize() "));
|
|
|
|
BisInterfaceVersion.Major = BIS_VERSION_1;
|
|
|
|
EfiStatus = BisPtr->Initialize (
|
|
BisPtr,
|
|
BisAppHandle,
|
|
&BisInterfaceVersion,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (EfiStatus)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nPxebcBisStart()""\n BisPtr->Initialize() %r (%xh)\n",
|
|
EfiStatus,
|
|
EfiStatus)
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
" BIS version: %d.%d",
|
|
BisInterfaceVersion.Major,
|
|
BisInterfaceVersion.Minor)
|
|
);
|
|
|
|
//
|
|
// If the requested BIS API version is not supported,
|
|
// shutdown BIS and return NULL.
|
|
//
|
|
if (BisInterfaceVersion.Major != BIS_VERSION_1) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nPxebcBisStart()""\n BIS version %d.%d not supported by PXE BaseCode.\n",
|
|
BisInterfaceVersion.Major,
|
|
BisInterfaceVersion.Minor)
|
|
);
|
|
|
|
BisPtr->Shutdown (*BisAppHandle);
|
|
return NULL;
|
|
}
|
|
//
|
|
// Get BIS check flag.
|
|
// If the BIS check flag cannot be read, shutdown BIS and return NULL.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\nBisPtr->GetBootObjectAuthorizationCheckFlag() "));
|
|
|
|
EfiStatus = BisPtr->GetBootObjectAuthorizationCheckFlag (*BisAppHandle, &BisCheckFlag);
|
|
|
|
if (EFI_ERROR (EfiStatus)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nPxebcBisStart()""\n BisPtr->GetBootObjectAuthorizationCheckFlag() %r (%xh)\n",
|
|
EfiStatus,
|
|
EfiStatus)
|
|
);
|
|
|
|
BisPtr->Shutdown (*BisAppHandle);
|
|
return NULL;
|
|
}
|
|
//
|
|
// If the BIS check flag is FALSE, shutdown BIS and return NULL.
|
|
//
|
|
if (!BisCheckFlag) {
|
|
DEBUG ((DEBUG_INFO, "\nBIS check flag is FALSE.\n"));
|
|
BisPtr->Shutdown (*BisAppHandle);
|
|
return NULL;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "\nBIS check flag is TRUE."));
|
|
}
|
|
//
|
|
// Early out if caller does not want signature information.
|
|
//
|
|
if (BisDataSigInfo == NULL) {
|
|
return BisPtr;
|
|
}
|
|
//
|
|
// Get BIS signature information.
|
|
// If the signature information cannot be read or is invalid,
|
|
// shutdown BIS and return NULL.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\nBisPtr->GetSignatureInfo() "));
|
|
|
|
EfiStatus = BisPtr->GetSignatureInfo (*BisAppHandle, BisDataSigInfo);
|
|
|
|
if (EFI_ERROR (EfiStatus)) {
|
|
DEBUG (
|
|
(DEBUG_WARN,
|
|
"\nPxebcBisStart()""\n BisPtr_GetSignatureInfo() %r (%xh)\n",
|
|
EfiStatus,
|
|
EfiStatus)
|
|
);
|
|
|
|
BisPtr->Shutdown (*BisAppHandle);
|
|
return NULL;
|
|
}
|
|
|
|
if (*BisDataSigInfo == NULL) {
|
|
//
|
|
// This should never happen.
|
|
//
|
|
DEBUG (
|
|
(DEBUG_NET,
|
|
"\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Data pointer is NULL!\n")
|
|
);
|
|
|
|
BisPtr->Shutdown (*BisAppHandle);
|
|
return NULL;
|
|
}
|
|
|
|
if ((*BisDataSigInfo)->Length < sizeof (EFI_BIS_SIGNATURE_INFO) ||
|
|
(*BisDataSigInfo)->Length % sizeof (EFI_BIS_SIGNATURE_INFO) ||
|
|
(*BisDataSigInfo)->Length > sizeof (EFI_BIS_SIGNATURE_INFO) * 63
|
|
) {
|
|
//
|
|
// This should never happen.
|
|
//
|
|
DEBUG (
|
|
(DEBUG_NET,
|
|
"\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Invalid BIS siginfo length.\n")
|
|
);
|
|
|
|
BisPtr->Free (*BisAppHandle, *BisDataSigInfo);
|
|
BisPtr->Shutdown (*BisAppHandle);
|
|
return NULL;
|
|
}
|
|
|
|
return BisPtr;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
**/
|
|
VOID
|
|
PxebcBisStop (
|
|
EFI_BIS_PROTOCOL *BisPtr,
|
|
BIS_APPLICATION_HANDLE BisAppHandle,
|
|
EFI_BIS_DATA *BisDataSigInfo
|
|
)
|
|
{
|
|
if (BisPtr == NULL) {
|
|
return ;
|
|
}
|
|
//
|
|
// Free BIS allocated resources and shutdown BIS.
|
|
// Return TRUE - BIS support is officially detected.
|
|
//
|
|
if (BisDataSigInfo != NULL) {
|
|
BisPtr->Free (BisAppHandle, BisDataSigInfo);
|
|
}
|
|
|
|
BisPtr->Shutdown (BisAppHandle);
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
@return TRUE := verified
|
|
@return FALSE := not verified
|
|
|
|
**/
|
|
BOOLEAN
|
|
PxebcBisVerify (
|
|
PXE_BASECODE_DEVICE *Private,
|
|
VOID *FileBuffer,
|
|
UINTN FileLength,
|
|
VOID *CredentialBuffer,
|
|
UINTN CredentialLength
|
|
)
|
|
{
|
|
EFI_BIS_PROTOCOL *BisPtr;
|
|
BIS_APPLICATION_HANDLE BisAppHandle;
|
|
EFI_BIS_DATA FileData;
|
|
EFI_BIS_DATA CredentialData;
|
|
EFI_STATUS EfiStatus;
|
|
BOOLEAN IsVerified;
|
|
|
|
if (Private == NULL || FileBuffer == NULL || FileLength == 0 || CredentialBuffer == NULL || CredentialLength == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
BisPtr = PxebcBisStart (Private, &BisAppHandle, NULL);
|
|
|
|
if (BisPtr == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
FileData.Length = (UINT32) FileLength;
|
|
FileData.Data = FileBuffer;
|
|
CredentialData.Length = (UINT32) CredentialLength;
|
|
CredentialData.Data = CredentialBuffer;
|
|
|
|
EfiStatus = BisPtr->VerifyBootObject (
|
|
BisAppHandle,
|
|
&CredentialData,
|
|
&FileData,
|
|
&IsVerified
|
|
);
|
|
|
|
PxebcBisStop (BisPtr, BisAppHandle, NULL);
|
|
|
|
return (BOOLEAN) ((EFI_ERROR (EfiStatus)) ? FALSE : (IsVerified ? TRUE : FALSE));
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
@return TRUE := BIS present
|
|
@return FALSE := BIS not present
|
|
|
|
**/
|
|
BOOLEAN
|
|
PxebcBisDetect (
|
|
PXE_BASECODE_DEVICE *Private
|
|
)
|
|
{
|
|
EFI_BIS_PROTOCOL *BisPtr;
|
|
BIS_APPLICATION_HANDLE BisAppHandle;
|
|
EFI_BIS_DATA *BisDataSigInfo;
|
|
|
|
BisPtr = PxebcBisStart (Private, &BisAppHandle, &BisDataSigInfo);
|
|
|
|
if (BisPtr == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Start and initialize the BaseCode protocol, Simple Network protocol and UNDI.
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
@param UseIPv6 Do we want to support IPv6?
|
|
|
|
@return EFI_SUCCESS
|
|
@return EFI_INVALID_PARAMETER
|
|
@return EFI_UNSUPPORTED
|
|
@return EFI_ALREADY_STARTED
|
|
@return EFI_OUT_OF_RESOURCES
|
|
@return Status is also returned from SNP.Start() and SNP.Initialize().
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BcStart (
|
|
IN EFI_PXE_BASE_CODE_PROTOCOL *This,
|
|
IN BOOLEAN UseIPv6
|
|
)
|
|
{
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
|
|
EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
|
|
EFI_STATUS Status;
|
|
EFI_STATUS StatCode;
|
|
PXE_BASECODE_DEVICE *Private;
|
|
|
|
//
|
|
// Lock the instance data
|
|
//
|
|
StatCode = EFI_SUCCESS;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
|
|
|
|
if (Private == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
//
|
|
// Make sure BaseCode is not already started.
|
|
//
|
|
if (This->Mode->Started) {
|
|
DEBUG ((DEBUG_WARN, "\nBcStart() BC is already started.\n"));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
//
|
|
// Fail if IPv6 is requested and not supported.
|
|
//
|
|
if (UseIPv6) {
|
|
DEBUG ((DEBUG_WARN, "\nBcStart() IPv6 is not supported.\n"));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
//
|
|
// Setup shortcuts to SNP protocol and data structure.
|
|
//
|
|
SnpPtr = Private->SimpleNetwork;
|
|
SnpModePtr = SnpPtr->Mode;
|
|
|
|
//
|
|
// Start and initialize SNP.
|
|
//
|
|
if (SnpModePtr->State == EfiSimpleNetworkStopped) {
|
|
StatCode = (*SnpPtr->Start) (SnpPtr);
|
|
|
|
if (SnpModePtr->State != EfiSimpleNetworkStarted) {
|
|
DEBUG ((DEBUG_WARN, "\nBcStart() Could not start SNP.\n"));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return StatCode;
|
|
}
|
|
}
|
|
//
|
|
// acquire memory for mode and transmit/receive buffers
|
|
//
|
|
if (SnpModePtr->State == EfiSimpleNetworkStarted) {
|
|
StatCode = (*SnpPtr->Initialize) (SnpPtr, 0, 0);
|
|
|
|
if (SnpModePtr->State != EfiSimpleNetworkInitialized) {
|
|
DEBUG ((DEBUG_WARN, "\nBcStart() Could not initialize SNP."));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return StatCode;
|
|
}
|
|
}
|
|
//
|
|
// Dump debug info.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\nBC Start()"));
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->State %Xh",
|
|
SnpModePtr->State)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->HwAddressSize %Xh",
|
|
SnpModePtr->HwAddressSize)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MediaHeaderSize %Xh",
|
|
SnpModePtr->MediaHeaderSize)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MaxPacketSize %Xh",
|
|
SnpModePtr->MaxPacketSize)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MacAddressChangeable %Xh",
|
|
SnpModePtr->MacAddressChangeable)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MultipleTxSupported %Xh",
|
|
SnpModePtr->MultipleTxSupported)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->CurrentAddress %Xh",
|
|
*((UINTN *)&SnpModePtr->CurrentAddress))
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->BroadcastAddress %Xh",
|
|
*((UINTN *)&SnpModePtr->BroadcastAddress))
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->PermanentAddress %Xh",
|
|
*((UINTN *)&SnpModePtr->PermanentAddress))
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->NvRamSize %Xh",
|
|
SnpModePtr->NvRamSize)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->NvRamAccessSize %Xh",
|
|
SnpModePtr->NvRamAccessSize)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->ReceiveFilterMask %Xh",
|
|
SnpModePtr->ReceiveFilterMask)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->ReceiveFilterSetting %Xh",
|
|
SnpModePtr->ReceiveFilterSetting)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MCastFilterCount %Xh",
|
|
SnpModePtr->MCastFilterCount)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MCastFilter %Xh",
|
|
SnpModePtr->MCastFilter)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->IfType %Xh",
|
|
SnpModePtr->IfType)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MediaPresentSupported %Xh",
|
|
SnpModePtr->MediaPresentSupported)
|
|
);
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nSnpModePtr->MediaPresent %Xh",
|
|
SnpModePtr->MediaPresent)
|
|
);
|
|
|
|
//
|
|
// If media check is supported and there is no media,
|
|
// return error to caller.
|
|
//
|
|
if (SnpModePtr->MediaPresentSupported && !SnpModePtr->MediaPresent) {
|
|
DEBUG ((DEBUG_WARN, "\nBcStart() Media not present.\n"));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
//
|
|
// Allocate Tx/Rx buffers
|
|
//
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
BUFFER_ALLOCATE_SIZE,
|
|
(VOID **) &Private->TransmitBufferPtr
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (Private->TransmitBufferPtr, BUFFER_ALLOCATE_SIZE);
|
|
} else {
|
|
DEBUG ((DEBUG_NET, "\nBcStart() Could not alloc TxBuf.\n"));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
BUFFER_ALLOCATE_SIZE,
|
|
(VOID **) &Private->ReceiveBufferPtr
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
ZeroMem (Private->ReceiveBufferPtr, BUFFER_ALLOCATE_SIZE);
|
|
} else {
|
|
DEBUG ((DEBUG_NET, "\nBcStart() Could not alloc RxBuf.\n"));
|
|
gBS->FreePool (Private->TransmitBufferPtr);
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
256,
|
|
(VOID **) &Private->TftpErrorBuffer
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (Private->ReceiveBufferPtr);
|
|
gBS->FreePool (Private->TransmitBufferPtr);
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = gBS->AllocatePool (EfiBootServicesData, 256, (VOID **) &Private->TftpAckBuffer);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (Private->TftpErrorBuffer);
|
|
gBS->FreePool (Private->ReceiveBufferPtr);
|
|
gBS->FreePool (Private->TransmitBufferPtr);
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Initialize private BaseCode instance data
|
|
//
|
|
do {
|
|
Private->RandomPort = (UINT16) (Private->RandomPort + PXE_RND_PORT_LOW + Random (Private));
|
|
} while (Private->RandomPort < PXE_RND_PORT_LOW);
|
|
|
|
Private->Igmpv1TimeoutEvent = NULL;
|
|
Private->UseIgmpv1Reporting = TRUE;
|
|
Private->IpLength = IP_ADDRESS_LENGTH (Private->EfiBc.Mode);
|
|
|
|
//
|
|
// Initialize Mode structure
|
|
//
|
|
ZeroMem (Private->EfiBc.Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
|
|
//
|
|
// check for callback protocol and set boolean
|
|
//
|
|
SetMakeCallback (Private);
|
|
Private->EfiBc.Mode->Started = TRUE;
|
|
Private->EfiBc.Mode->TTL = DEFAULT_TTL;
|
|
Private->EfiBc.Mode->ToS = DEFAULT_ToS;
|
|
Private->EfiBc.Mode->UsingIpv6 = UseIPv6;
|
|
|
|
//
|
|
// Set to PXE_TRUE by the BC constructor if this BC implementation
|
|
// supports IPv6.
|
|
//
|
|
Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6;
|
|
|
|
Private->EfiBc.Mode->Ipv6Available = FALSE;
|
|
//
|
|
// Set to TRUE by the BC constructor if this BC implementation
|
|
// supports BIS.
|
|
//
|
|
Private->EfiBc.Mode->BisSupported = TRUE;
|
|
Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private);
|
|
|
|
//
|
|
// This field is set to PXE_TRUE by the BC Start() function. When this
|
|
// field is PXE_TRUE, ARP packets are sent as needed to get IP and MAC
|
|
// addresses. This can cause unexpected delays in the DHCP(), Discover()
|
|
// and MTFTP() functions. Setting this to PXE_FALSE will cause these
|
|
// functions to fail if the required IP/MAC information is not in the
|
|
// ARP cache. The value of this field can be changed by an application
|
|
// at any time.
|
|
//
|
|
Private->EfiBc.Mode->AutoArp = TRUE;
|
|
|
|
//
|
|
// Unlock the instance data
|
|
//
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Stop the BaseCode protocol, Simple Network protocol and UNDI.
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
|
|
@retval 0 Successfully stopped
|
|
@retval !0 Failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BcStop (
|
|
IN EFI_PXE_BASE_CODE_PROTOCOL *This
|
|
)
|
|
{
|
|
//
|
|
// Lock the instance data
|
|
//
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
|
|
EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
|
|
EFI_STATUS StatCode;
|
|
PXE_BASECODE_DEVICE *Private;
|
|
|
|
StatCode = EFI_SUCCESS;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
|
|
|
|
if (Private == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
SnpPtr = Private->SimpleNetwork;
|
|
SnpModePtr = SnpPtr->Mode;
|
|
|
|
//
|
|
// Issue BC command
|
|
//
|
|
StatCode = EFI_NOT_STARTED;
|
|
|
|
if (SnpModePtr->State == EfiSimpleNetworkInitialized) {
|
|
StatCode = (*SnpPtr->Shutdown) (SnpPtr);
|
|
}
|
|
|
|
if (SnpModePtr->State == EfiSimpleNetworkStarted) {
|
|
StatCode = (*SnpPtr->Stop) (SnpPtr);
|
|
}
|
|
|
|
if (Private->TransmitBufferPtr != NULL) {
|
|
gBS->FreePool (Private->TransmitBufferPtr);
|
|
Private->TransmitBufferPtr = NULL;
|
|
}
|
|
|
|
if (Private->ReceiveBufferPtr != NULL) {
|
|
gBS->FreePool (Private->ReceiveBufferPtr);
|
|
Private->ReceiveBufferPtr = NULL;
|
|
}
|
|
|
|
if (Private->ArpBuffer != NULL) {
|
|
gBS->FreePool (Private->ArpBuffer);
|
|
Private->ArpBuffer = NULL;
|
|
}
|
|
|
|
if (Private->TftpErrorBuffer != NULL) {
|
|
gBS->FreePool (Private->TftpErrorBuffer);
|
|
Private->TftpErrorBuffer = NULL;
|
|
}
|
|
|
|
if (Private->TftpAckBuffer != NULL) {
|
|
gBS->FreePool (Private->TftpAckBuffer);
|
|
Private->TftpAckBuffer = NULL;
|
|
}
|
|
|
|
if (Private->Igmpv1TimeoutEvent != NULL) {
|
|
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
|
|
Private->Igmpv1TimeoutEvent = NULL;
|
|
}
|
|
|
|
Private->FileSize = 0;
|
|
|
|
if (!Private->EfiBc.Mode->Started) {
|
|
StatCode = EFI_NOT_STARTED;
|
|
} else {
|
|
Private->EfiBc.Mode->Started = FALSE;
|
|
}
|
|
|
|
//
|
|
// Unlock the instance data
|
|
//
|
|
EfiReleaseLock (&Private->Lock);
|
|
return StatCode;
|
|
}
|
|
|
|
const IPV4_ADDR AllSystemsGroup = {{224, 0, 0, 1}};
|
|
|
|
|
|
/**
|
|
Set up the IP filter
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
@param Filter Pointer to the filter
|
|
|
|
@retval 0 Successfully set the filter
|
|
@retval !0 Failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpFilter (
|
|
IN PXE_BASECODE_DEVICE *Private,
|
|
IN EFI_PXE_BASE_CODE_IP_FILTER *Filter
|
|
)
|
|
{
|
|
EFI_STATUS StatCode;
|
|
EFI_MAC_ADDRESS MACadds[PXE_IP_FILTER_SIZE];
|
|
EFI_PXE_BASE_CODE_MODE *PxebcMode;
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
|
|
EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
|
|
UINT32 Enable;
|
|
UINT32 Disable;
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
|
|
PxebcMode = Private->EfiBc.Mode;
|
|
SnpPtr = Private->SimpleNetwork;
|
|
SnpModePtr = SnpPtr->Mode;
|
|
|
|
//
|
|
// validate input parameters
|
|
// must have a filter
|
|
// must not have any extra filter bits set
|
|
//
|
|
if (Filter == NULL ||
|
|
(Filter->Filters &~FILTER_BITS)
|
|
//
|
|
// must not have a count which is too large or with no IP list
|
|
//
|
|
||
|
|
(Filter->IpCnt && (!Filter->IpList || Filter->IpCnt > PXE_IP_FILTER_SIZE))
|
|
//
|
|
// must not have incompatible filters - promiscuous incompatible with anything else
|
|
//
|
|
||
|
|
(
|
|
(Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) &&
|
|
((Filter->Filters &~EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) || Filter->IpCnt)
|
|
)
|
|
) {
|
|
DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #1"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// promiscuous multicast incompatible with multicast in IP list
|
|
//
|
|
if (Filter->IpCnt && (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST)) {
|
|
for (Index = 0; Index < Filter->IpCnt; ++Index) {
|
|
if (IS_MULTICAST (&Filter->IpList[Index])) {
|
|
DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #2"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// leave groups for all those multicast which are no longer enabled
|
|
//
|
|
for (Index = 0; Index < PxebcMode->IpFilter.IpCnt; ++Index) {
|
|
if (!IS_MULTICAST (&PxebcMode->IpFilter.IpList[Index])) {
|
|
continue;
|
|
}
|
|
|
|
for (Index2 = 0; Index2 < Filter->IpCnt; ++Index2) {
|
|
if (!CompareMem (&PxebcMode->IpFilter.IpList[Index], &Filter->IpList[Index2], IP_ADDRESS_LENGTH (PxebcMode))) {
|
|
//
|
|
// still enabled
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// if we didn't find it, remove from group
|
|
//
|
|
if (Index2 == Filter->IpCnt) {
|
|
IgmpLeaveGroup (Private, &PxebcMode->IpFilter.IpList[Index]);
|
|
}
|
|
}
|
|
//
|
|
// set enable bits, convert multicast ip adds, join groups
|
|
// allways leave receive broadcast enabled at hardware layer
|
|
//
|
|
Index2 = 0;
|
|
|
|
if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {
|
|
Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
|
|
} else {
|
|
if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) {
|
|
Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
|
|
} else {
|
|
Enable = EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
|
|
|
|
for (Index = 0; Index < Filter->IpCnt; ++Index) {
|
|
CopyMem (&PxebcMode->IpFilter.IpList[Index], &Filter->IpList[Index], sizeof (EFI_IP_ADDRESS));
|
|
|
|
if (IS_MULTICAST (&Filter->IpList[Index])) {
|
|
EFI_IP_ADDRESS *TmpIp;
|
|
|
|
Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
|
|
|
|
//
|
|
// if this is the first group, add the all systems group to mcast list
|
|
//
|
|
if (!Index2)
|
|
{
|
|
TmpIp = (EFI_IP_ADDRESS *) &AllSystemsGroup;
|
|
--Index;
|
|
} else {
|
|
TmpIp = (EFI_IP_ADDRESS *) &Filter->IpList[Index];
|
|
}
|
|
//
|
|
// get MAC address of IP
|
|
//
|
|
StatCode = (*SnpPtr->MCastIpToMac) (SnpPtr, PxebcMode->UsingIpv6, TmpIp, &MACadds[Index2++]);
|
|
|
|
if (EFI_ERROR (StatCode)) {
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nIpFilter() Exit #2 %Xh (%r)",
|
|
StatCode,
|
|
StatCode)
|
|
);
|
|
return StatCode;
|
|
}
|
|
} else {
|
|
Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) {
|
|
Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
|
|
}
|
|
}
|
|
//
|
|
// if nothing changed, just return
|
|
//
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\nsnp->ReceiveFilterSetting == %Xh Filter->IpCnt == %Xh",
|
|
SnpModePtr->ReceiveFilterSetting,
|
|
Filter->IpCnt)
|
|
);
|
|
|
|
if (SnpModePtr->ReceiveFilterSetting == Enable && !Filter->IpCnt) {
|
|
DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #4"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// disable those currently set but not set in new filter
|
|
//
|
|
Disable = SnpModePtr->ReceiveFilterSetting &~Enable;
|
|
|
|
StatCode = SnpPtr->ReceiveFilters (SnpPtr, Enable, Disable, FALSE, Index2, MACadds);
|
|
|
|
PxebcMode->IpFilter.IpCnt = Filter->IpCnt;
|
|
|
|
//
|
|
// join groups for all multicast in list
|
|
//
|
|
for (Index = 0; Index < Filter->IpCnt; ++Index) {
|
|
if (IS_MULTICAST (&Filter->IpList[Index])) {
|
|
IgmpJoinGroup (Private, &Filter->IpList[Index]);
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #5 %Xh (%r)", StatCode, StatCode));
|
|
|
|
return StatCode;
|
|
}
|
|
|
|
|
|
/**
|
|
Call the IP filter
|
|
|
|
@param Private Pointer to Pxe BaseCode Protocol
|
|
@param Filter Pointer to the filter
|
|
|
|
@retval 0 Successfully set the filter
|
|
@retval !0 Failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BcIpFilter (
|
|
IN EFI_PXE_BASE_CODE_PROTOCOL *This,
|
|
IN EFI_PXE_BASE_CODE_IP_FILTER *Filter
|
|
)
|
|
{
|
|
EFI_STATUS StatCode;
|
|
PXE_BASECODE_DEVICE *Private;
|
|
UINTN Index;
|
|
//
|
|
// Lock the instance data and make sure started
|
|
//
|
|
StatCode = EFI_SUCCESS;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
|
|
|
|
if (Private == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
for (Index = 0; Index < Filter->IpCnt; ++Index) {
|
|
if ((Filter->IpList[Index].Addr[0]) == BROADCAST_IPv4) {
|
|
//
|
|
// The IP is a broadcast address.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
if (This->Mode == NULL || !This->Mode->Started) {
|
|
DEBUG ((DEBUG_ERROR, "BC was not started."));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_NOT_STARTED;
|
|
}
|
|
|
|
if (Filter == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Issue BC command
|
|
//
|
|
StatCode = IpFilter (Private, Filter);
|
|
|
|
//
|
|
// Unlock the instance data
|
|
//
|
|
EfiReleaseLock (&Private->Lock);
|
|
return StatCode;
|
|
}
|
|
|
|
|
|
/**
|
|
Set the Base Code behavior parameters
|
|
|
|
@param This Pointer to Pxe BaseCode Protocol
|
|
@param AutoArpPtr Boolean to do ARP stuff
|
|
@param SendGuidPtr Boolean whether or not to send GUID info
|
|
@param TimeToLivePtr Value for Total time to live
|
|
@param TypeOfServicePtr Value for Type of Service
|
|
@param MakeCallbackPtr Boolean to determine if we make callbacks
|
|
|
|
@retval 0 Successfully set the parameters
|
|
@retval !0 Failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BcSetParameters (
|
|
EFI_PXE_BASE_CODE_PROTOCOL *This,
|
|
BOOLEAN *AutoArpPtr,
|
|
BOOLEAN *SendGuidPtr,
|
|
UINT8 *TimeToLivePtr,
|
|
UINT8 *TypeOfServicePtr,
|
|
BOOLEAN *MakeCallbackPtr
|
|
)
|
|
{
|
|
EFI_PXE_BASE_CODE_MODE *PxebcMode;
|
|
EFI_GUID TmpGuid;
|
|
UINT8 *SerialNumberPtr;
|
|
EFI_STATUS StatCode;
|
|
PXE_BASECODE_DEVICE *Private;
|
|
|
|
//
|
|
// Lock the instance data and make sure started
|
|
//
|
|
StatCode = EFI_SUCCESS;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
|
|
|
|
if (Private == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
if (This->Mode == NULL || !This->Mode->Started) {
|
|
DEBUG ((DEBUG_ERROR, "BC was not started."));
|
|
EfiReleaseLock (&Private->Lock);
|
|
return EFI_NOT_STARTED;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "\nSetParameters() Entry. "));
|
|
|
|
PxebcMode = Private->EfiBc.Mode;
|
|
StatCode = EFI_SUCCESS;
|
|
|
|
if (SendGuidPtr != NULL) {
|
|
if (*SendGuidPtr) {
|
|
if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (&TmpGuid, (CHAR8 **) &SerialNumberPtr) != EFI_SUCCESS) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (MakeCallbackPtr != NULL) {
|
|
if (*MakeCallbackPtr) {
|
|
if (!SetMakeCallback (Private)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
PxebcMode->MakeCallbacks = *MakeCallbackPtr;
|
|
}
|
|
|
|
if (AutoArpPtr != NULL) {
|
|
PxebcMode->AutoArp = *AutoArpPtr;
|
|
}
|
|
|
|
if (SendGuidPtr != NULL) {
|
|
PxebcMode->SendGUID = *SendGuidPtr;
|
|
}
|
|
|
|
if (TimeToLivePtr != NULL) {
|
|
PxebcMode->TTL = *TimeToLivePtr;
|
|
}
|
|
|
|
if (TypeOfServicePtr != NULL) {
|
|
PxebcMode->ToS = *TypeOfServicePtr;
|
|
}
|
|
//
|
|
// Unlock the instance data
|
|
//
|
|
DEBUG ((DEBUG_INFO, "\nSetparameters() Exit = %xh ", StatCode));
|
|
|
|
EfiReleaseLock (&Private->Lock);
|
|
return StatCode;
|
|
}
|
|
//
|
|
// //////////////////////////////////////////////////////////
|
|
//
|
|
// BC Set Station IP Routine
|
|
//
|
|
|
|
/**
|
|
Set the station IP address
|
|
|
|
@param This Pointer to Pxe BaseCode Protocol
|
|
@param StationIpPtr Pointer to the requested IP address to set in base
|
|
code
|
|
@param SubnetMaskPtr Pointer to the requested subnet mask for the base
|
|
code
|
|
|
|
@retval EFI_SUCCESS Successfully set the parameters
|
|
@retval EFI_NOT_STARTED BC has not started
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BcSetStationIP (
|
|
IN EFI_PXE_BASE_CODE_PROTOCOL *This,
|
|
IN EFI_IP_ADDRESS *StationIpPtr,
|
|
IN EFI_IP_ADDRESS *SubnetMaskPtr
|
|
)
|
|
{
|
|
EFI_PXE_BASE_CODE_MODE *PxebcMode;
|
|
EFI_STATUS StatCode;
|
|
PXE_BASECODE_DEVICE *Private;
|
|
UINT32 SubnetMask;
|
|
|
|
//
|
|
// Lock the instance data and make sure started
|
|
//
|
|
StatCode = EFI_SUCCESS;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
|
|
|
|
if (Private == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
if (This->Mode == NULL || !This->Mode->Started) {
|
|
DEBUG ((DEBUG_ERROR, "BC was not started."));
|
|
StatCode = EFI_NOT_STARTED;
|
|
goto RELEASE_LOCK;
|
|
}
|
|
|
|
PxebcMode = Private->EfiBc.Mode;
|
|
|
|
if (!Private->GoodStationIp && ((StationIpPtr == NULL) || (SubnetMaskPtr == NULL))) {
|
|
//
|
|
// It's not allowed to only set one of the two addresses while there isn't a previous
|
|
// GOOD address configuration.
|
|
//
|
|
StatCode = EFI_INVALID_PARAMETER;
|
|
goto RELEASE_LOCK;
|
|
}
|
|
|
|
if (SubnetMaskPtr != NULL) {
|
|
SubnetMask = SubnetMaskPtr->Addr[0];
|
|
|
|
if (SubnetMask & (SubnetMask + 1)) {
|
|
//
|
|
// the subnet mask is valid if it's with leading continuous 1 bits.
|
|
//
|
|
StatCode = EFI_INVALID_PARAMETER;
|
|
goto RELEASE_LOCK;
|
|
}
|
|
} else {
|
|
SubnetMaskPtr = &PxebcMode->SubnetMask;
|
|
SubnetMask = SubnetMaskPtr->Addr[0];
|
|
}
|
|
|
|
if (StationIpPtr == NULL) {
|
|
StationIpPtr = &PxebcMode->StationIp;
|
|
}
|
|
|
|
if (!IS_INADDR_UNICAST (StationIpPtr) ||
|
|
((StationIpPtr->Addr[0] | SubnetMask) == BROADCAST_IPv4)) {
|
|
//
|
|
// The station IP is not a unicast address.
|
|
//
|
|
StatCode = EFI_INVALID_PARAMETER;
|
|
goto RELEASE_LOCK;
|
|
}
|
|
|
|
CopyMem (&PxebcMode->StationIp, StationIpPtr, sizeof (EFI_IP_ADDRESS));
|
|
CopyMem (&PxebcMode->SubnetMask, SubnetMaskPtr, sizeof (EFI_IP_ADDRESS));
|
|
Private->GoodStationIp = TRUE;
|
|
|
|
RELEASE_LOCK:
|
|
//
|
|
// Unlock the instance data
|
|
//
|
|
EfiReleaseLock (&Private->Lock);
|
|
|
|
return StatCode;
|
|
}
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL mPxeBcDriverBinding = {
|
|
PxeBcDriverSupported,
|
|
PxeBcDriverStart,
|
|
PxeBcDriverStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
/**
|
|
Test to see if this driver supports Controller. Any Controller
|
|
than contains a Snp protocol can be supported.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Controller Handle of device to test.
|
|
@param RemainingDevicePath Not used.
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval EFI_ALREADY_STARTED This driver is already running on this device.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PxeBcDriverSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiDevicePathProtocolGuid,
|
|
NULL,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
(VOID **) &SnpPtr,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Start the Base code driver.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Controller Handle of device to test.
|
|
@param RemainingDevicePath Not used.
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval EFI_ALREADY_STARTED This driver is already running on this device.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PxeBcDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
PXE_BASECODE_DEVICE *Private;
|
|
LOADFILE_DEVICE *pLF;
|
|
|
|
//
|
|
// Allocate structures needed by BaseCode and LoadFile protocols.
|
|
//
|
|
Private = AllocateZeroPool (sizeof (PXE_BASECODE_DEVICE));
|
|
|
|
if (Private == NULL ) {
|
|
DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc PXE_BASECODE_DEVICE structure.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
pLF = AllocateZeroPool (sizeof (LOADFILE_DEVICE));
|
|
if (pLF == NULL) {
|
|
DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc LOADFILE_DEVICE structure.\n"));
|
|
FreePool (Private);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Private->EfiBc.Mode = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_MODE));
|
|
if (Private->EfiBc.Mode == NULL) {
|
|
DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc Mode structure.\n"));
|
|
FreePool (Private);
|
|
FreePool (pLF);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Lock access, just in case
|
|
//
|
|
EfiInitializeLock (&Private->Lock, TPL_CALLBACK);
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
EfiInitializeLock (&pLF->Lock, TPL_CALLBACK);
|
|
EfiAcquireLock (&pLF->Lock);
|
|
|
|
//
|
|
// Initialize PXE structure
|
|
//
|
|
//
|
|
// First initialize the internal 'private' data that the application
|
|
// does not see.
|
|
//
|
|
Private->Signature = PXE_BASECODE_DEVICE_SIGNATURE;
|
|
Private->Handle = Controller;
|
|
|
|
//
|
|
// Get the NII interface
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
|
|
(VOID **) &Private->NiiPtr,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto PxeBcError;
|
|
}
|
|
|
|
//
|
|
// Get the Snp interface
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
(VOID **) &Private->SimpleNetwork,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto PxeBcError;
|
|
}
|
|
|
|
//
|
|
// Next, initialize the external 'public' data that
|
|
// the application does see.
|
|
//
|
|
Private->EfiBc.Revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION;
|
|
Private->EfiBc.Start = BcStart;
|
|
Private->EfiBc.Stop = BcStop;
|
|
Private->EfiBc.Dhcp = BcDhcp;
|
|
Private->EfiBc.Discover = BcDiscover;
|
|
Private->EfiBc.Mtftp = BcMtftp;
|
|
Private->EfiBc.UdpWrite = BcUdpWrite;
|
|
Private->EfiBc.UdpRead = BcUdpRead;
|
|
Private->EfiBc.Arp = BcArp;
|
|
Private->EfiBc.SetIpFilter = BcIpFilter;
|
|
Private->EfiBc.SetParameters = BcSetParameters;
|
|
Private->EfiBc.SetStationIp = BcSetStationIP;
|
|
Private->EfiBc.SetPackets = BcSetPackets;
|
|
|
|
//
|
|
// Initialize BaseCode Mode structure
|
|
//
|
|
Private->EfiBc.Mode->Started = FALSE;
|
|
Private->EfiBc.Mode->TTL = DEFAULT_TTL;
|
|
Private->EfiBc.Mode->ToS = DEFAULT_ToS;
|
|
Private->EfiBc.Mode->UsingIpv6 = FALSE;
|
|
Private->EfiBc.Mode->AutoArp = TRUE;
|
|
|
|
//
|
|
// Set to PXE_TRUE by the BC constructor if this BC
|
|
// implementation supports IPv6.
|
|
//
|
|
Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6;
|
|
Private->EfiBc.Mode->Ipv6Available = FALSE;
|
|
|
|
//
|
|
// Set to TRUE by the BC constructor if this BC
|
|
// implementation supports BIS.
|
|
//
|
|
Private->EfiBc.Mode->BisSupported = TRUE;
|
|
Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private);
|
|
|
|
//
|
|
// Initialize LoadFile structure.
|
|
//
|
|
pLF->Signature = LOADFILE_DEVICE_SIGNATURE;
|
|
pLF->LoadFile.LoadFile = LoadFile;
|
|
pLF->Private = Private;
|
|
|
|
//
|
|
// Install protocol interfaces.
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Controller,
|
|
&gEfiPxeBaseCodeProtocolGuid,
|
|
&Private->EfiBc,
|
|
&gEfiLoadFileProtocolGuid,
|
|
&pLF->LoadFile,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
goto PxeBcError;
|
|
}
|
|
//
|
|
// Release locks.
|
|
//
|
|
EfiReleaseLock (&pLF->Lock);
|
|
EfiReleaseLock (&Private->Lock);
|
|
return Status;
|
|
|
|
PxeBcError: ;
|
|
gBS->FreePool (Private->EfiBc.Mode);
|
|
gBS->FreePool (Private);
|
|
gBS->FreePool (pLF);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Stop the Base code driver.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Controller Handle of device to test.
|
|
@param NumberOfChildren Not used
|
|
@param ChildHandleBuffer Not used
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval EFI_ALREADY_STARTED This driver is already running on this device.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PxeBcDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LOAD_FILE_PROTOCOL *LfProtocol;
|
|
LOADFILE_DEVICE *LoadDevice;
|
|
|
|
//
|
|
// Get our context back.
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiLoadFileProtocolGuid,
|
|
(VOID **) &LfProtocol,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
LoadDevice = EFI_LOAD_FILE_DEV_FROM_THIS (LfProtocol);
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
&gEfiLoadFileProtocolGuid,
|
|
&LoadDevice->LoadFile,
|
|
&gEfiPxeBaseCodeProtocolGuid,
|
|
&LoadDevice->Private->EfiBc,
|
|
NULL
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Status = gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiSimpleNetworkProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
gBS->FreePool (LoadDevice->Private->EfiBc.Mode);
|
|
gBS->FreePool (LoadDevice->Private);
|
|
gBS->FreePool (LoadDevice);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Initialize the base code drivers and install the driver binding
|
|
|
|
Standard EFI Image Entry
|
|
|
|
@retval EFI_SUCCESS This driver was successfully bound
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializeBCDriver (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Initialize EFI library
|
|
//
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&mPxeBcDriverBinding,
|
|
NULL,
|
|
&gPxeBcComponentName,
|
|
&gPxeBcComponentName2
|
|
);
|
|
|
|
InitArpHeader ();
|
|
OptionsStrucInit ();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* eof - bc.c */
|