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