summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c
diff options
context:
space:
mode:
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-30 02:37:10 +0000
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-30 02:37:10 +0000
commit772db4bb33ae66fa20e39f786b5f80d107d450a5 (patch)
tree206a2d4756e0f7e245e08ca75f3ba10df2e1cf7a /MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c
parenteca7eaf49be5f23e3c79270621df7097ef585349 (diff)
downloadedk2-772db4bb33ae66fa20e39f786b5f80d107d450a5.zip
edk2-772db4bb33ae66fa20e39f786b5f80d107d450a5.tar.gz
edk2-772db4bb33ae66fa20e39f786b5f80d107d450a5.tar.bz2
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c')
-rw-r--r--MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c2401
1 files changed, 2401 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c b/MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c
new file mode 100644
index 0000000..5f15c81
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c
@@ -0,0 +1,2401 @@
+/** @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;
+
+ Sum = (UINT16)~IpChecksum (Header, HeaderLen) + (UINT16)~IpChecksum (Message, MessageLen);
+
+ //
+ // 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;
+}
+
+static VOID *BCNotifyReg;
+
+
+/**
+ 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;
+ }
+
+#if !SUPPORT_IPV6
+ //
+ // 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;
+ }
+#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 ((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,
+ &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,
+ &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,
+ &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, &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_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 ((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);
+
+ 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;
+
+ 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) {
+ PxebcMode->IpFilter.IpList[Index] = Filter->IpList[Index];
+
+ 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, &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;
+ }
+
+ PxebcMode->StationIp = *StationIpPtr;
+ PxebcMode->SubnetMask = *SubnetMaskPtr;
+ 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)) {
+ 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_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;
+
+#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;
+}
+
+
+/**
+ 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 = EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &mPxeBcDriverBinding,
+ NULL,
+ COMPONENT_NAME,
+ NULL,
+ NULL
+ );
+
+ InitArpHeader ();
+ OptionsStrucInit ();
+
+ return EFI_SUCCESS;
+}
+
+/* eof - bc.c */