2. Enable Network stack to pass ICC build. 3. Sync Network library instances' module names with their filenames. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3692 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1619 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1619 lines
		
	
	
		
			43 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:
 | 
						|
  pxe_loadfile.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
  An implementation of the load file protocol for network devices.
 | 
						|
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
 | 
						|
#include "Bc.h"
 | 
						|
 | 
						|
#define DO_MENU     (EFI_SUCCESS)
 | 
						|
#define NO_MENU     (DO_MENU + 1)
 | 
						|
#define LOCAL_BOOT  (EFI_ABORTED)
 | 
						|
#define AUTO_SELECT (NO_MENU)
 | 
						|
 | 
						|
#define NUMBER_ROWS   25  // we set to mode 0
 | 
						|
#define MAX_MENULIST  23
 | 
						|
 | 
						|
#define Ctl(x)  (0x1F & (x))
 | 
						|
 | 
						|
typedef union {
 | 
						|
  DHCPV4_OP_STRUCT          *OpPtr;
 | 
						|
  PXE_BOOT_MENU_ENTRY       *CurrentMenuItemPtr;
 | 
						|
  PXE_OP_DISCOVERY_CONTROL  *DiscCtlOpStr;
 | 
						|
  PXE_OP_BOOT_MENU          *MenuPtr;
 | 
						|
  UINT8                     *BytePtr;
 | 
						|
} UNION_PTR;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  PxeBc callback routine for status updates and aborts.
 | 
						|
 | 
						|
  @param  This                                        Pointer to PxeBcCallback
 | 
						|
                                                      interface
 | 
						|
  @param  Function                                    PxeBc function ID#
 | 
						|
  @param  Received                                    Receive/transmit flag
 | 
						|
  @param  PacketLength                                Length of received packet (0
 | 
						|
                                                      == idle callback)
 | 
						|
  @param  PacketPtr                                   Pointer to received packet
 | 
						|
                                                      (NULL == idle callback)
 | 
						|
 | 
						|
  @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
 | 
						|
                                                      EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT
 | 
						|
                                                      -
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_PXE_BASE_CODE_CALLBACK_STATUS
 | 
						|
EFIAPI
 | 
						|
