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