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