bc_callback (
 | 
						|
  IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  * This,
 | 
						|
  IN EFI_PXE_BASE_CODE_FUNCTION           Function,
 | 
						|
  IN BOOLEAN                              Received,
 | 
						|
  IN UINT32                               PacketLength,
 | 
						|
  IN EFI_PXE_BASE_CODE_PACKET             * PacketPtr OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  STATIC UINTN  Propeller;
 | 
						|
 | 
						|
  EFI_INPUT_KEY Key;
 | 
						|
  UINTN         Row;
 | 
						|
  UINTN         Col;
 | 
						|
 | 
						|
  Propeller = 0;
 | 
						|
  //
 | 
						|
  // Resolve Warning 4 unreferenced parameter problem
 | 
						|
  //
 | 
						|
  This = This;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check for user abort.
 | 
						|
  //
 | 
						|
  if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {
 | 
						|
    if (!Key.ScanCode) {
 | 
						|
      if (Key.UnicodeChar == Ctl ('c')) {
 | 
						|
        return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
 | 
						|
      }
 | 
						|
    } else if (Key.ScanCode == SCAN_ESC) {
 | 
						|
      return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Do nothing if this is a receive.
 | 
						|
  //
 | 
						|
  if (Received) {
 | 
						|
    return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // The display code is only for these functions.
 | 
						|
  //
 | 
						|
  switch (Function) {
 | 
						|
  case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
 | 
						|
    //
 | 
						|
    // If this is a transmit and not a M/TFTP open request,
 | 
						|
    // return now.  Do not print a dot for each M/TFTP packet
 | 
						|
    // that is sent, only for the open packets.
 | 
						|
    //
 | 
						|
    if (PacketLength != 0 && PacketPtr != NULL) {
 | 
						|
      if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
 | 
						|
        return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
 | 
						|
  case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Display routines
 | 
						|
  //
 | 
						|
  if (PacketLength != 0 && PacketPtr != NULL) {
 | 
						|
    //
 | 
						|
    // Display a '.' when a packet is transmitted.
 | 
						|
    //
 | 
						|
    AsciiPrint (".");
 | 
						|
  } else if (PacketLength == 0 && PacketPtr == NULL) {
 | 
						|
    //
 | 
						|
    // Display a propeller when waiting for packets if at
 | 
						|
    // least 200 ms have passed.
 | 
						|
    //
 | 
						|
    Row = gST->ConOut->Mode->CursorRow;
 | 
						|
    Col = gST->ConOut->Mode->CursorColumn;
 | 
						|
 | 
						|
    AsciiPrint ("%c", "/-\\|"[Propeller]);
 | 
						|
    gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);
 | 
						|
 | 
						|
    Propeller = (Propeller + 1) & 3;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
 | 
						|
}
 | 
						|
 | 
						|
STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  _bc_callback = {
 | 
						|
  EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
 | 
						|
  &bc_callback
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Display an IPv4 address in dot notation.
 | 
						|
 | 
						|
  @param  Ptr                                         Pointer to IPv4 address.
 | 
						|
 | 
						|
  @return None
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
PrintIpv4 (
 | 
						|
  UINT8 *Ptr
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (Ptr != NULL) {
 | 
						|
    AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Display client and server IP information.
 | 
						|
 | 
						|
  @param  Private                                     Pointer to PxeBc interface
 | 
						|
 | 
						|
  @return None
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
ShowMyInfo (
 | 
						|
  IN PXE_BASECODE_DEVICE *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PXE_BASE_CODE_MODE  *PxeBcMode;
 | 
						|
  UINTN                   Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Do nothing if a NULL pointer is passed in.
 | 
						|
  //
 | 
						|
  if (Private == NULL) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get pointer to PXE BaseCode mode structure
 | 
						|
  //
 | 
						|
  PxeBcMode = Private->EfiBc.Mode;
 | 
						|
 | 
						|
  //
 | 
						|
  // Display client IP address
 | 
						|
  //
 | 
						|
  AsciiPrint ("\rCLIENT IP: ");
 | 
						|
  PrintIpv4 (PxeBcMode->StationIp.v4.Addr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Display subnet mask
 | 
						|
  //
 | 
						|
  AsciiPrint ("  MASK: ");
 | 
						|
  PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Display DHCP and proxyDHCP IP addresses
 | 
						|
  //
 | 
						|
  if (PxeBcMode->ProxyOfferReceived) {
 | 
						|
    AsciiPrint ("\nDHCP IP: ");
 | 
						|
    PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
 | 
						|
 | 
						|
    AsciiPrint ("  PROXY IP: ");
 | 
						|
    PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
 | 
						|
  } else {
 | 
						|
    AsciiPrint ("  DHCP IP: ");
 | 
						|
    PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Display gateway IP addresses
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
 | 
						|
    if ((Index % 3) == 0) {
 | 
						|
      AsciiPrint ("\r\nGATEWAY IP:");
 | 
						|
    }
 | 
						|
 | 
						|
    AsciiPrint (" ");
 | 
						|
    PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);
 | 
						|
    AsciiPrint (" ");
 | 
						|
  }
 | 
						|
 | 
						|
  AsciiPrint ("\n");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Display prompt and wait for input.
 | 
						|
 | 
						|
  @param  Private                                     Pointer to PxeBc interface
 | 
						|
  @param  BootPromptPtr                               Pointer to PXE boot prompt
 | 
						|
                                                      option
 | 
						|
 | 
						|
  @retval AUTO_SELECT                                 DO_MENU -
 | 
						|
  @retval NO_MENU
 | 
						|
  @retval LOCAL_BOOT
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
DoPrompt (
 | 
						|
  PXE_BASECODE_DEVICE *Private,
 | 
						|
  PXE_OP_BOOT_PROMPT  *BootPromptPtr
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_EVENT   TimeoutEvent;
 | 
						|
  EFI_EVENT   SecondsEvent;
 | 
						|
  INT32       SecColumn;
 | 
						|
  INT32       SecRow;
 | 
						|
  UINT8       SaveChar;
 | 
						|
  UINT8       SecsLeft;
 | 
						|
 | 
						|
  //
 | 
						|
  // if auto select, just get right to it
 | 
						|
  //
 | 
						|
  if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {
 | 
						|
    return AUTO_SELECT;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // if no timeout, go directly to display of menu
 | 
						|
  //
 | 
						|
  if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {
 | 
						|
    return DO_MENU;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_TIMER,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  NULL,
 | 
						|
                  NULL,
 | 
						|
                  &TimeoutEvent
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return DO_MENU;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->SetTimer (
 | 
						|
                  TimeoutEvent,
 | 
						|
                  TimerRelative,
 | 
						|
                  BootPromptPtr->Timeout * 10000000 + 100000
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->CloseEvent (TimeoutEvent);
 | 
						|
    return DO_MENU;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_TIMER,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  NULL,
 | 
						|
                  NULL,
 | 
						|
                  &SecondsEvent
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->CloseEvent (TimeoutEvent);
 | 
						|
    return DO_MENU;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->SetTimer (
 | 
						|
                  SecondsEvent,
 | 
						|
                  TimerPeriodic,
 | 
						|
                  10000000
 | 
						|
                  );  /* 1 second */
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->CloseEvent (SecondsEvent);
 | 
						|
    gBS->CloseEvent (TimeoutEvent);
 | 
						|
    return DO_MENU;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // display the prompt
 | 
						|
  // IMPORTANT!  This prompt is an ASCII character string that may
 | 
						|
  // not be terminated with a NULL byte.
 | 
						|
  //
 | 
						|
  SaveChar  = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];
 | 
						|
  BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;
 | 
						|
 | 
						|
  AsciiPrint ("%a ", BootPromptPtr->Prompt);
 | 
						|
  BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;
 | 
						|
 | 
						|
  //
 | 
						|
  // wait until time expires or selection made - menu or local
 | 
						|
  //
 | 
						|
  SecColumn = gST->ConOut->Mode->CursorColumn;
 | 
						|
  SecRow    = gST->ConOut->Mode->CursorRow;
 | 
						|
  SecsLeft  = BootPromptPtr->Timeout;
 | 
						|
 | 
						|
  gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
 | 
						|
  AsciiPrint ("(%d) ", SecsLeft);
 | 
						|
 | 
						|
  //
 | 
						|
  // set the default action to be AUTO_SELECT
 | 
						|
  //
 | 
						|
  Status = AUTO_SELECT;
 | 
						|
 | 
						|
  while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
 | 
						|
    EFI_INPUT_KEY Key;
 | 
						|
 | 
						|
    if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {
 | 
						|
      --SecsLeft;
 | 
						|
      gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
 | 
						|
      AsciiPrint ("(%d) ", SecsLeft);
 | 
						|
    }
 | 
						|
 | 
						|
    if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
 | 
						|
      UINT8       Buffer[512];
 | 
						|
      UINTN       BufferSize;
 | 
						|
 | 
						|
      BufferSize = sizeof Buffer;
 | 
						|
 | 
						|
      Status = Private->EfiBc.UdpRead (
 | 
						|
                                &Private->EfiBc,
 | 
						|
                                EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
 | 
						|
                                EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
 | 
						|
                                EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
 | 
						|
                                NULL, /* dest ip */
 | 
						|
                                NULL, /* dest port */
 | 
						|
                                NULL, /* src ip */
 | 
						|
                                NULL, /* src port */
 | 
						|
                                NULL, /* hdr size */
 | 
						|
                                NULL, /* hdr ptr */
 | 
						|
                                &BufferSize,
 | 
						|
                                Buffer
 | 
						|
                                );
 | 
						|
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Key.ScanCode == 0) {
 | 
						|
      switch (Key.UnicodeChar) {
 | 
						|
      case Ctl ('c'):
 | 
						|
        Status = LOCAL_BOOT;
 | 
						|
        break;
 | 
						|
 | 
						|
      case Ctl ('m'):
 | 
						|
      case 'm':
 | 
						|
      case 'M':
 | 
						|
        Status = DO_MENU;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      switch (Key.ScanCode) {
 | 
						|
      case SCAN_F8:
 | 
						|
        Status = DO_MENU;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_ESC:
 | 
						|
        Status = LOCAL_BOOT;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->CloseEvent (SecondsEvent);
 | 
						|
  gBS->CloseEvent (TimeoutEvent);
 | 
						|
 | 
						|
  gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
 | 
						|
  AsciiPrint ("     ");
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Display one menu item.
 | 
						|
 | 
						|
  @param  MenuItemPtr                                 Pointer to PXE menu item
 | 
						|
                                                      option.
 | 
						|
 | 
						|
  @return None
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
PrintMenuItem (
 | 
						|
  PXE_BOOT_MENU_ENTRY *MenuItemPtr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 Length;
 | 
						|
  UINT8 SaveChar;
 | 
						|
 | 
						|
  Length                    = (UINT8) MIN (70, MenuItemPtr->DataLen);
 | 
						|
  SaveChar                  = MenuItemPtr->Data[Length];
 | 
						|
 | 
						|
  MenuItemPtr->Data[Length] = 0;
 | 
						|
  AsciiPrint ("     %a\n", MenuItemPtr->Data);
 | 
						|
  MenuItemPtr->Data[Length] = SaveChar;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Display and process menu.
 | 
						|
 | 
						|
  @param  Private                                     Pointer to PxeBc interface
 | 
						|
  @param  RxBufferPtr                                 Pointer to receive buffer
 | 
						|
 | 
						|
  @retval NO_MENU
 | 
						|
  @retval LOCAL_BOOT
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
DoMenu (
 | 
						|
  PXE_BASECODE_DEVICE *Private,
 | 
						|
  DHCP_RECEIVE_BUFFER *RxBufferPtr
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_OP_DISCOVERY_CONTROL  *DiscoveryControlPtr;
 | 
						|
  PXE_BOOT_MENU_ENTRY       *MenuItemPtrs[MAX_MENULIST];
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UNION_PTR                 Ptr;
 | 
						|
  UINTN                     SaveNumRte;
 | 
						|
  UINTN                     TopRow;
 | 
						|
  UINTN                     MenuLth;
 | 
						|
  UINTN                     NumMenuItems;
 | 
						|
  UINTN                     Index;
 | 
						|
  UINTN                     Longest;
 | 
						|
  UINTN                     Selected;
 | 
						|
  UINT16                    Type;
 | 
						|
  UINT16                    Layer;
 | 
						|
  BOOLEAN                   Done;
 | 
						|
 | 
						|
  Selected  = 0;
 | 
						|
  Layer     = 0;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_WARN, "\nDoMenu()  Enter."));
 | 
						|
 | 
						|
  /* see if we have a menu/prompt */
 | 
						|
  if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {
 | 
						|
    DEBUG (
 | 
						|
      (DEBUG_WARN,
 | 
						|
      "\nDoMenu()  No menu/prompt info.  OpAdds.Status == %xh  ",
 | 
						|
      RxBufferPtr->OpAdds.Status)
 | 
						|
      );
 | 
						|
 | 
						|
    return NO_MENU;
 | 
						|
  }
 | 
						|
 | 
						|
  DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
 | 
						|
 | 
						|
  //
 | 
						|
  // if not USE_BOOTFILE or no bootfile given, must have menu stuff
 | 
						|
  //
 | 
						|
  if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nDoMenu()  DHCP w/ bootfile.  "));
 | 
						|
    return NO_MENU;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // do prompt & menu if necessary
 | 
						|
  //
 | 
						|
  Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);
 | 
						|
 | 
						|
  if (Status == LOCAL_BOOT) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nDoMenu()  DoPrompt() returned LOCAL_BOOT.  "));
 | 
						|
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Ptr.BytePtr             = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
 | 
						|
 | 
						|
  MenuLth                 = Ptr.MenuPtr->Header.Length;
 | 
						|
  Ptr.CurrentMenuItemPtr  = Ptr.MenuPtr->MenuItem;
 | 
						|
 | 
						|
  //
 | 
						|
  // build menu items array
 | 
						|
  //
 | 
						|
  for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems < MAX_MENULIST;) {
 | 
						|
    UINTN lth;
 | 
						|
 | 
						|
    lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);
 | 
						|
 | 
						|
    MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;
 | 
						|
 | 
						|
    if (lth > Longest) {
 | 
						|
      //
 | 
						|
      // check if too long
 | 
						|
      //
 | 
						|
      if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {
 | 
						|
        Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Index += lth;
 | 
						|
    Ptr.BytePtr += lth;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status != AUTO_SELECT) {
 | 
						|
    UINT8 BlankBuf[75];
 | 
						|
 | 
						|
    SetMem (BlankBuf, sizeof BlankBuf, ' ');
 | 
						|
    BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;
 | 
						|
    AsciiPrint ("\n");
 | 
						|
 | 
						|
    //
 | 
						|
    // now put up menu
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < NumMenuItems; ++Index) {
 | 
						|
      PrintMenuItem (MenuItemPtrs[Index]);
 | 
						|
    }
 | 
						|
 | 
						|
    TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;
 | 
						|
 | 
						|
    //
 | 
						|
    // now wait for a selection
 | 
						|
    //
 | 
						|
    Done = FALSE;
 | 
						|
    do {
 | 
						|
      //
 | 
						|
      // highlight selection
 | 
						|
      //
 | 
						|
      EFI_INPUT_KEY Key;
 | 
						|
      UINTN         NewSelected;
 | 
						|
 | 
						|
      NewSelected = Selected;
 | 
						|
 | 
						|
      //
 | 
						|
      // highlight selected row
 | 
						|
      //
 | 
						|
      gST->ConOut->SetAttribute (
 | 
						|
                    gST->ConOut,
 | 
						|
                    EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)
 | 
						|
                    );
 | 
						|
      gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);
 | 
						|
 | 
						|
      AsciiPrint (" --->%a\r", BlankBuf);
 | 
						|
 | 
						|
      PrintMenuItem (MenuItemPtrs[Selected]);
 | 
						|
      gST->ConOut->SetAttribute (
 | 
						|
                    gST->ConOut,
 | 
						|
                    EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
 | 
						|
                    );
 | 
						|
      gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);
 | 
						|
 | 
						|
      //
 | 
						|
      // wait for a keystroke
 | 
						|
      //
 | 
						|
      while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
 | 
						|
        UINT8 TmpBuf[512];
 | 
						|
        UINTN TmpBufLen;
 | 
						|
 | 
						|
        TmpBufLen = sizeof TmpBuf;
 | 
						|
 | 
						|
        Private->EfiBc.UdpRead (
 | 
						|
                        &Private->EfiBc,
 | 
						|
                        EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
 | 
						|
                        EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
 | 
						|
                        EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
 | 
						|
                        NULL, /* dest ip */
 | 
						|
                        NULL, /* dest port */
 | 
						|
                        NULL, /* src ip */
 | 
						|
                        NULL, /* src port */
 | 
						|
                        NULL, /* hdr size */
 | 
						|
                        NULL, /* hdr ptr */
 | 
						|
                        &TmpBufLen,
 | 
						|
                        TmpBuf
 | 
						|
                        );
 | 
						|
      }
 | 
						|
 | 
						|
      if (!Key.ScanCode) {
 | 
						|
        switch (Key.UnicodeChar) {
 | 
						|
        case Ctl ('c'):
 | 
						|
          Key.ScanCode = SCAN_ESC;
 | 
						|
          break;
 | 
						|
 | 
						|
        case Ctl ('j'): /* linefeed */
 | 
						|
        case Ctl ('m'): /* return */
 | 
						|
          Done = TRUE;
 | 
						|
          break;
 | 
						|
 | 
						|
        case Ctl ('i'): /* tab */
 | 
						|
        case ' ':
 | 
						|
        case 'd':
 | 
						|
        case 'D':
 | 
						|
          Key.ScanCode = SCAN_DOWN;
 | 
						|
          break;
 | 
						|
 | 
						|
        case Ctl ('h'): /* backspace */
 | 
						|
        case 'u':
 | 
						|
        case 'U':
 | 
						|
          Key.ScanCode = SCAN_UP;
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          Key.ScanCode = 0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      switch (Key.ScanCode) {
 | 
						|
      case SCAN_LEFT:
 | 
						|
      case SCAN_UP:
 | 
						|
        if (NewSelected) {
 | 
						|
          --NewSelected;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_DOWN:
 | 
						|
      case SCAN_RIGHT:
 | 
						|
        if (++NewSelected == NumMenuItems) {
 | 
						|
          --NewSelected;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_PAGE_UP:
 | 
						|
      case SCAN_HOME:
 | 
						|
        NewSelected = 0;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_PAGE_DOWN:
 | 
						|
      case SCAN_END:
 | 
						|
        NewSelected = NumMenuItems - 1;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_ESC:
 | 
						|
        return LOCAL_BOOT;
 | 
						|
      }
 | 
						|
 | 
						|
      /* unhighlight last selected row */
 | 
						|
      gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);
 | 
						|
 | 
						|
      AsciiPrint ("%a\r", BlankBuf);
 | 
						|
 | 
						|
      PrintMenuItem (MenuItemPtrs[Selected]);
 | 
						|
 | 
						|
      Selected = NewSelected;
 | 
						|
    } while (!Done);
 | 
						|
  }
 | 
						|
 | 
						|
  SaveNumRte  = Private->EfiBc.Mode->RouteTableEntries;
 | 
						|
 | 
						|
  Type        = NTOHS (MenuItemPtrs[Selected]->Type);
 | 
						|
 | 
						|
  if (Type == 0) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nDoMenu()  Local boot selected.  "));
 | 
						|
    return LOCAL_BOOT;
 | 
						|
  }
 | 
						|
 | 
						|
  AsciiPrint ("Discover");
 | 
						|
 | 
						|
  Status = Private->EfiBc.Discover (
 | 
						|
                            &Private->EfiBc,
 | 
						|
                            Type,
 | 
						|
                            &Layer,
 | 
						|
                            (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),
 | 
						|
                            0
 | 
						|
                            );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    AsciiPrint ("\r                    \r");
 | 
						|
 | 
						|
    DEBUG (
 | 
						|
      (DEBUG_WARN,
 | 
						|
      "\nDoMenu()  Return w/ %xh (%r).",
 | 
						|
      Status,
 | 
						|
      Status)
 | 
						|
      );
 | 
						|
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  AsciiPrint ("\rBOOT_SERVER_IP: ");
 | 
						|
  PrintIpv4 ((UINT8 *) &Private->ServerIp);
 | 
						|
 | 
						|
  for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {
 | 
						|
    if ((Index % 3) == 0) {
 | 
						|
      AsciiPrint ("\r\nGATEWAY IP:");
 | 
						|
    }
 | 
						|
 | 
						|
    AsciiPrint (" ");
 | 
						|
    PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);
 | 
						|
    AsciiPrint (" ");
 | 
						|
  }
 | 
						|
 | 
						|
  AsciiPrint ("\n");
 | 
						|
 | 
						|
  DEBUG ((DEBUG_WARN, "\nDoMenu()  Return w/ EFI_SUCCESS.  "));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get value 8- or 16-bit value from DHCP option.
 | 
						|
 | 
						|
  @param  OpPtr                                       Pointer to DHCP option
 | 
						|
 | 
						|
  @return Value from DHCP option
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
UINT16
 | 
						|
GetValue (
 | 
						|
  DHCPV4_OP_STRUCT *OpPtr
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (OpPtr->Header.Length == 1) {
 | 
						|
    return OpPtr->Data[0];
 | 
						|
  } else {
 | 
						|
    return NTOHS (OpPtr->Data);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Locate opcode in buffer.
 | 
						|
 | 
						|
  @param  BufferPtr                                   Pointer to buffer
 | 
						|
  @param  BufferLen                                   Length of buffer
 | 
						|
  @param  OpCode                                      Option number
 | 
						|
 | 
						|
  @return Pointer to opcode, may be NULL
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
UINT8 *
 | 
						|
_PxeBcFindOpt (
 | 
						|
  UINT8 *BufferPtr,
 | 
						|
  UINTN BufferLen,
 | 
						|
  UINT8 OpCode
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (BufferPtr == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  while (BufferLen != 0) {
 | 
						|
    if (*BufferPtr == OpCode) {
 | 
						|
      return BufferPtr;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (*BufferPtr) {
 | 
						|
    case OP_END:
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    case OP_PAD:
 | 
						|
      ++BufferPtr;
 | 
						|
      --BufferLen;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    BufferLen -= 2 + BufferPtr[1];
 | 
						|
    BufferPtr += 2 + BufferPtr[1];
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Find option in packet
 | 
						|
 | 
						|
  @param  PacketPtr                                   Pointer to packet
 | 
						|
  @param  OpCode                                      option number
 | 
						|
 | 
						|
  @return Pointer to option in packet
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
UINT8 *
 | 
						|
PxeBcFindDhcpOpt (
 | 
						|
  EFI_PXE_BASE_CODE_PACKET  *PacketPtr,
 | 
						|
  UINT8                     OpCode
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN PacketLen;
 | 
						|
  UINT8 Overload;
 | 
						|
  UINT8 *OptionBufferPtr;
 | 
						|
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //
 | 
						|
  PacketLen = 380;
 | 
						|
  Overload  = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Figure size of DHCP option space.
 | 
						|
  //
 | 
						|
  OptionBufferPtr = _PxeBcFindOpt (
 | 
						|
                      PacketPtr->Dhcpv4.DhcpOptions,
 | 
						|
                      380,
 | 
						|
                      OP_DHCP_MAX_MESSAGE_SZ
 | 
						|
                      );
 | 
						|
 | 
						|
  if (OptionBufferPtr != NULL) {
 | 
						|
    if (OptionBufferPtr[1] == 2) {
 | 
						|
      UINT16  n;
 | 
						|
 | 
						|
      CopyMem (&n, &OptionBufferPtr[2], 2);
 | 
						|
      PacketLen = HTONS (n);
 | 
						|
 | 
						|
      if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {
 | 
						|
        PacketLen = 380;
 | 
						|
      } else {
 | 
						|
        PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Look for option overloading.
 | 
						|
  //
 | 
						|
  OptionBufferPtr = _PxeBcFindOpt (
 | 
						|
                      PacketPtr->Dhcpv4.DhcpOptions,
 | 
						|
                      PacketLen,
 | 
						|
                      OP_DHCP_OPTION_OVERLOAD
 | 
						|
                      );
 | 
						|
 | 
						|
  if (OptionBufferPtr != NULL) {
 | 
						|
    if (OptionBufferPtr[1] == 1) {
 | 
						|
      Overload = OptionBufferPtr[2];
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Look for caller's option.
 | 
						|
  //
 | 
						|
  OptionBufferPtr = _PxeBcFindOpt (
 | 
						|
                      PacketPtr->Dhcpv4.DhcpOptions,
 | 
						|
                      PacketLen,
 | 
						|
                      OpCode
 | 
						|
                      );
 | 
						|
 | 
						|
  if (OptionBufferPtr != NULL) {
 | 
						|
    return OptionBufferPtr;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Overload & OVLD_FILE) {
 | 
						|
    OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);
 | 
						|
 | 
						|
    if (OptionBufferPtr != NULL) {
 | 
						|
      return OptionBufferPtr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Overload & OVLD_SRVR_NAME) {
 | 
						|
    OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);
 | 
						|
 | 
						|
    if (OptionBufferPtr != NULL) {
 | 
						|
      return OptionBufferPtr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Download file into buffer
 | 
						|
 | 
						|
  @param  Private                                     Pointer to PxeBc interface
 | 
						|
  @param  BufferSize                                  pointer to size of download
 | 
						|
                                                      buffer
 | 
						|
  @param  Buffer                                      Pointer to buffer
 | 
						|
 | 
						|
  @return EFI_BUFFER_TOO_SMALL -
 | 
						|
  @return EFI_NOT_FOUND -
 | 
						|
  @return EFI_PROTOCOL_ERROR -
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
DownloadFile (
 | 
						|
  IN PXE_BASECODE_DEVICE  *Private,
 | 
						|
  IN OUT UINT64           *BufferSize,
 | 
						|
  IN VOID                 *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PXE_BASE_CODE_MTFTP_INFO  MtftpInfo;
 | 
						|
  EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;
 | 
						|
  DHCP_RECEIVE_BUFFER           *RxBuf;
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINTN                         BlockSize;
 | 
						|
 | 
						|
  RxBuf     = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;
 | 
						|
  BlockSize = 0x8000;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_WARN, "\nDownloadFile()  Enter."));
 | 
						|
 | 
						|
  if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {
 | 
						|
    if (Private->FileSize != 0) {
 | 
						|
      *BufferSize = Private->FileSize;
 | 
						|
      return EFI_BUFFER_TOO_SMALL;
 | 
						|
    }
 | 
						|
 | 
						|
    AsciiPrint ("\nTSize");
 | 
						|
 | 
						|
    OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
 | 
						|
  } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {
 | 
						|
    OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;
 | 
						|
 | 
						|
    ZeroMem (&MtftpInfo, sizeof MtftpInfo);
 | 
						|
 | 
						|
    *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;
 | 
						|
 | 
						|
    CopyMem (
 | 
						|
      &MtftpInfo.CPort,
 | 
						|
      RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,
 | 
						|
      sizeof MtftpInfo.CPort
 | 
						|
      );
 | 
						|
 | 
						|
    CopyMem (
 | 
						|
      &MtftpInfo.SPort,
 | 
						|
      RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,
 | 
						|
      sizeof MtftpInfo.SPort
 | 
						|
      );
 | 
						|
 | 
						|
    MtftpInfo.ListenTimeout   = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);
 | 
						|
 | 
						|
    MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);
 | 
						|
 | 
						|
    AsciiPrint ("\nMTFTP");
 | 
						|
  } else {
 | 
						|
    AsciiPrint ("\nTFTP");
 | 
						|
 | 
						|
    OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
 | 
						|
  }
 | 
						|
 | 
						|
  Private->FileSize = 0;
 | 
						|
 | 
						|
  RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;
 | 
						|
 | 
						|
  Status = Private->EfiBc.Mtftp (
 | 
						|
                            &Private->EfiBc,
 | 
						|
                            OpCode,
 | 
						|
                            Buffer,
 | 
						|
                            FALSE,
 | 
						|
                            BufferSize,
 | 
						|
                            &BlockSize,
 | 
						|
                            &Private->ServerIp,
 | 
						|
                            (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,
 | 
						|
                            &MtftpInfo,
 | 
						|
                            FALSE
 | 
						|
                            );
 | 
						|
 | 
						|
  if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nDownloadFile()  Exit #1 %Xh", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {
 | 
						|
    Private->FileSize = 0xFFFFFFFF;
 | 
						|
  } else {
 | 
						|
    Private->FileSize = (UINTN) *BufferSize;
 | 
						|
  }
 | 
						|
 | 
						|
  if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nDownloadFile()  Exit #2"));
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nDownloadFile()  Exit #3 %Xh", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {
 | 
						|
    UINT64  CredentialLen;
 | 
						|
    UINT8   CredentialFilename[256];
 | 
						|
    UINT8   *op;
 | 
						|
    VOID    *CredentialBuffer;
 | 
						|
 | 
						|
    //
 | 
						|
    // Get name of credential file.  It may be in the BOOTP
 | 
						|
    // bootfile field or a DHCP option.
 | 
						|
    //
 | 
						|
    ZeroMem (CredentialFilename, sizeof CredentialFilename);
 | 
						|
 | 
						|
    op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);
 | 
						|
 | 
						|
    if (op != NULL) {
 | 
						|
      if (op[1] == 0) {
 | 
						|
        /* No credential filename */
 | 
						|
        return EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (CredentialFilename, &op[2], op[1]);
 | 
						|
    } else {
 | 
						|
      if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {
 | 
						|
        /* No credential filename */
 | 
						|
        return EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (CredentialFilename, &op[2], 128);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Get size of credential file.  It may be available as a
 | 
						|
    // DHCP option.  If not, use the TFTP get file size.
 | 
						|
    //
 | 
						|
    CredentialLen = 0;
 | 
						|
 | 
						|
    op            = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);
 | 
						|
 | 
						|
    if (op != NULL) {
 | 
						|
      /*
 | 
						|
       * This is actually the size of the credential file
 | 
						|
       * buffer.  The actual credential file size will be
 | 
						|
       * returned when we download the file.
 | 
						|
       */
 | 
						|
      if (op[1] == 2) {
 | 
						|
        UINT16  n;
 | 
						|
 | 
						|
        CopyMem (&n, &op[2], 2);
 | 
						|
        CredentialLen = HTONS (n) * 512;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (CredentialLen == 0) {
 | 
						|
      BlockSize = 8192;
 | 
						|
 | 
						|
      Status = Private->EfiBc.Mtftp (
 | 
						|
                                &Private->EfiBc,
 | 
						|
                                EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
 | 
						|
                                NULL,
 | 
						|
                                FALSE,
 | 
						|
                                &CredentialLen,
 | 
						|
                                &BlockSize,
 | 
						|
                                &Private->ServerIp,
 | 
						|
                                CredentialFilename,
 | 
						|
                                NULL,
 | 
						|
                                FALSE
 | 
						|
                                );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      if (CredentialLen == 0) {
 | 
						|
        //
 | 
						|
        // %%TBD -- EFI error for invalid credential
 | 
						|
        // file.
 | 
						|
        //
 | 
						|
        return EFI_PROTOCOL_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Allocate credential file buffer.
 | 
						|
    //
 | 
						|
    Status = gBS->AllocatePool (
 | 
						|
                    EfiBootServicesData,
 | 
						|
                    (UINTN) CredentialLen,
 | 
						|
                    &CredentialBuffer
 | 
						|
                    );
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Download credential file.
 | 
						|
    //
 | 
						|
    BlockSize = 8192;
 | 
						|
 | 
						|
    Status = Private->EfiBc.Mtftp (
 | 
						|
                              &Private->EfiBc,
 | 
						|
                              EFI_PXE_BASE_CODE_TFTP_READ_FILE,
 | 
						|
                              CredentialBuffer,
 | 
						|
                              FALSE,
 | 
						|
                              &CredentialLen,
 | 
						|
                              &BlockSize,
 | 
						|
                              &Private->ServerIp,
 | 
						|
                              CredentialFilename,
 | 
						|
                              NULL,
 | 
						|
                              FALSE
 | 
						|
                              );
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      gBS->FreePool (CredentialBuffer);
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Verify credentials.
 | 
						|
    //
 | 
						|
    if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // %%TBD -- An EFI error code for failing credential verification.
 | 
						|
      //
 | 
						|
      Status = EFI_PROTOCOL_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->FreePool (CredentialBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Start PXE DHCP.  Get DHCP and proxyDHCP information.
 | 
						|
  Display remote boot menu and prompt.  Select item from menu.
 | 
						|
 | 
						|
  @param  Private                                     Pointer to PxeBc interface
 | 
						|
  @param  BufferSize                                  Pointer to download buffer
 | 
						|
                                                      size
 | 
						|
  @param  Buffer                                      Pointer to download buffer
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  @retval EFI_NOT_READY
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
LoadfileStart (
 | 
						|
  IN PXE_BASECODE_DEVICE  *Private,
 | 
						|
  IN OUT UINT64           *BufferSize,
 | 
						|
  IN VOID                 *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PXE_BASE_CODE_MODE      *PxeBcMode;
 | 
						|
  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
 | 
						|
  EFI_SIMPLE_NETWORK_MODE     *SnpMode;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  VOID                        *RxBuf;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_WARN, "\nLoadfileStart()  Enter."));
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to start BaseCode, for now only IPv4 is supported
 | 
						|
  // so don't try to start using IPv6.
 | 
						|
  //
 | 
						|
  Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    if (Status != EFI_ALREADY_STARTED) {
 | 
						|
      DEBUG ((DEBUG_NET, "\nLoadfileStart()  Exit  BC.Start() == %xh", Status));
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get pointers to PXE mode structure, SNP protocol structure
 | 
						|
  // and SNP mode structure.
 | 
						|
  //
 | 
						|
  PxeBcMode = Private->EfiBc.Mode;
 | 
						|
  Snp       = Private->SimpleNetwork;
 | 
						|
  SnpMode   = Snp->Mode;
 | 
						|
 | 
						|
  //
 | 
						|
  // Display client MAC address, like 16-bit PXE ROMs
 | 
						|
  //
 | 
						|
  AsciiPrint ("\nCLIENT MAC ADDR: ");
 | 
						|
 | 
						|
  {
 | 
						|
    UINTN Index;
 | 
						|
    UINTN hlen;
 | 
						|
 | 
						|
    hlen = SnpMode->HwAddressSize;
 | 
						|
 | 
						|
    for (Index = 0; Index < hlen; ++Index) {
 | 
						|
      AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  AsciiPrint ("\nDHCP");
 | 
						|
 | 
						|
  Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadfileStart()  Exit  BC.Dhcp() == %Xh", Status));
 | 
						|
    AsciiPrint ("\r               \r");
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  ShowMyInfo (Private);
 | 
						|
 | 
						|
  RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
 | 
						|
#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)
 | 
						|
 | 
						|
  Status = DoMenu (Private, RxBufferPtr);
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    //
 | 
						|
    // did a discovery - take info from discovery packet
 | 
						|
    //
 | 
						|
    RxBuf = &PXE_ACK_BUFFER;
 | 
						|
  } else if (Status == NO_MENU) {
 | 
						|
    //
 | 
						|
    // did not do a discovery - take info from rxbuf
 | 
						|
    //
 | 
						|
    Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;
 | 
						|
 | 
						|
    if (!(Private->ServerIp.Addr[0])) {
 | 
						|
      *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadfileStart()  Exit  DoMenu() == %Xh", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadfileStart()  Exit  Not ready?"));
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // check for file size option sent
 | 
						|
  //
 | 
						|
  if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {
 | 
						|
    Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);
 | 
						|
  }
 | 
						|
 | 
						|
  Private->BootServerReceiveBuffer  = RxBufferPtr;
 | 
						|
 | 
						|
  Status = DownloadFile (Private, BufferSize, Buffer);
 | 
						|
 | 
						|
  DEBUG (
 | 
						|
    (DEBUG_WARN,
 | 
						|
    "\nLoadfileStart()  Exit.  DownloadFile() = %Xh",
 | 
						|
    Status)
 | 
						|
    );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Loadfile interface for PxeBc interface
 | 
						|
 | 
						|
  @param  This                                        Pointer to Loadfile interface
 | 
						|
  @param  FilePath                                    Not used and not checked
 | 
						|
  @param  BootPolicy                                  Must be TRUE
 | 
						|
  @param  BufferSize                                  Pointer to buffer size
 | 
						|
  @param  Buffer                                      Pointer to download buffer or
 | 
						|
                                                      NULL
 | 
						|
 | 
						|
  @return EFI_INVALID_PARAMETER -
 | 
						|
  @return EFI_UNSUPPORTED -
 | 
						|
  @return EFI_SUCCESS -
 | 
						|
  @return EFI_BUFFER_TOO_SMALL -
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
LoadFile (
 | 
						|
  IN EFI_LOAD_FILE_PROTOCOL           *This,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL         *FilePath,
 | 
						|
  IN BOOLEAN                          BootPolicy,
 | 
						|
  IN OUT UINTN                        *BufferSize,
 | 
						|
  IN OUT VOID                         *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  LOADFILE_DEVICE *LoadfilePtr;
 | 
						|
  UINT64          TmpBufSz;
 | 
						|
  INT32           OrigMode;
 | 
						|
  INT32           OrigAttribute;
 | 
						|
  BOOLEAN         RemoveCallback;
 | 
						|
  BOOLEAN         NewMakeCallback;
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  EFI_STATUS      TempStatus;
 | 
						|
 | 
						|
  //
 | 
						|
  // The following line is only used for passing ICC build.
 | 
						|
  //
 | 
						|
  DEBUG ((EFI_D_INFO, "FilePath = %x\n", FilePath));
 | 
						|
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //
 | 
						|
  OrigMode        = gST->ConOut->Mode->Mode;
 | 
						|
  OrigAttribute   = gST->ConOut->Mode->Attribute;
 | 
						|
  RemoveCallback  = FALSE;
 | 
						|
 | 
						|
  AsciiPrint ("Running LoadFile()\n");
 | 
						|
 | 
						|
  //
 | 
						|
  // Resolve Warning 4 unreferenced parameter problem
 | 
						|
  //
 | 
						|
  FilePath = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // If either if these parameters are NULL, we cannot continue.
 | 
						|
  //
 | 
						|
  if (This == NULL || BufferSize == NULL) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadFile()  This or BufferSize == NULL"));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // We only support BootPolicy == TRUE
 | 
						|
  //
 | 
						|
  if (!BootPolicy) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadFile()  BootPolicy == FALSE"));
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get pointer to LoadFile protocol structure.
 | 
						|
  //
 | 
						|
  LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);
 | 
						|
 | 
						|
  if (LoadfilePtr == NULL) {
 | 
						|
    DEBUG (
 | 
						|
      (DEBUG_NET,
 | 
						|
      "\nLoadFile()  Could not get pointer to LoadFile structure")
 | 
						|
      );
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Lock interface
 | 
						|
  //
 | 
						|
  EfiAcquireLock (&LoadfilePtr->Lock);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set console output mode and display attribute
 | 
						|
  //
 | 
						|
  if (OrigMode != 0) {
 | 
						|
    gST->ConOut->SetMode (gST->ConOut, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  gST->ConOut->SetAttribute (
 | 
						|
                gST->ConOut,
 | 
						|
                EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)
 | 
						|
                );
 | 
						|
 | 
						|
  //
 | 
						|
  // See if BaseCode already has a Callback protocol attached.
 | 
						|
  // If there is none, attach our own Callback protocol.
 | 
						|
  //
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  LoadfilePtr->Private->Handle,
 | 
						|
                  &gEfiPxeBaseCodeCallbackProtocolGuid,
 | 
						|
                  (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr
 | 
						|
                  );
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    //
 | 
						|
    // There is already a callback routine.  Do nothing.
 | 
						|
    //
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadFile()  BC callback exists."));
 | 
						|
 | 
						|
  } else if (Status == EFI_UNSUPPORTED) {
 | 
						|
    //
 | 
						|
    // No BaseCode Callback protocol found.  Add our own.
 | 
						|
    //
 | 
						|
    Status = gBS->InstallProtocolInterface (
 | 
						|
                    &LoadfilePtr->Private->Handle,
 | 
						|
                    &gEfiPxeBaseCodeCallbackProtocolGuid,
 | 
						|
                    EFI_NATIVE_INTERFACE,
 | 
						|
                    &_bc_callback
 | 
						|
                    );
 | 
						|
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadFile()  Callback install status == %xh", Status));
 | 
						|
 | 
						|
    RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);
 | 
						|
 | 
						|
    if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {
 | 
						|
      NewMakeCallback = TRUE;
 | 
						|
      LoadfilePtr->Private->EfiBc.SetParameters (
 | 
						|
                                    &LoadfilePtr->Private->EfiBc,
 | 
						|
                                    NULL,
 | 
						|
                                    NULL,
 | 
						|
                                    NULL,
 | 
						|
                                    NULL,
 | 
						|
                                    &NewMakeCallback
 | 
						|
                                    );
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadFile()  Callback check status == %xh", Status));
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Check for starting or for continuing after already getting
 | 
						|
  // the file size.
 | 
						|
  //
 | 
						|
  if (LoadfilePtr->Private->FileSize == 0) {
 | 
						|
    TmpBufSz  = 0;
 | 
						|
    Status    = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);
 | 
						|
 | 
						|
    if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {
 | 
						|
      *BufferSize = 0xFFFFFFFF;
 | 
						|
    } else {
 | 
						|
      *BufferSize = (UINTN) TmpBufSz;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      //
 | 
						|
      // This is done so loadfile will work even if the boot manager
 | 
						|
      // did not make the first call with Buffer == NULL.
 | 
						|
      //
 | 
						|
      Buffer = NULL;
 | 
						|
    }
 | 
						|
  } else if (Buffer == NULL) {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadfile()  Get buffer size"));
 | 
						|
 | 
						|
    //
 | 
						|
    // Continuing from previous LoadFile request.  Make sure there
 | 
						|
    // is a buffer and that it is big enough.
 | 
						|
    //
 | 
						|
    *BufferSize = LoadfilePtr->Private->FileSize;
 | 
						|
    Status      = EFI_BUFFER_TOO_SMALL;
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_WARN, "\nLoadFile()  Download file"));
 | 
						|
 | 
						|
    //
 | 
						|
    // Everything looks good, try to download the file.
 | 
						|
    //
 | 
						|
    TmpBufSz  = *BufferSize;
 | 
						|
    Status    = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);
 | 
						|
 | 
						|
    //
 | 
						|
    // Next call to loadfile will start DHCP process again.
 | 
						|
    //
 | 
						|
    LoadfilePtr->Private->FileSize = 0;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If we added a callback protocol, now is the time to remove it.
 | 
						|
  //
 | 
						|
  if (RemoveCallback) {
 | 
						|
    NewMakeCallback = FALSE;
 | 
						|
    TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (
 | 
						|
                                          &LoadfilePtr->Private->EfiBc,
 | 
						|
                                          NULL,
 | 
						|
                                          NULL,
 | 
						|
                                          NULL,
 | 
						|
                                          NULL,
 | 
						|
                                          &NewMakeCallback
 | 
						|
                                          );
 | 
						|
 | 
						|
    if (TempStatus == EFI_SUCCESS) {
 | 
						|
      gBS->UninstallProtocolInterface (
 | 
						|
            LoadfilePtr->Private->Handle,
 | 
						|
            &gEfiPxeBaseCodeCallbackProtocolGuid,
 | 
						|
            &_bc_callback
 | 
						|
            );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Restore display mode and attribute
 | 
						|
  //
 | 
						|
  if (OrigMode != 0) {
 | 
						|
    gST->ConOut->SetMode (gST->ConOut, OrigMode);
 | 
						|
  }
 | 
						|
 | 
						|
  gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);
 | 
						|
 | 
						|
  //
 | 
						|
  // Unlock interface
 | 
						|
  //
 | 
						|
  EfiReleaseLock (&LoadfilePtr->Lock);
 | 
						|
 | 
						|
  DEBUG ((DEBUG_WARN, "\nBC.Loadfile()  Status == %xh\n", Status));
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
 | 
						|
  } else if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
    //
 | 
						|
    // Error is only displayed when we are actually trying to
 | 
						|
    // download the boot image.
 | 
						|
    //
 | 
						|
    if (Buffer == NULL) {
 | 
						|
      return EFI_BUFFER_TOO_SMALL;
 | 
						|
    }
 | 
						|
 | 
						|
    AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_DEVICE_ERROR) {
 | 
						|
    AsciiPrint ("\nPXE-E07: Network device error.  Check network connection.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_OUT_OF_RESOURCES) {
 | 
						|
    AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_NO_MEDIA) {
 | 
						|
    AsciiPrint ("\nPXE-E12: Could not detect network connection.  Check cable.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_NO_RESPONSE) {
 | 
						|
    AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_TIMEOUT) {
 | 
						|
    AsciiPrint ("\nPXE-E18: Timeout.  Server did not respond.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_ABORTED) {
 | 
						|
    AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");
 | 
						|
 | 
						|
  } else if (Status == EFI_ICMP_ERROR) {
 | 
						|
    AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");
 | 
						|
 | 
						|
    if (LoadfilePtr->Private->EfiBc.Mode != NULL) {
 | 
						|
      if (LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {
 | 
						|
 | 
						|
      AsciiPrint (
 | 
						|
          "PXE-E98: Type: %xh  Code: %xh  ",
 | 
						|
          LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,
 | 
						|
          LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code
 | 
						|
          );
 | 
						|
 | 
						|
        switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {
 | 
						|
        case 0x03:
 | 
						|
          switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {
 | 
						|
          case 0x00:              /* net unreachable */
 | 
						|
          AsciiPrint ("Net unreachable");
 | 
						|
            break;
 | 
						|
 | 
						|
          case 0x01:              /* host unreachable */
 | 
						|
          AsciiPrint ("Host unreachable");
 | 
						|
            break;
 | 
						|
 | 
						|
          case 0x02:              /* protocol unreachable */
 | 
						|
          AsciiPrint ("Protocol unreachable");
 | 
						|
            break;
 | 
						|
 | 
						|
          case 0x03:              /* port unreachable */
 | 
						|
          AsciiPrint ("Port unreachable");
 | 
						|
            break;
 | 
						|
 | 
						|
          case 0x04:              /* Fragmentation needed */
 | 
						|
          AsciiPrint ("Fragmentation needed");
 | 
						|
            break;
 | 
						|
 | 
						|
          case 0x05:              /* Source route failed */
 | 
						|
          AsciiPrint ("Source route failed");
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
      AsciiPrint ("\n");
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  } else if (Status == EFI_TFTP_ERROR) {
 | 
						|
    AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");
 | 
						|
 | 
						|
    if (LoadfilePtr->Private->EfiBc.Mode != NULL) {
 | 
						|
      if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) {
 | 
						|
      AsciiPrint (
 | 
						|
          "PXE-E98: Code: %xh  %a\n",
 | 
						|
          LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,
 | 
						|
          LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString
 | 
						|
          );
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);
 | 
						|
  }
 | 
						|
 | 
						|
  LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |