/*++ | |
Copyright (c) 2006, 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 | |
// | |
VOID | |
CvtNum ( | |
IN UINTN Number, | |
IN UINT8 *Buffer, | |
IN INTN Length | |
) | |
/*++ | |
Routine Description: | |
Convert number to ASCII value | |
Arguments: | |
Number - Numeric value to convert to decimal ASCII value. | |
Buffer - Buffer to place ASCII version of the Number | |
Length - Length of Buffer. | |
Returns: | |
none - none | |
--*/ | |
{ | |
UINTN Remainder; | |
while (Length--) { | |
Remainder = Number % 10; | |
Number /= 10; | |
Buffer[Length] = (UINT8) ('0' + Remainder); | |
} | |
} | |
VOID | |
UtoA10 ( | |
IN UINTN Number, | |
IN UINT8 *Buffer | |
) | |
/*++ | |
Routine Description: | |
Convert number to decimal ASCII value at Buffer location | |
Arguments: | |
Number - Numeric value to convert to decimal ASCII value. | |
Buffer - Buffer to place ASCII version of the Number | |
Returns: | |
none - none | |
--*/ | |
{ | |
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); | |
} | |
UINTN | |
AtoU ( | |
IN UINT8 *Buffer | |
) | |
/*++ | |
Routine Description: | |
Convert ASCII numeric string to a UINTN value | |
Arguments: | |
Number - Numeric value to convert to decimal ASCII value. | |
Buffer - Buffer to place ASCII version of the Number | |
Returns: | |
Value - UINTN value of the ASCII string. | |
--*/ | |
{ | |
UINTN Value; | |
INT8 Character; | |
Value = 0; | |
Character = *Buffer++; | |
do { | |
Value = Value * 10 + Character - '0'; | |
Character = *Buffer++; | |
} while (Character); | |
return Value; | |
} | |
UINT64 | |
AtoU64 ( | |
IN UINT8 *Buffer | |
) | |
/*++ | |
Routine Description: | |
Convert ASCII numeric string to a UINTN value | |
Arguments: | |
Number - Numeric value to convert to decimal ASCII value. | |
Buffer - Buffer to place ASCII version of the Number | |
Returns: | |
Value - UINTN value of the ASCII string. | |
--*/ | |
{ | |
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; | |
} | |
} | |
UINT16 | |
Random ( | |
IN PXE_BASECODE_DEVICE *Private | |
) | |
/*++ | |
Routine Description: | |
Generate and return a pseudo-random number | |
Arguments: | |
Returns: | |
Number - UINT16 random number | |
--*/ | |
{ | |
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 | |
// | |
UINT16 | |
IpChecksum ( | |
IN UINT16 *Packet, | |
IN UINTN Length | |
) | |
/*++ | |
Routine Description: | |
Calculate the internet checksum (see RFC 1071) | |
Arguments: | |
Packet - Buffer which contains the data to be checksummed | |
Length - Length to be checksummed | |
Returns: | |
Checksum - Returns the 16 bit ones complement of | |
ones complement sum of 16 bit words | |
--*/ | |
{ | |
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); | |
} | |
UINT16 | |
IpChecksum2 ( | |
IN UINT16 *Header, | |
IN UINTN HeaderLen, | |
IN UINT16 *Message, | |
IN UINTN MessageLen | |
) | |
/*++ | |
Routine Description: | |
Calculate the internet checksum (see RFC 1071) | |
on a non contiguous header and data | |
Arguments: | |
Header - Buffer which contains the data to be checksummed | |
HeaderLen - Length to be checksummed | |
Message - Buffer which contains the data to be checksummed | |
MessageLen - Length to be checksummed | |
Returns: | |
Checksum - Returns the 16 bit ones complement of | |
ones complement sum of 16 bit words | |
--*/ | |
{ | |
UINT32 Sum; | |
Sum = (UINT16)~IpChecksum (Header, HeaderLen) + (UINT16)~IpChecksum (Message, MessageLen); | |
// | |
// in case above carried | |
// | |
Sum += Sum >> 16; | |
return (UINT16) (~ (UINT16) Sum); | |
} | |
UINT16 | |
UpdateChecksum ( | |
IN UINT16 OldChksum, | |
IN UINT16 OldWord, | |
IN UINT16 NewWord | |
) | |
/*++ | |
Routine Description: | |
Adjust the internet checksum (see RFC 1071) on a single word update. | |
Arguments: | |
OldChkSum - Checksum previously calculated | |
OldWord - Value | |
NewWord - New Value | |
Returns: | |
Checksum - Returns the 16 bit ones complement of | |
ones complement sum of 16 bit words | |
--*/ | |
{ | |
UINT32 sum; | |
sum = ~OldChksum + NewWord - OldWord; | |
// | |
// in case above carried | |
// | |
sum += sum >> 16; | |
return (UINT16) (~ (UINT16) sum); | |
} | |
STATIC | |
BOOLEAN | |
SetMakeCallback ( | |
IN PXE_BASECODE_DEVICE *Private | |
) | |
/*++ | |
Routine Description: | |
See if a callback is in play | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
Returns: | |
0 - Callbacks are active on the handle | |
1 - Callbacks are not active on the handle | |
--*/ | |
{ | |
Private->EfiBc.Mode->MakeCallbacks = (BOOLEAN) (gBS->HandleProtocol ( | |
Private->Handle, | |
&gEfiPxeBaseCodeCallbackProtocolGuid, | |
(VOID *) &Private->CallbackProtocolPtr | |
) == EFI_SUCCESS); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nMode->MakeCallbacks == %d ", | |
Private->EfiBc.Mode->MakeCallbacks) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nPrivate->CallbackProtocolPtr == %xh ", | |
Private->CallbackProtocolPtr) | |
); | |
if (Private->CallbackProtocolPtr != NULL) { | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nCallbackProtocolPtr->Revision = %xh ", | |
Private->CallbackProtocolPtr->Revision) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nCallbackProtocolPtr->Callback = %xh ", | |
Private->CallbackProtocolPtr->Callback) | |
); | |
} | |
return Private->EfiBc.Mode->MakeCallbacks; | |
} | |
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
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 | |
) | |
/*++ | |
Routine Description: | |
Routine which does an SNP->Receive over a timeout period and doing callbacks | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
Function - What PXE function to callback | |
TimeoutEvent - Timer event that will trigger when we have waited too | |
long for an incoming packet | |
HeaderSizePtr - Pointer to the size of the Header size | |
BufferSizePtr - Pointer to the size of the Buffer size | |
ProtocolPtr - The protocol to sniff for (namely, UDP/etc) | |
Returns: | |
0 - Something was returned | |
!0 - Like there was nothing to receive (EFI_TIMEOUT/NOT_READY) | |
--*/ | |
{ | |
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 ( | |
EFI_EVENT_TIMER, | |
EFI_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 (;;) | |
{ | |
#if 0 | |
// | |
// Check for received packet event. | |
// | |
if (!EFI_ERROR (gBS->CheckEvent (SnpPtr->WaitForPacket))) { | |
// | |
// Packet should be available. Attempt to read it. | |
// | |
*BufferSizePtr = BUFFER_ALLOCATE_SIZE; | |
StatCode = SnpPtr->Receive ( | |
SnpPtr, | |
HeaderSizePtr, | |
BufferSizePtr, | |
Private->ReceiveBufferPtr, | |
0, | |
0, | |
ProtocolPtr | |
); | |
if (EFI_ERROR (StatCode)) { | |
break; | |
} | |
// | |
// 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; | |
} | |
#else | |
// | |
// 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; | |
} | |
#endif | |
// | |
// 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; | |
} | |
EFI_STATUS | |
SendPacket ( | |
PXE_BASECODE_DEVICE *Private, | |
VOID *HeaderPtr, | |
VOID *PacketPtr, | |
INTN PacketLen, | |
VOID *HardwareAddr, | |
UINT16 MediaProtocol, | |
IN EFI_PXE_BASE_CODE_FUNCTION Function | |
) | |
/*++ | |
Routine Description: | |
Routine which does an SNP->Transmit of a buffer | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
HeaderPtr - Pointer to the buffer | |
PacketPtr - Pointer to the packet to send | |
PacketLen - The length of the entire packet to send | |
HardwareAddr - Pointer to the MAC address of the destination | |
MediaProtocol - What type of frame to create (RFC 1700) - IE. Ethernet | |
Function - What PXE function to callback | |
Returns: | |
0 - Something was sent | |
!0 - An error was encountered during sending of a packet | |
--*/ | |
{ | |
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 ( | |
(EFI_D_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 ( | |
(EFI_D_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 ( | |
EFI_EVENT_TIMER, | |
EFI_TPL_CALLBACK, | |
NULL, | |
NULL, | |
&TimeoutEvent | |
); | |
if (EFI_ERROR (StatCode)) { | |
DEBUG ( | |
(EFI_D_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 ( | |
(EFI_D_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 ( | |
(EFI_D_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 ( | |
EFI_EVENT_TIMER, | |
EFI_TPL_CALLBACK, | |
NULL, | |
NULL, | |
&TimeoutEvent | |
); | |
if (EFI_ERROR (StatCode)) { | |
DEBUG ( | |
(EFI_D_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 ( | |
(EFI_D_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 ( | |
(EFI_D_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 | |
) | |
/*++ | |
Routine description: | |
Locate BIS interface and if found, try to start it. | |
Parameters: | |
Private := Pointer to PxeBc protocol | |
BisAppHandle := Pointer to BIS application handle storage | |
BisDataSigInfo := Pointer to BIS signature information storage | |
Returns: | |
--*/ | |
{ | |
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 ((EFI_D_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 ( | |
(EFI_D_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 ( | |
(EFI_D_NET, | |
"\nPxebcBisStart() BisHandleCount != %d\n", | |
sizeof BisHandleBuffer) | |
); | |
return NULL; | |
} | |
DEBUG ((EFI_D_INFO, "BIS handle found.")); | |
// | |
// Locate BIS protocol interface. | |
// If the BIS protocol interface cannot be found, return NULL. | |
// | |
DEBUG ((EFI_D_INFO, "\ngBS->HandleProtocol() ")); | |
EfiStatus = gBS->HandleProtocol ( | |
BisHandleBuffer, | |
&gEfiBisProtocolGuid, | |
(VOID **) &BisPtr | |
); | |
if (EFI_ERROR (EfiStatus)) { | |
DEBUG ( | |
(EFI_D_WARN, | |
"\nPxebcBisStart()""\n gBS->HandleProtocol() %r (%xh)\n", | |
EfiStatus, | |
EfiStatus) | |
); | |
return NULL; | |
} | |
if (BisPtr == NULL) { | |
// | |
// This really should never happen. | |
// | |
DEBUG ( | |
(EFI_D_NET, | |
"\nPxebcBisStart()""\n gBS->HandleProtocoL() ""BIS protocol interface pointer is NULL!\n") | |
); | |
return NULL; | |
} | |
DEBUG ((EFI_D_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 ( | |
( | |
EFI_D_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 ((EFI_D_INFO, "\nBisPtr->Initialize() ")); | |
BisInterfaceVersion.Major = BIS_VERSION_1; | |
EfiStatus = BisPtr->Initialize ( | |
BisPtr, | |
BisAppHandle, | |
&BisInterfaceVersion, | |
NULL | |
); | |
if (EFI_ERROR (EfiStatus)) { | |
DEBUG ( | |
(EFI_D_WARN, | |
"\nPxebcBisStart()""\n BisPtr->Initialize() %r (%xh)\n", | |
EfiStatus, | |
EfiStatus) | |
); | |
return NULL; | |
} | |
DEBUG ( | |
(EFI_D_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 ( | |
(EFI_D_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 ((EFI_D_INFO, "\nBisPtr->GetBootObjectAuthorizationCheckFlag() ")); | |
EfiStatus = BisPtr->GetBootObjectAuthorizationCheckFlag (*BisAppHandle, &BisCheckFlag); | |
if (EFI_ERROR (EfiStatus)) { | |
DEBUG ( | |
(EFI_D_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 ((EFI_D_INFO, "\nBIS check flag is FALSE.\n")); | |
BisPtr->Shutdown (*BisAppHandle); | |
return NULL; | |
} else { | |
DEBUG ((EFI_D_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 ((EFI_D_INFO, "\nBisPtr->GetSignatureInfo() ")); | |
EfiStatus = BisPtr->GetSignatureInfo (*BisAppHandle, BisDataSigInfo); | |
if (EFI_ERROR (EfiStatus)) { | |
DEBUG ( | |
(EFI_D_WARN, | |
"\nPxebcBisStart()""\n BisPtr_GetSignatureInfo() %r (%xh)\n", | |
EfiStatus, | |
EfiStatus) | |
); | |
BisPtr->Shutdown (*BisAppHandle); | |
return NULL; | |
} | |
if (*BisDataSigInfo == NULL) { | |
// | |
// This should never happen. | |
// | |
DEBUG ( | |
(EFI_D_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 ( | |
(EFI_D_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 | |
) | |
/*++ | |
Routine description: | |
Stop the BIS interface and release allocations. | |
Parameters: | |
BisPtr := Pointer to BIS interface | |
BisAppHandle := BIS application handle | |
BisDataSigInfo := Pointer to BIS signature information data | |
Returns: | |
--*/ | |
{ | |
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); | |
} | |
BOOLEAN | |
PxebcBisVerify ( | |
PXE_BASECODE_DEVICE *Private, | |
VOID *FileBuffer, | |
UINTN FileLength, | |
VOID *CredentialBuffer, | |
UINTN CredentialLength | |
) | |
/*++ | |
Routine description: | |
Verify image and credential file. | |
Parameters: | |
Private := Pointer to PxeBc interface | |
FileBuffer := Pointer to image buffer | |
FileLength := Image length in bytes | |
CredentialBuffer := Pointer to credential buffer | |
CredentialLength := Credential length in bytes | |
Returns: | |
TRUE := verified | |
FALSE := not verified | |
--*/ | |
{ | |
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)); | |
} | |
BOOLEAN | |
PxebcBisDetect ( | |
PXE_BASECODE_DEVICE *Private | |
) | |
/*++ | |
Routine description: | |
Check for BIS interface presence. | |
Parameters: | |
Private := Pointer to PxeBc interface | |
Returns: | |
TRUE := BIS present | |
FALSE := BIS not present | |
--*/ | |
{ | |
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; | |
} | |
VOID *BCNotifyReg; | |
EFI_STATUS | |
EFIAPI | |
BcStart ( | |
IN EFI_PXE_BASE_CODE_PROTOCOL *This, | |
IN BOOLEAN UseIPv6 | |
) | |
/*++ | |
Routine Description: | |
Start and initialize the BaseCode protocol, Simple Network protocol and UNDI. | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
UseIPv6 - Do we want to support IPv6? | |
Returns: | |
EFI_SUCCESS | |
EFI_INVALID_PARAMETER | |
EFI_UNSUPPORTED | |
EFI_ALREADY_STARTED | |
EFI_OUT_OF_RESOURCES | |
Status is also returned from SNP.Start() and SNP.Initialize(). | |
--*/ | |
{ | |
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 ((EFI_D_ERROR, "BC *This pointer == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); | |
if (Private == NULL) { | |
DEBUG ((EFI_D_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 ((EFI_D_WARN, "\nBcStart() BC is already started.\n")); | |
EfiReleaseLock (&Private->Lock); | |
return EFI_ALREADY_STARTED; | |
} | |
#if !SUPPORT_IPV6 | |
// | |
// Fail if IPv6 is requested and not supported. | |
// | |
if (UseIPv6) { | |
DEBUG ((EFI_D_WARN, "\nBcStart() IPv6 is not supported.\n")); | |
EfiReleaseLock (&Private->Lock); | |
return EFI_UNSUPPORTED; | |
} | |
#endif | |
// | |
// 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 ((EFI_D_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 ((EFI_D_WARN, "\nBcStart() Could not initialize SNP.")); | |
EfiReleaseLock (&Private->Lock); | |
return StatCode; | |
} | |
} | |
// | |
// Dump debug info. | |
// | |
DEBUG ((EFI_D_INFO, "\nBC Start()")); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->State %Xh", | |
SnpModePtr->State) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->HwAddressSize %Xh", | |
SnpModePtr->HwAddressSize) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MediaHeaderSize %Xh", | |
SnpModePtr->MediaHeaderSize) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MaxPacketSize %Xh", | |
SnpModePtr->MaxPacketSize) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MacAddressChangeable %Xh", | |
SnpModePtr->MacAddressChangeable) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MultipleTxSupported %Xh", | |
SnpModePtr->MultipleTxSupported) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->CurrentAddress %Xh", | |
*((UINTN *)&SnpModePtr->CurrentAddress)) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->BroadcastAddress %Xh", | |
*((UINTN *)&SnpModePtr->BroadcastAddress)) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->PermanentAddress %Xh", | |
*((UINTN *)&SnpModePtr->PermanentAddress)) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->NvRamSize %Xh", | |
SnpModePtr->NvRamSize) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->NvRamAccessSize %Xh", | |
SnpModePtr->NvRamAccessSize) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->ReceiveFilterMask %Xh", | |
SnpModePtr->ReceiveFilterMask) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->ReceiveFilterSetting %Xh", | |
SnpModePtr->ReceiveFilterSetting) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MCastFilterCount %Xh", | |
SnpModePtr->MCastFilterCount) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MCastFilter %Xh", | |
SnpModePtr->MCastFilter) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->IfType %Xh", | |
SnpModePtr->IfType) | |
); | |
DEBUG ( | |
(EFI_D_INFO, | |
"\nSnpModePtr->MediaPresentSupported %Xh", | |
SnpModePtr->MediaPresentSupported) | |
); | |
DEBUG ( | |
(EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 | |
// | |
// | |
// 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; | |
Private->EfiBc.Mode->DhcpDiscoverValid = FALSE; | |
Private->EfiBc.Mode->DhcpAckReceived = FALSE; | |
Private->EfiBc.Mode->ProxyOfferReceived = FALSE; | |
Private->EfiBc.Mode->PxeDiscoverValid = FALSE; | |
Private->EfiBc.Mode->PxeReplyReceived = FALSE; | |
Private->EfiBc.Mode->PxeBisReplyReceived = FALSE; | |
Private->EfiBc.Mode->IcmpErrorReceived = FALSE; | |
Private->EfiBc.Mode->TftpErrorReceived = FALSE; | |
ZeroMem (&Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS)); | |
ZeroMem (&Private->EfiBc.Mode->SubnetMask, sizeof (EFI_IP_ADDRESS)); | |
Private->EfiBc.Mode->IpFilter.Filters = 0; | |
Private->EfiBc.Mode->IpFilter.IpCnt = 0; | |
Private->EfiBc.Mode->ArpCacheEntries = 0; | |
Private->EfiBc.Mode->RouteTableEntries = 0; | |
ZeroMem (&Private->EfiBc.Mode->IcmpError, sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)); | |
ZeroMem (&Private->EfiBc.Mode->TftpError, sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR)); | |
// | |
// Set to PXE_TRUE by the BC constructor if this BC implementation | |
// supports IPv6. | |
// | |
Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6; | |
#if SUPPORT_IPV6 | |
Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported; | |
#else | |
Private->EfiBc.Mode->Ipv6Available = FALSE; | |
#endif | |
// | |
// 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; | |
} | |
EFI_STATUS | |
EFIAPI | |
BcStop ( | |
IN EFI_PXE_BASE_CODE_PROTOCOL *This | |
) | |
/*++ | |
Routine Description: | |
Stop the BaseCode protocol, Simple Network protocol and UNDI. | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
Returns: | |
0 - Successfully stopped | |
!0 - Failed | |
--*/ | |
{ | |
// | |
// Lock the instance data | |
// | |
EFI_PXE_BASE_CODE_MODE *PxebcMode; | |
EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; | |
EFI_SIMPLE_NETWORK_MODE *SnpModePtr; | |
EFI_STATUS StatCode; | |
PXE_BASECODE_DEVICE *Private; | |
StatCode = EFI_SUCCESS; | |
if (This == NULL) { | |
DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); | |
if (Private == NULL) { | |
DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
EfiAcquireLock (&Private->Lock); | |
PxebcMode = Private->EfiBc.Mode; | |
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; | |
Private->EfiBc.Mode->Started = FALSE; | |
// | |
// Unlock the instance data | |
// | |
EfiReleaseLock (&Private->Lock); | |
return StatCode; | |
} | |
const IPV4_ADDR AllSystemsGroup = { { 224, 0, 0, 1 } }; | |
EFI_STATUS | |
IpFilter ( | |
IN PXE_BASECODE_DEVICE *Private, | |
IN EFI_PXE_BASE_CODE_IP_FILTER *Filter | |
) | |
/*++ | |
Routine Description: | |
Set up the IP filter | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
Filter - Pointer to the filter | |
Returns: | |
0 - Successfully set the filter | |
!0 - Failed | |
--*/ | |
{ | |
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 ((EFI_D_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 ((EFI_D_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) | |
{ | |
#if SUPPORT_IPV6 | |
if (PxebcMode->UsingIpv6) { | |
// | |
// TBD | |
// | |
} else | |
#endif | |
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 ( | |
(EFI_D_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 ( | |
(EFI_D_INFO, | |
"\nsnp->ReceiveFilterSetting == %Xh Filter->IpCnt == %Xh", | |
SnpModePtr->ReceiveFilterSetting, | |
Filter->IpCnt) | |
); | |
if (SnpModePtr->ReceiveFilterSetting == Enable && !Filter->IpCnt) { | |
DEBUG ((EFI_D_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 ((EFI_D_INFO, "\nIpFilter() Exit #5 %Xh (%r)", StatCode, StatCode)); | |
return StatCode; | |
} | |
EFI_STATUS | |
EFIAPI | |
BcIpFilter ( | |
IN EFI_PXE_BASE_CODE_PROTOCOL *This, | |
IN EFI_PXE_BASE_CODE_IP_FILTER *Filter | |
) | |
/*++ | |
Routine Description: | |
Call the IP filter | |
Arguments: | |
Private - Pointer to Pxe BaseCode Protocol | |
Filter - Pointer to the filter | |
Returns: | |
0 - Successfully set the filter | |
!0 - Failed | |
--*/ | |
{ | |
EFI_STATUS StatCode; | |
PXE_BASECODE_DEVICE *Private; | |
// | |
// Lock the instance data and make sure started | |
// | |
StatCode = EFI_SUCCESS; | |
if (This == NULL) { | |
DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); | |
if (Private == NULL) { | |
DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
EfiAcquireLock (&Private->Lock); | |
if (This->Mode == NULL || !This->Mode->Started) { | |
DEBUG ((EFI_D_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; | |
} | |
EFI_STATUS | |
EFIAPI | |
BcSetParameters ( | |
EFI_PXE_BASE_CODE_PROTOCOL *This, | |
BOOLEAN *AutoArpPtr, | |
BOOLEAN *SendGuidPtr, | |
UINT8 *TimeToLivePtr, | |
UINT8 *TypeOfServicePtr, | |
BOOLEAN *MakeCallbackPtr | |
) | |
/*++ | |
Routine Description: | |
Set the Base Code behavior parameters | |
Arguments: | |
This - Pointer to Pxe BaseCode Protocol | |
AutoArpPtr - Boolean to do ARP stuff | |
SendGuidPtr - Boolean whether or not to send GUID info | |
TimeToLivePtr - Value for Total time to live | |
TypeOfServicePtr - Value for Type of Service | |
MakeCallbackPtr - Boolean to determine if we make callbacks | |
Returns: | |
0 - Successfully set the parameters | |
!0 - Failed | |
--*/ | |
{ | |
EFI_PXE_BASE_CODE_MODE *PxebcMode; | |
EFI_GUID TmpGuid; | |
CHAR8 *SerialNumberPtr; | |
EFI_STATUS StatCode; | |
PXE_BASECODE_DEVICE *Private; | |
// | |
// Lock the instance data and make sure started | |
// | |
StatCode = EFI_SUCCESS; | |
if (This == NULL) { | |
DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); | |
if (Private == NULL) { | |
DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
EfiAcquireLock (&Private->Lock); | |
if (This->Mode == NULL || !This->Mode->Started) { | |
DEBUG ((EFI_D_ERROR, "BC was not started.")); | |
EfiReleaseLock (&Private->Lock); | |
return EFI_NOT_STARTED; | |
} | |
DEBUG ((EFI_D_INFO, "\nSetParameters() Entry. ")); | |
PxebcMode = Private->EfiBc.Mode; | |
StatCode = EFI_SUCCESS; | |
if (SendGuidPtr != NULL) { | |
if (*SendGuidPtr) { | |
if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (&TmpGuid, &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 ((EFI_D_INFO, "\nSetparameters() Exit = %xh ", StatCode)); | |
EfiReleaseLock (&Private->Lock); | |
return StatCode; | |
} | |
// | |
// ////////////////////////////////////////////////////////// | |
// | |
// BC Set Station IP Routine | |
// | |
EFI_STATUS | |
EFIAPI | |
BcSetStationIP ( | |
IN EFI_PXE_BASE_CODE_PROTOCOL *This, | |
IN EFI_IP_ADDRESS *StationIpPtr, | |
IN EFI_IP_ADDRESS *SubnetMaskPtr | |
) | |
/*++ | |
Routine Description: | |
Set the station IP address | |
Arguments: | |
This - Pointer to Pxe BaseCode Protocol | |
StationIpPtr - Pointer to the requested IP address to set in base code | |
SubnetMaskPtr - Pointer to the requested subnet mask for the base code | |
Returns: | |
EFI_SUCCESS - Successfully set the parameters | |
EFI_NOT_STARTED - BC has not started | |
--*/ | |
{ | |
EFI_PXE_BASE_CODE_MODE *PxebcMode; | |
EFI_STATUS StatCode; | |
PXE_BASECODE_DEVICE *Private; | |
// | |
// Lock the instance data and make sure started | |
// | |
StatCode = EFI_SUCCESS; | |
if (This == NULL) { | |
DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); | |
if (Private == NULL) { | |
DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); | |
return EFI_INVALID_PARAMETER; | |
} | |
EfiAcquireLock (&Private->Lock); | |
if (This->Mode == NULL || !This->Mode->Started) { | |
DEBUG ((EFI_D_ERROR, "BC was not started.")); | |
EfiReleaseLock (&Private->Lock); | |
return EFI_NOT_STARTED; | |
} | |
PxebcMode = Private->EfiBc.Mode; | |
if (StationIpPtr != NULL) { | |
CopyMem (&PxebcMode->StationIp, StationIpPtr, sizeof (EFI_IP_ADDRESS)); | |
Private->GoodStationIp = TRUE; | |
} | |
if (SubnetMaskPtr != NULL) { | |
CopyMem (&PxebcMode->SubnetMask, SubnetMaskPtr, sizeof (EFI_IP_ADDRESS)); | |
} | |
// | |
// Unlock the instance data | |
// | |
EfiReleaseLock (&Private->Lock); | |
return EFI_SUCCESS; | |
} | |
EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding = { | |
PxeBcDriverSupported, | |
PxeBcDriverStart, | |
PxeBcDriverStop, | |
0x10, | |
NULL, | |
NULL | |
}; | |
EFI_STATUS | |
EFIAPI | |
PxeBcDriverSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
/*++ | |
Routine Description: | |
Test to see if this driver supports Controller. Any Controller | |
than contains a Snp protocol can be supported. | |
Arguments: | |
This - Protocol instance pointer. | |
Controller - Handle of device to test. | |
RemainingDevicePath - Not used. | |
Returns: | |
EFI_SUCCESS - This driver supports this device. | |
EFI_ALREADY_STARTED - This driver is already running on this device. | |
other - This driver does not support this device. | |
--*/ | |
{ | |
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; | |
} | |
EFI_STATUS | |
EFIAPI | |
PxeBcDriverStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
/*++ | |
Routine Description: | |
Start the Base code driver. | |
Arguments: | |
This - Protocol instance pointer. | |
Controller - Handle of device to test. | |
RemainingDevicePath - Not used. | |
Returns: | |
EFI_SUCCESS - This driver supports this device. | |
EFI_ALREADY_STARTED - This driver is already running on this device. | |
other - This driver does not support this device. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
PXE_BASECODE_DEVICE *Private; | |
LOADFILE_DEVICE *pLF; | |
// | |
// Allocate structures needed by BaseCode and LoadFile protocols. | |
// | |
Status = gBS->AllocatePool ( | |
EfiBootServicesData, | |
sizeof (PXE_BASECODE_DEVICE), | |
(VOID **) &Private | |
); | |
if (!EFI_ERROR (Status)) { | |
ZeroMem (Private, sizeof (PXE_BASECODE_DEVICE)); | |
} else { | |
DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc PXE_BASECODE_DEVICE structure.\n")); | |
return Status; | |
} | |
Status = gBS->AllocatePool ( | |
EfiBootServicesData, | |
sizeof (LOADFILE_DEVICE), | |
(VOID **) &pLF | |
); | |
if (!EFI_ERROR (Status)) { | |
ZeroMem (pLF, sizeof (LOADFILE_DEVICE)); | |
} else { | |
DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc LOADFILE_DEVICE structure.\n")); | |
gBS->FreePool (Private); | |
return Status; | |
} | |
Status = gBS->AllocatePool ( | |
EfiBootServicesData, | |
sizeof (EFI_PXE_BASE_CODE_MODE), | |
(VOID **) &Private->EfiBc.Mode | |
); | |
if (!EFI_ERROR (Status)) { | |
ZeroMem (Private->EfiBc.Mode, sizeof (EFI_PXE_BASE_CODE_MODE)); | |
} else { | |
DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc Mode structure.\n")); | |
gBS->FreePool (Private); | |
gBS->FreePool (pLF); | |
return Status; | |
} | |
// | |
// Lock access, just in case | |
// | |
EfiInitializeLock (&Private->Lock, EFI_TPL_CALLBACK); | |
EfiAcquireLock (&Private->Lock); | |
EfiInitializeLock (&pLF->Lock, EFI_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)) { | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiNetworkInterfaceIdentifierProtocolGuid, | |
(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_INTERFACE_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; | |
#if SUPPORT_IPV6 | |
Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported; | |
#else | |
Private->EfiBc.Mode->Ipv6Available = FALSE; | |
#endif | |
// | |
// 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; | |
} | |
EFI_STATUS | |
EFIAPI | |
PxeBcDriverStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
/*++ | |
Routine Description: | |
Stop the Base code driver. | |
Arguments: | |
This - Protocol instance pointer. | |
Controller - Handle of device to test. | |
NumberOfChildren - Not used | |
ChildHandleBuffer - Not used | |
Returns: | |
EFI_SUCCESS - This driver supports this device. | |
EFI_ALREADY_STARTED - This driver is already running on this device. | |
other - This driver does not support this device. | |
--*/ | |
{ | |
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; | |
} | |
EFI_STATUS | |
EFIAPI | |
InitializeBCDriver ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
/*++ | |
Routine Description: | |
Initialize the base code drivers and install the driver binding | |
Arguments: | |
Standard EFI Image Entry | |
Returns: | |
EFI_SUCCESS - This driver was successfully bound | |
--*/ | |
{ | |
InitArpHeader (); | |
OptionsStrucInit (); | |
return EFI_SUCCESS; | |
} | |
/* eof - bc.c */ |