/*++ Copyright (c) 2006 - 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" // // helper routines // VOID CvtNum ( IN UINTN Number, IN UINT8 *Buffer, IN INTN Length ) /*++ Routine Description: Convert number to ASCII value Arguments: Number - Numeric value to convert to decimal ASCII value. Buffer - Buffer to place ASCII version of the Number Length - Length of Buffer. Returns: none - none --*/ { UINTN Remainder; while (Length--) { Remainder = Number % 10; Number /= 10; Buffer[Length] = (UINT8) ('0' + Remainder); } } VOID UtoA10 ( IN UINTN Number, IN UINT8 *Buffer ) /*++ Routine Description: Convert number to decimal ASCII value at Buffer location Arguments: Number - Numeric value to convert to decimal ASCII value. Buffer - Buffer to place ASCII version of the Number Returns: none - none --*/ { INTN Index; UINT8 BuffArray[31]; BuffArray[30] = 0; CvtNum (Number, BuffArray, 30); for (Index = 0; Index < 30; ++Index) { if (BuffArray[Index] != '0') { break; } } CopyMem (Buffer, BuffArray + Index, 31 - Index); } UINTN AtoU ( IN UINT8 *Buffer ) /*++ Routine Description: Convert ASCII numeric string to a UINTN value Arguments: Number - Numeric value to convert to decimal ASCII value. Buffer - Buffer to place ASCII version of the Number Returns: Value - UINTN value of the ASCII string. --*/ { UINTN Value; INT8 Character; Value = 0; Character = *Buffer++; do { Value = Value * 10 + Character - '0'; Character = *Buffer++; } while (Character); return Value; } UINT64 AtoU64 ( IN UINT8 *Buffer ) /*++ Routine Description: Convert ASCII numeric string to a UINTN value Arguments: Number - Numeric value to convert to decimal ASCII value. Buffer - Buffer to place ASCII version of the Number Returns: Value - UINTN value of the ASCII string. --*/ { UINT64 Value; UINT8 Character; Value = 0; while ((Character = *Buffer++) != '\0') { Value = MultU64x32 (Value, 10) + (Character - '0'); } return Value; } // // random number generator // #define RANDOM_MULTIPLIER 2053 #define RANDOM_ADD_IN_VALUE 19 VOID SeedRandom ( IN PXE_BASECODE_DEVICE *Private, IN UINT16 InitialSeed ) /*++ Routine Description: Initialize the Seed for the random number generator Arguments: Returns: none - --*/ { if (Private != NULL) { Private->RandomSeed = InitialSeed; } } UINT16 Random ( IN PXE_BASECODE_DEVICE *Private ) /*++ Routine Description: Generate and return a pseudo-random number Arguments: Returns: Number - UINT16 random number --*/ { UINTN Number; if (Private != NULL) { Number = -(INTN) Private->RandomSeed * RANDOM_MULTIPLIER + RANDOM_ADD_IN_VALUE; return Private->RandomSeed = (UINT16) Number; } else { return 0; } } // // calculate the internet checksum (RFC 1071) // return 16 bit ones complement of ones complement sum of 16 bit words // UINT16 IpChecksum ( IN UINT16 *Packet, IN UINTN Length ) /*++ Routine Description: Calculate the internet checksum (see RFC 1071) Arguments: Packet - Buffer which contains the data to be checksummed Length - Length to be checksummed Returns: Checksum - Returns the 16 bit ones complement of ones complement sum of 16 bit words --*/ { UINT32 Sum; UINT8 Odd; Sum = 0; Odd = (UINT8) (Length & 1); Length >>= 1; while (Length--) { Sum += *Packet++; } if (Odd) { Sum += *(UINT8 *) Packet; } Sum = (Sum & 0xffff) + (Sum >> 16); // // in case above carried // Sum += Sum >> 16; return (UINT16) (~ (UINT16) Sum); } UINT16 IpChecksum2 ( IN UINT16 *Header, IN UINTN HeaderLen, IN UINT16 *Message, IN UINTN MessageLen ) /*++ Routine Description: Calculate the internet checksum (see RFC 1071) on a non contiguous header and data Arguments: Header - Buffer which contains the data to be checksummed HeaderLen - Length to be checksummed Message - Buffer which contains the data to be checksummed MessageLen - Length to be checksummed Returns: Checksum - Returns the 16 bit ones complement of ones complement sum of 16 bit words --*/ { UINT32 Sum; Sum = (UINT16)~IpChecksum (Header, HeaderLen); Sum = Sum + (UINT16)~IpChecksum (Message, MessageLen); // // in case above carried // Sum += Sum >> 16; return (UINT16) (~ (UINT16) Sum); } UINT16 UpdateChecksum ( IN UINT16 OldChksum, IN UINT16 OldWord, IN UINT16 NewWord ) /*++ Routine Description: Adjust the internet checksum (see RFC 1071) on a single word update. Arguments: OldChkSum - Checksum previously calculated OldWord - Value NewWord - New Value Returns: Checksum - Returns the 16 bit ones complement of ones complement sum of 16 bit words --*/ { UINT32 sum; sum = ~OldChksum + NewWord - OldWord; // // in case above carried // sum += sum >> 16; return (UINT16) (~ (UINT16) sum); } STATIC BOOLEAN SetMakeCallback ( IN PXE_BASECODE_DEVICE *Private ) /*++ Routine Description: See if a callback is in play Arguments: Private - Pointer to Pxe BaseCode Protocol Returns: 0 - Callbacks are active on the handle 1 - Callbacks are not active on the handle --*/ { Private->EfiBc.Mode->MakeCallbacks = (BOOLEAN) (gBS->HandleProtocol ( Private->Handle, &gEfiPxeBaseCodeCallbackProtocolGuid, (VOID *) &Private->CallbackProtocolPtr ) == EFI_SUCCESS); DEBUG ( (EFI_D_INFO, "\nMode->MakeCallbacks == %d ", Private->EfiBc.Mode->MakeCallbacks) ); DEBUG ( (EFI_D_INFO, "\nPrivate->CallbackProtocolPtr == %xh ", Private->CallbackProtocolPtr) ); if (Private->CallbackProtocolPtr != NULL) { DEBUG ( (EFI_D_INFO, "\nCallbackProtocolPtr->Revision = %xh ", Private->CallbackProtocolPtr->Revision) ); DEBUG ( (EFI_D_INFO, "\nCallbackProtocolPtr->Callback = %xh ", Private->CallbackProtocolPtr->Callback) ); } return Private->EfiBc.Mode->MakeCallbacks; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ EFI_STATUS WaitForReceive ( IN PXE_BASECODE_DEVICE *Private, IN EFI_PXE_BASE_CODE_FUNCTION Function, IN EFI_EVENT TimeoutEvent, IN OUT UINTN *HeaderSizePtr, IN OUT UINTN *BufferSizePtr, IN OUT UINT16 *ProtocolPtr ) /*++ Routine Description: Routine which does an SNP->Receive over a timeout period and doing callbacks Arguments: Private - Pointer to Pxe BaseCode Protocol Function - What PXE function to callback TimeoutEvent - Timer event that will trigger when we have waited too long for an incoming packet HeaderSizePtr - Pointer to the size of the Header size BufferSizePtr - Pointer to the size of the Buffer size ProtocolPtr - The protocol to sniff for (namely, UDP/etc) Returns: 0 - Something was returned !0 - Like there was nothing to receive (EFI_TIMEOUT/NOT_READY) --*/ { EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; EFI_PXE_CALLBACK CallbackPtr; EFI_STATUS StatCode; EFI_EVENT CallbackEvent; // // Initialize pointer to SNP interface // SnpPtr = Private->SimpleNetwork; // // Initialize pointer to PxeBc callback routine - if any // CallbackPtr = (Private->EfiBc.Mode->MakeCallbacks) ? Private->CallbackProtocolPtr->Callback : NULL; // // Create callback event and set timer // StatCode = gBS->CreateEvent ( 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; } EFI_STATUS SendPacket ( PXE_BASECODE_DEVICE *Private, VOID *HeaderPtr, VOID *PacketPtr, INTN PacketLen, VOID *HardwareAddr, UINT16 MediaProtocol, IN EFI_PXE_BASE_CODE_FUNCTION Function ) /*++ Routine Description: Routine which does an SNP->Transmit of a buffer Arguments: Private - Pointer to Pxe BaseCode Protocol HeaderPtr - Pointer to the buffer PacketPtr - Pointer to the packet to send PacketLen - The length of the entire packet to send HardwareAddr - Pointer to the MAC address of the destination MediaProtocol - What type of frame to create (RFC 1700) - IE. Ethernet Function - What PXE function to callback Returns: 0 - Something was sent !0 - An error was encountered during sending of a packet --*/ { EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; EFI_SIMPLE_NETWORK_MODE *SnpModePtr; EFI_PXE_CALLBACK CallbackPtr; EFI_STATUS StatCode; EFI_EVENT TimeoutEvent; UINT32 IntStatus; VOID *TxBuf; // // // CallbackPtr = Private->EfiBc.Mode->MakeCallbacks ? Private->CallbackProtocolPtr->Callback : 0; SnpPtr = Private->SimpleNetwork; SnpModePtr = SnpPtr->Mode; // // clear prior interrupt status // StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, 0); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_WARN, "\nSendPacket() Exit #1 %xh (%r)", StatCode, StatCode) ); return StatCode; } Private->DidTransmit = FALSE; if (CallbackPtr != NULL) { if (CallbackPtr ( Private->CallbackProtocolPtr, Function, FALSE, (UINT32) PacketLen, PacketPtr ) != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { DEBUG ( (EFI_D_WARN, "\nSendPacket() Exit #2 %xh (%r)", EFI_ABORTED, EFI_ABORTED) ); return EFI_ABORTED; } } // // put packet in transmit queue // headersize should be zero if not filled in // StatCode = gBS->CreateEvent ( EVT_TIMER, TPL_CALLBACK, NULL, NULL, &TimeoutEvent ); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_ERROR, "Could not create transmit timeout event. %r\n", StatCode) ); return EFI_DEVICE_ERROR; } // // 5 milliseconds // StatCode = gBS->SetTimer ( TimeoutEvent, TimerRelative, 50000 ); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_ERROR, "Could not set transmit timeout event timer. %r\n", StatCode) ); gBS->CloseEvent (TimeoutEvent); return EFI_DEVICE_ERROR; } for (;;) { StatCode = SnpPtr->Transmit ( SnpPtr, (UINTN) SnpPtr->Mode->MediaHeaderSize, (UINTN) (PacketLen + SnpPtr->Mode->MediaHeaderSize), HeaderPtr, &SnpModePtr->CurrentAddress, (EFI_MAC_ADDRESS *) HardwareAddr, &MediaProtocol ); if (StatCode != EFI_NOT_READY) { break; } if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { StatCode = EFI_TIMEOUT; break; } } gBS->CloseEvent (TimeoutEvent); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_WARN, "\nSendPacket() Exit #3 %xh (%r)", StatCode, StatCode) ); return StatCode; } // // remove transmit buffer from snp's unused queue // done this way in case someday things are buffered and we don't get it back // immediately // StatCode = gBS->CreateEvent ( EVT_TIMER, TPL_CALLBACK, NULL, NULL, &TimeoutEvent ); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_ERROR, "Could not create transmit status timeout event. %r\n", StatCode) ); return EFI_DEVICE_ERROR; } // // 5 milliseconds // StatCode = gBS->SetTimer ( TimeoutEvent, TimerRelative, 50000 ); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_ERROR, "Could not set transmit status timeout event timer. %r\n", StatCode) ); gBS->CloseEvent (TimeoutEvent); return EFI_DEVICE_ERROR; } for (;;) { StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, &TxBuf); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_WARN, "\nSendPacket() Exit #4 %xh (%r)", StatCode, StatCode) ); break; } if (IntStatus & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT) { Private->DidTransmit = TRUE; } if (TxBuf != NULL) { break; } if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { StatCode = EFI_TIMEOUT; break; } } gBS->CloseEvent (TimeoutEvent); return StatCode; } // // // EFI_BIS_PROTOCOL * PxebcBisStart ( IN PXE_BASECODE_DEVICE *Private, OUT BIS_APPLICATION_HANDLE *BisAppHandle, OUT OPTIONAL EFI_BIS_DATA **BisDataSigInfo ) /*++ Routine description: Locate BIS interface and if found, try to start it. Parameters: Private := Pointer to PxeBc protocol BisAppHandle := Pointer to BIS application handle storage BisDataSigInfo := Pointer to BIS signature information storage Returns: --*/ { EFI_STATUS EfiStatus; EFI_HANDLE BisHandleBuffer; UINTN BisHandleCount; EFI_BIS_PROTOCOL *BisPtr; EFI_BIS_VERSION BisInterfaceVersion; BOOLEAN BisCheckFlag; BisHandleCount = sizeof (EFI_HANDLE); BisCheckFlag = FALSE; // // Locate BIS protocol handle (if present). // If BIS protocol handle is not found, return NULL. // DEBUG ((EFI_D_INFO, "\ngBS->LocateHandle() ")); EfiStatus = gBS->LocateHandle ( ByProtocol, &gEfiBisProtocolGuid, NULL, &BisHandleCount, &BisHandleBuffer ); if (EFI_ERROR (EfiStatus)) { // // Any error means that there is no BIS. // Note - It could mean that there are more than // one BIS protocols installed, but that scenario // is not yet supported. // DEBUG ( (EFI_D_WARN, "\nPxebcBisStart()""\n gBS->LocateHandle() %r (%xh)\n", EfiStatus, EfiStatus) ); return NULL; } if (BisHandleCount != sizeof (BisHandleBuffer)) { // // This really should never happen, but I am paranoid. // DEBUG ( (EFI_D_NET, "\nPxebcBisStart() BisHandleCount != %d\n", sizeof BisHandleBuffer) ); return NULL; } DEBUG ((EFI_D_INFO, "BIS handle found.")); // // Locate BIS protocol interface. // If the BIS protocol interface cannot be found, return NULL. // DEBUG ((EFI_D_INFO, "\ngBS->HandleProtocol() ")); EfiStatus = gBS->HandleProtocol ( BisHandleBuffer, &gEfiBisProtocolGuid, (VOID **) &BisPtr ); if (EFI_ERROR (EfiStatus)) { DEBUG ( (EFI_D_WARN, "\nPxebcBisStart()""\n gBS->HandleProtocol() %r (%xh)\n", EfiStatus, EfiStatus) ); return NULL; } if (BisPtr == NULL) { // // This really should never happen. // DEBUG ( (EFI_D_NET, "\nPxebcBisStart()""\n gBS->HandleProtocoL() ""BIS protocol interface pointer is NULL!\n") ); return NULL; } DEBUG ((EFI_D_INFO, "BIS protocol interface found.")); // // Check that all of the BIS API function pointers are not NULL. // if (BisPtr->Initialize == NULL || BisPtr->Shutdown == NULL || BisPtr->Free == NULL || BisPtr->GetBootObjectAuthorizationCertificate == NULL || BisPtr->GetBootObjectAuthorizationCheckFlag == NULL || BisPtr->GetBootObjectAuthorizationUpdateToken == NULL || BisPtr->GetSignatureInfo == NULL || BisPtr->UpdateBootObjectAuthorization == NULL || BisPtr->VerifyBootObject == NULL || BisPtr->VerifyObjectWithCredential == NULL ) { DEBUG ( ( EFI_D_NET, "\nPxebcBisStart()""\n BIS protocol interface is invalid." "\n At least one BIS protocol function pointer is NULL.\n" ) ); return NULL; } // // Initialize BIS. // If BIS does not initialize, return NULL. // DEBUG ((EFI_D_INFO, "\nBisPtr->Initialize() ")); BisInterfaceVersion.Major = BIS_VERSION_1; EfiStatus = BisPtr->Initialize ( BisPtr, BisAppHandle, &BisInterfaceVersion, NULL ); if (EFI_ERROR (EfiStatus)) { DEBUG ( (EFI_D_WARN, "\nPxebcBisStart()""\n BisPtr->Initialize() %r (%xh)\n", EfiStatus, EfiStatus) ); return NULL; } DEBUG ( (EFI_D_INFO, " BIS version: %d.%d", BisInterfaceVersion.Major, BisInterfaceVersion.Minor) ); // // If the requested BIS API version is not supported, // shutdown BIS and return NULL. // if (BisInterfaceVersion.Major != BIS_VERSION_1) { DEBUG ( (EFI_D_WARN, "\nPxebcBisStart()""\n BIS version %d.%d not supported by PXE BaseCode.\n", BisInterfaceVersion.Major, BisInterfaceVersion.Minor) ); BisPtr->Shutdown (*BisAppHandle); return NULL; } // // Get BIS check flag. // If the BIS check flag cannot be read, shutdown BIS and return NULL. // DEBUG ((EFI_D_INFO, "\nBisPtr->GetBootObjectAuthorizationCheckFlag() ")); EfiStatus = BisPtr->GetBootObjectAuthorizationCheckFlag (*BisAppHandle, &BisCheckFlag); if (EFI_ERROR (EfiStatus)) { DEBUG ( (EFI_D_WARN, "\nPxebcBisStart()""\n BisPtr->GetBootObjectAuthorizationCheckFlag() %r (%xh)\n", EfiStatus, EfiStatus) ); BisPtr->Shutdown (*BisAppHandle); return NULL; } // // If the BIS check flag is FALSE, shutdown BIS and return NULL. // if (!BisCheckFlag) { DEBUG ((EFI_D_INFO, "\nBIS check flag is FALSE.\n")); BisPtr->Shutdown (*BisAppHandle); return NULL; } else { DEBUG ((EFI_D_INFO, "\nBIS check flag is TRUE.")); } // // Early out if caller does not want signature information. // if (BisDataSigInfo == NULL) { return BisPtr; } // // Get BIS signature information. // If the signature information cannot be read or is invalid, // shutdown BIS and return NULL. // DEBUG ((EFI_D_INFO, "\nBisPtr->GetSignatureInfo() ")); EfiStatus = BisPtr->GetSignatureInfo (*BisAppHandle, BisDataSigInfo); if (EFI_ERROR (EfiStatus)) { DEBUG ( (EFI_D_WARN, "\nPxebcBisStart()""\n BisPtr_GetSignatureInfo() %r (%xh)\n", EfiStatus, EfiStatus) ); BisPtr->Shutdown (*BisAppHandle); return NULL; } if (*BisDataSigInfo == NULL) { // // This should never happen. // DEBUG ( (EFI_D_NET, "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Data pointer is NULL!\n") ); BisPtr->Shutdown (*BisAppHandle); return NULL; } if ((*BisDataSigInfo)->Length < sizeof (EFI_BIS_SIGNATURE_INFO) || (*BisDataSigInfo)->Length % sizeof (EFI_BIS_SIGNATURE_INFO) || (*BisDataSigInfo)->Length > sizeof (EFI_BIS_SIGNATURE_INFO) * 63 ) { // // This should never happen. // DEBUG ( (EFI_D_NET, "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Invalid BIS siginfo length.\n") ); BisPtr->Free (*BisAppHandle, *BisDataSigInfo); BisPtr->Shutdown (*BisAppHandle); return NULL; } return BisPtr; } VOID PxebcBisStop ( EFI_BIS_PROTOCOL *BisPtr, BIS_APPLICATION_HANDLE BisAppHandle, EFI_BIS_DATA *BisDataSigInfo ) /*++ Routine description: Stop the BIS interface and release allocations. Parameters: BisPtr := Pointer to BIS interface BisAppHandle := BIS application handle BisDataSigInfo := Pointer to BIS signature information data Returns: --*/ { if (BisPtr == NULL) { return ; } // // Free BIS allocated resources and shutdown BIS. // Return TRUE - BIS support is officially detected. // if (BisDataSigInfo != NULL) { BisPtr->Free (BisAppHandle, BisDataSigInfo); } BisPtr->Shutdown (BisAppHandle); } BOOLEAN PxebcBisVerify ( PXE_BASECODE_DEVICE *Private, VOID *FileBuffer, UINTN FileLength, VOID *CredentialBuffer, UINTN CredentialLength ) /*++ Routine description: Verify image and credential file. Parameters: Private := Pointer to PxeBc interface FileBuffer := Pointer to image buffer FileLength := Image length in bytes CredentialBuffer := Pointer to credential buffer CredentialLength := Credential length in bytes Returns: TRUE := verified FALSE := not verified --*/ { EFI_BIS_PROTOCOL *BisPtr; BIS_APPLICATION_HANDLE BisAppHandle; EFI_BIS_DATA FileData; EFI_BIS_DATA CredentialData; EFI_STATUS EfiStatus; BOOLEAN IsVerified; if (Private == NULL || FileBuffer == NULL || FileLength == 0 || CredentialBuffer == NULL || CredentialLength == 0) { return FALSE; } BisPtr = PxebcBisStart (Private, &BisAppHandle, NULL); if (BisPtr == NULL) { return FALSE; } FileData.Length = (UINT32) FileLength; FileData.Data = FileBuffer; CredentialData.Length = (UINT32) CredentialLength; CredentialData.Data = CredentialBuffer; EfiStatus = BisPtr->VerifyBootObject ( BisAppHandle, &CredentialData, &FileData, &IsVerified ); PxebcBisStop (BisPtr, BisAppHandle, NULL); return (BOOLEAN) ((EFI_ERROR (EfiStatus)) ? FALSE : (IsVerified ? TRUE : FALSE)); } BOOLEAN PxebcBisDetect ( PXE_BASECODE_DEVICE *Private ) /*++ Routine description: Check for BIS interface presence. Parameters: Private := Pointer to PxeBc interface Returns: TRUE := BIS present FALSE := BIS not present --*/ { EFI_BIS_PROTOCOL *BisPtr; BIS_APPLICATION_HANDLE BisAppHandle; EFI_BIS_DATA *BisDataSigInfo; BisPtr = PxebcBisStart (Private, &BisAppHandle, &BisDataSigInfo); if (BisPtr == NULL) { return FALSE; } PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo); return TRUE; } VOID *BCNotifyReg; EFI_STATUS EFIAPI BcStart ( IN EFI_PXE_BASE_CODE_PROTOCOL *This, IN BOOLEAN UseIPv6 ) /*++ Routine Description: Start and initialize the BaseCode protocol, Simple Network protocol and UNDI. Arguments: Private - Pointer to Pxe BaseCode Protocol UseIPv6 - Do we want to support IPv6? Returns: EFI_SUCCESS EFI_INVALID_PARAMETER EFI_UNSUPPORTED EFI_ALREADY_STARTED EFI_OUT_OF_RESOURCES Status is also returned from SNP.Start() and SNP.Initialize(). --*/ { EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; EFI_SIMPLE_NETWORK_MODE *SnpModePtr; EFI_STATUS StatCode; PXE_BASECODE_DEVICE *Private; // // Lock the instance data // StatCode = EFI_SUCCESS; if (This == NULL) { DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); // // Make sure BaseCode is not already started. // if (This->Mode->Started) { DEBUG ((EFI_D_WARN, "\nBcStart() BC is already started.\n")); EfiReleaseLock (&Private->Lock); return EFI_ALREADY_STARTED; } // // Fail if IPv6 is requested and not supported. // if (UseIPv6) { DEBUG ((EFI_D_WARN, "\nBcStart() IPv6 is not supported.\n")); EfiReleaseLock (&Private->Lock); return EFI_UNSUPPORTED; } // // Setup shortcuts to SNP protocol and data structure. // SnpPtr = Private->SimpleNetwork; SnpModePtr = SnpPtr->Mode; // // Start and initialize SNP. // if (SnpModePtr->State == EfiSimpleNetworkStopped) { StatCode = (*SnpPtr->Start) (SnpPtr); if (SnpModePtr->State != EfiSimpleNetworkStarted) { DEBUG ((EFI_D_WARN, "\nBcStart() Could not start SNP.\n")); EfiReleaseLock (&Private->Lock); return StatCode; } } // // acquire memory for mode and transmit/receive buffers // if (SnpModePtr->State == EfiSimpleNetworkStarted) { StatCode = (*SnpPtr->Initialize) (SnpPtr, 0, 0); if (SnpModePtr->State != EfiSimpleNetworkInitialized) { DEBUG ((EFI_D_WARN, "\nBcStart() Could not initialize SNP.")); EfiReleaseLock (&Private->Lock); return StatCode; } } // // Dump debug info. // DEBUG ((EFI_D_INFO, "\nBC Start()")); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->State %Xh", SnpModePtr->State) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->HwAddressSize %Xh", SnpModePtr->HwAddressSize) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MediaHeaderSize %Xh", SnpModePtr->MediaHeaderSize) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MaxPacketSize %Xh", SnpModePtr->MaxPacketSize) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MacAddressChangeable %Xh", SnpModePtr->MacAddressChangeable) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MultipleTxSupported %Xh", SnpModePtr->MultipleTxSupported) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->CurrentAddress %Xh", *((UINTN *)&SnpModePtr->CurrentAddress)) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->BroadcastAddress %Xh", *((UINTN *)&SnpModePtr->BroadcastAddress)) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->PermanentAddress %Xh", *((UINTN *)&SnpModePtr->PermanentAddress)) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->NvRamSize %Xh", SnpModePtr->NvRamSize) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->NvRamAccessSize %Xh", SnpModePtr->NvRamAccessSize) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->ReceiveFilterMask %Xh", SnpModePtr->ReceiveFilterMask) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->ReceiveFilterSetting %Xh", SnpModePtr->ReceiveFilterSetting) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MCastFilterCount %Xh", SnpModePtr->MCastFilterCount) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MCastFilter %Xh", SnpModePtr->MCastFilter) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->IfType %Xh", SnpModePtr->IfType) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MediaPresentSupported %Xh", SnpModePtr->MediaPresentSupported) ); DEBUG ( (EFI_D_INFO, "\nSnpModePtr->MediaPresent %Xh", SnpModePtr->MediaPresent) ); // // If media check is supported and there is no media, // return error to caller. // if (SnpModePtr->MediaPresentSupported && !SnpModePtr->MediaPresent) { DEBUG ((EFI_D_WARN, "\nBcStart() Media not present.\n")); EfiReleaseLock (&Private->Lock); return EFI_NO_MEDIA; } // // Allocate Tx/Rx buffers // Private->TransmitBufferPtr = AllocateZeroPool (BUFFER_ALLOCATE_SIZE); if (Private->TransmitBufferPtr == NULL) { DEBUG ((EFI_D_NET, "\nBcStart() Could not alloc TxBuf.\n")); EfiReleaseLock (&Private->Lock); return EFI_OUT_OF_RESOURCES; } Private->ReceiveBufferPtr = AllocateZeroPool (BUFFER_ALLOCATE_SIZE); if (Private->ReceiveBufferPtr == NULL) { DEBUG ((EFI_D_NET, "\nBcStart() Could not alloc RxBuf.\n")); FreePool (Private->TransmitBufferPtr); EfiReleaseLock (&Private->Lock); return EFI_OUT_OF_RESOURCES; } Private->TftpErrorBuffer = AllocatePool (256); if (Private->TftpErrorBuffer == NULL) { FreePool (Private->ReceiveBufferPtr); FreePool (Private->TransmitBufferPtr); EfiReleaseLock (&Private->Lock); return EFI_OUT_OF_RESOURCES; } Private->TftpAckBuffer = AllocatePool (256); if (Private->TftpAckBuffer == NULL) { FreePool (Private->TftpErrorBuffer); FreePool (Private->ReceiveBufferPtr); FreePool (Private->TransmitBufferPtr); EfiReleaseLock (&Private->Lock); return EFI_OUT_OF_RESOURCES; } // // Initialize private BaseCode instance data // do { Private->RandomPort = (UINT16) (Private->RandomPort + PXE_RND_PORT_LOW + Random (Private)); } while (Private->RandomPort < PXE_RND_PORT_LOW); Private->Igmpv1TimeoutEvent = NULL; Private->UseIgmpv1Reporting = TRUE; Private->IpLength = IP_ADDRESS_LENGTH (Private->EfiBc.Mode); // // Initialize Mode structure // // // check for callback protocol and set boolean // SetMakeCallback (Private); Private->EfiBc.Mode->Started = TRUE; Private->EfiBc.Mode->TTL = DEFAULT_TTL; Private->EfiBc.Mode->ToS = DEFAULT_ToS; Private->EfiBc.Mode->UsingIpv6 = UseIPv6; Private->EfiBc.Mode->DhcpDiscoverValid = FALSE; Private->EfiBc.Mode->DhcpAckReceived = FALSE; Private->EfiBc.Mode->ProxyOfferReceived = FALSE; Private->EfiBc.Mode->PxeDiscoverValid = FALSE; Private->EfiBc.Mode->PxeReplyReceived = FALSE; Private->EfiBc.Mode->PxeBisReplyReceived = FALSE; Private->EfiBc.Mode->IcmpErrorReceived = FALSE; Private->EfiBc.Mode->TftpErrorReceived = FALSE; ZeroMem (&Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS)); ZeroMem (&Private->EfiBc.Mode->SubnetMask, sizeof (EFI_IP_ADDRESS)); Private->EfiBc.Mode->IpFilter.Filters = 0; Private->EfiBc.Mode->IpFilter.IpCnt = 0; Private->EfiBc.Mode->ArpCacheEntries = 0; Private->EfiBc.Mode->RouteTableEntries = 0; ZeroMem (&Private->EfiBc.Mode->IcmpError, sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)); ZeroMem (&Private->EfiBc.Mode->TftpError, sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR)); // // Set to PXE_TRUE by the BC constructor if this BC implementation // supports IPv6. // Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6; 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; } EFI_STATUS EFIAPI BcStop ( IN EFI_PXE_BASE_CODE_PROTOCOL *This ) /*++ Routine Description: Stop the BaseCode protocol, Simple Network protocol and UNDI. Arguments: Private - Pointer to Pxe BaseCode Protocol Returns: 0 - Successfully stopped !0 - Failed --*/ { // // Lock the instance data // EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; EFI_SIMPLE_NETWORK_MODE *SnpModePtr; EFI_STATUS StatCode; PXE_BASECODE_DEVICE *Private; StatCode = EFI_SUCCESS; if (This == NULL) { DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); 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) { FreePool (Private->TransmitBufferPtr); Private->TransmitBufferPtr = NULL; } if (Private->ReceiveBufferPtr != NULL) { FreePool (Private->ReceiveBufferPtr); Private->ReceiveBufferPtr = NULL; } if (Private->ArpBuffer != NULL) { FreePool (Private->ArpBuffer); Private->ArpBuffer = NULL; } if (Private->TftpErrorBuffer != NULL) { FreePool (Private->TftpErrorBuffer); Private->TftpErrorBuffer = NULL; } if (Private->TftpAckBuffer != NULL) { FreePool (Private->TftpAckBuffer); Private->TftpAckBuffer = NULL; } if (Private->Igmpv1TimeoutEvent != NULL) { gBS->CloseEvent (Private->Igmpv1TimeoutEvent); Private->Igmpv1TimeoutEvent = NULL; } Private->FileSize = 0; Private->EfiBc.Mode->Started = FALSE; // // Unlock the instance data // EfiReleaseLock (&Private->Lock); return StatCode; } const IPV4_ADDR AllSystemsGroup = { { 224, 0, 0, 1 } }; EFI_STATUS IpFilter ( IN PXE_BASECODE_DEVICE *Private, IN EFI_PXE_BASE_CODE_IP_FILTER *Filter ) /*++ Routine Description: Set up the IP filter Arguments: Private - Pointer to Pxe BaseCode Protocol Filter - Pointer to the filter Returns: 0 - Successfully set the filter !0 - Failed --*/ { EFI_STATUS StatCode; EFI_MAC_ADDRESS MACadds[PXE_IP_FILTER_SIZE]; EFI_PXE_BASE_CODE_MODE *PxebcMode; EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; EFI_SIMPLE_NETWORK_MODE *SnpModePtr; UINT32 Enable; UINT32 Disable; UINTN Index; UINTN Index2; PxebcMode = Private->EfiBc.Mode; SnpPtr = Private->SimpleNetwork; SnpModePtr = SnpPtr->Mode; // // validate input parameters // must have a filter // must not have any extra filter bits set // if (Filter == NULL || (Filter->Filters &~FILTER_BITS) // // must not have a count which is too large or with no IP list // || (Filter->IpCnt && (!Filter->IpList || Filter->IpCnt > PXE_IP_FILTER_SIZE)) // // must not have incompatible filters - promiscuous incompatible with anything else // || ( (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) && ((Filter->Filters &~EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) || Filter->IpCnt) ) ) { DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #1")); return EFI_INVALID_PARAMETER; } // // promiscuous multicast incompatible with multicast in IP list // if (Filter->IpCnt && (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST)) { for (Index = 0; Index < Filter->IpCnt; ++Index) { if (IS_MULTICAST (&Filter->IpList[Index])) { DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #2")); return EFI_INVALID_PARAMETER; } } } // // leave groups for all those multicast which are no longer enabled // for (Index = 0; Index < PxebcMode->IpFilter.IpCnt; ++Index) { if (!IS_MULTICAST (&PxebcMode->IpFilter.IpList[Index])) { continue; } for (Index2 = 0; Index2 < Filter->IpCnt; ++Index2) { if (!CompareMem (&PxebcMode->IpFilter.IpList[Index], &Filter->IpList[Index2], IP_ADDRESS_LENGTH (PxebcMode))) { // // still enabled // break; } } // // if we didn't find it, remove from group // if (Index2 == Filter->IpCnt) { IgmpLeaveGroup (Private, &PxebcMode->IpFilter.IpList[Index]); } } // // set enable bits, convert multicast ip adds, join groups // allways leave receive broadcast enabled at hardware layer // Index2 = 0; if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) { Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; } else { if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) { Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; } else { Enable = EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; for (Index = 0; Index < Filter->IpCnt; ++Index) { CopyMem (&(PxebcMode->IpFilter.IpList[Index]), &(Filter->IpList[Index]), sizeof (EFI_IP_ADDRESS)); if (IS_MULTICAST (&Filter->IpList[Index])) { EFI_IP_ADDRESS *TmpIp; Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; // // if this is the first group, add the all systems group to mcast list // if (!Index2) { TmpIp = (EFI_IP_ADDRESS *) &AllSystemsGroup; --Index; } else { TmpIp = (EFI_IP_ADDRESS *) &Filter->IpList[Index]; } // // get MAC address of IP // StatCode = (*SnpPtr->MCastIpToMac) (SnpPtr, PxebcMode->UsingIpv6, TmpIp, &MACadds[Index2++]); if (EFI_ERROR (StatCode)) { DEBUG ( (EFI_D_INFO, "\nIpFilter() Exit #2 %Xh (%r)", StatCode, StatCode) ); return StatCode; } } else { Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; } } } if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) { Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; } } // // if nothing changed, just return // DEBUG ( (EFI_D_INFO, "\nsnp->ReceiveFilterSetting == %Xh Filter->IpCnt == %Xh", SnpModePtr->ReceiveFilterSetting, Filter->IpCnt) ); if (SnpModePtr->ReceiveFilterSetting == Enable && !Filter->IpCnt) { DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #4")); return EFI_SUCCESS; } // // disable those currently set but not set in new filter // Disable = SnpModePtr->ReceiveFilterSetting &~Enable; StatCode = SnpPtr->ReceiveFilters (SnpPtr, Enable, Disable, FALSE, Index2, MACadds); PxebcMode->IpFilter.IpCnt = Filter->IpCnt; // // join groups for all multicast in list // for (Index = 0; Index < Filter->IpCnt; ++Index) { if (IS_MULTICAST (&Filter->IpList[Index])) { IgmpJoinGroup (Private, &Filter->IpList[Index]); } } DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #5 %Xh (%r)", StatCode, StatCode)); return StatCode; } EFI_STATUS EFIAPI BcIpFilter ( IN EFI_PXE_BASE_CODE_PROTOCOL *This, IN EFI_PXE_BASE_CODE_IP_FILTER *Filter ) /*++ Routine Description: Call the IP filter Arguments: Private - Pointer to Pxe BaseCode Protocol Filter - Pointer to the filter Returns: 0 - Successfully set the filter !0 - Failed --*/ { EFI_STATUS StatCode; PXE_BASECODE_DEVICE *Private; // // Lock the instance data and make sure started // StatCode = EFI_SUCCESS; if (This == NULL) { DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); if (This->Mode == NULL || !This->Mode->Started) { DEBUG ((EFI_D_ERROR, "BC was not started.")); EfiReleaseLock (&Private->Lock); return EFI_NOT_STARTED; } if (Filter == NULL) { return EFI_INVALID_PARAMETER; } // // Issue BC command // StatCode = IpFilter (Private, Filter); // // Unlock the instance data // EfiReleaseLock (&Private->Lock); return StatCode; } EFI_STATUS EFIAPI BcSetParameters ( EFI_PXE_BASE_CODE_PROTOCOL *This, BOOLEAN *AutoArpPtr, BOOLEAN *SendGuidPtr, UINT8 *TimeToLivePtr, UINT8 *TypeOfServicePtr, BOOLEAN *MakeCallbackPtr ) /*++ Routine Description: Set the Base Code behavior parameters Arguments: This - Pointer to Pxe BaseCode Protocol AutoArpPtr - Boolean to do ARP stuff SendGuidPtr - Boolean whether or not to send GUID info TimeToLivePtr - Value for Total time to live TypeOfServicePtr - Value for Type of Service MakeCallbackPtr - Boolean to determine if we make callbacks Returns: 0 - Successfully set the parameters !0 - Failed --*/ { EFI_PXE_BASE_CODE_MODE *PxebcMode; EFI_GUID TmpGuid; CHAR8 *SerialNumberPtr; EFI_STATUS StatCode; PXE_BASECODE_DEVICE *Private; // // Lock the instance data and make sure started // StatCode = EFI_SUCCESS; if (This == NULL) { DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); if (This->Mode == NULL || !This->Mode->Started) { DEBUG ((EFI_D_ERROR, "BC was not started.")); EfiReleaseLock (&Private->Lock); return EFI_NOT_STARTED; } DEBUG ((EFI_D_INFO, "\nSetParameters() Entry. ")); PxebcMode = Private->EfiBc.Mode; StatCode = EFI_SUCCESS; if (SendGuidPtr != NULL) { if (*SendGuidPtr) { if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (&TmpGuid, &SerialNumberPtr) != EFI_SUCCESS) { return EFI_INVALID_PARAMETER; } } } if (MakeCallbackPtr != NULL) { if (*MakeCallbackPtr) { if (!SetMakeCallback (Private)) { return EFI_INVALID_PARAMETER; } } PxebcMode->MakeCallbacks = *MakeCallbackPtr; } if (AutoArpPtr != NULL) { PxebcMode->AutoArp = *AutoArpPtr; } if (SendGuidPtr != NULL) { PxebcMode->SendGUID = *SendGuidPtr; } if (TimeToLivePtr != NULL) { PxebcMode->TTL = *TimeToLivePtr; } if (TypeOfServicePtr != NULL) { PxebcMode->ToS = *TypeOfServicePtr; } // // Unlock the instance data // DEBUG ((EFI_D_INFO, "\nSetparameters() Exit = %xh ", StatCode)); EfiReleaseLock (&Private->Lock); return StatCode; } // // ////////////////////////////////////////////////////////// // // BC Set Station IP Routine // EFI_STATUS EFIAPI BcSetStationIP ( IN EFI_PXE_BASE_CODE_PROTOCOL *This, IN EFI_IP_ADDRESS *StationIpPtr, IN EFI_IP_ADDRESS *SubnetMaskPtr ) /*++ Routine Description: Set the station IP address Arguments: This - Pointer to Pxe BaseCode Protocol StationIpPtr - Pointer to the requested IP address to set in base code SubnetMaskPtr - Pointer to the requested subnet mask for the base code Returns: EFI_SUCCESS - Successfully set the parameters EFI_NOT_STARTED - BC has not started --*/ { EFI_PXE_BASE_CODE_MODE *PxebcMode; EFI_STATUS StatCode; PXE_BASECODE_DEVICE *Private; UINT32 SubnetMask; // // Lock the instance data and make sure started // StatCode = EFI_SUCCESS; if (This == NULL) { DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); if (This->Mode == NULL || !This->Mode->Started) { DEBUG ((EFI_D_ERROR, "BC was not started.")); 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 gPxeBcDriverBinding = { PxeBcDriverSupported, PxeBcDriverStart, PxeBcDriverStop, 0xa, NULL, NULL }; EFI_STATUS EFIAPI PxeBcDriverSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) /*++ Routine Description: Test to see if this driver supports Controller. Any Controller than contains a Snp protocol can be supported. Arguments: This - Protocol instance pointer. Controller - Handle of device to test. RemainingDevicePath - Not used. Returns: EFI_SUCCESS - This driver supports this device. EFI_ALREADY_STARTED - This driver is already running on this device. other - This driver does not support this device. --*/ { EFI_STATUS Status; EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr; Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, NULL, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( Controller, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpPtr, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } gBS->CloseProtocol ( Controller, &gEfiSimpleNetworkProtocolGuid, This->DriverBindingHandle, Controller ); return Status; } EFI_STATUS EFIAPI PxeBcDriverStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) /*++ Routine Description: Start the Base code driver. Arguments: This - Protocol instance pointer. Controller - Handle of device to test. RemainingDevicePath - Not used. Returns: EFI_SUCCESS - This driver supports this device. EFI_ALREADY_STARTED - This driver is already running on this device. other - This driver does not support this device. --*/ { EFI_STATUS Status; PXE_BASECODE_DEVICE *Private; LOADFILE_DEVICE *pLF; // // Allocate structures needed by BaseCode and LoadFile protocols. // 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_INTERFACE_REVISION; Private->EfiBc.Start = BcStart; Private->EfiBc.Stop = BcStop; Private->EfiBc.Dhcp = BcDhcp; Private->EfiBc.Discover = BcDiscover; Private->EfiBc.Mtftp = BcMtftp; Private->EfiBc.UdpWrite = BcUdpWrite; Private->EfiBc.UdpRead = BcUdpRead; Private->EfiBc.Arp = BcArp; Private->EfiBc.SetIpFilter = BcIpFilter; Private->EfiBc.SetParameters = BcSetParameters; Private->EfiBc.SetStationIp = BcSetStationIP; Private->EfiBc.SetPackets = BcSetPackets; // // Initialize BaseCode Mode structure // Private->EfiBc.Mode->Started = FALSE; Private->EfiBc.Mode->TTL = DEFAULT_TTL; Private->EfiBc.Mode->ToS = DEFAULT_ToS; Private->EfiBc.Mode->UsingIpv6 = FALSE; Private->EfiBc.Mode->AutoArp = TRUE; // // Set to PXE_TRUE by the BC constructor if this BC // implementation supports IPv6. // Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6; 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: ; FreePool (Private->EfiBc.Mode); FreePool (Private); FreePool (pLF); return Status; } EFI_STATUS EFIAPI PxeBcDriverStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) /*++ Routine Description: Stop the Base code driver. Arguments: This - Protocol instance pointer. Controller - Handle of device to test. NumberOfChildren - Not used ChildHandleBuffer - Not used Returns: EFI_SUCCESS - This driver supports this device. EFI_ALREADY_STARTED - This driver is already running on this device. other - This driver does not support this device. --*/ { EFI_STATUS Status; EFI_LOAD_FILE_PROTOCOL *LfProtocol; LOADFILE_DEVICE *LoadDevice; // // Get our context back. // Status = gBS->OpenProtocol ( Controller, &gEfiLoadFileProtocolGuid, (VOID **) &LfProtocol, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } LoadDevice = EFI_LOAD_FILE_DEV_FROM_THIS (LfProtocol); Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiLoadFileProtocolGuid, &LoadDevice->LoadFile, &gEfiPxeBaseCodeProtocolGuid, &LoadDevice->Private->EfiBc, NULL ); if (!EFI_ERROR (Status)) { Status = gBS->CloseProtocol ( Controller, &gEfiSimpleNetworkProtocolGuid, This->DriverBindingHandle, Controller ); FreePool (LoadDevice->Private->EfiBc.Mode); FreePool (LoadDevice->Private); FreePool (LoadDevice); } return Status; } EFI_STATUS EFIAPI InitializeBCDriver ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: Initialize the base code drivers and install the driver binding Arguments: Standard EFI Image Entry Returns: EFI_SUCCESS - This driver was successfully bound --*/ { InitArpHeader (); OptionsStrucInit (); return EFI_SUCCESS; } /* eof - bc.c */