]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Bc.c
diff --git a/MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c b/MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c
new file mode 100644 (file)
index 0000000..5f15c81
--- /dev/null
@@ -0,0 +1,2401 @@
+/** @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