mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-31 11:13:53 +01:00 
			
		
		
		
	MdePkg/Include/Protocol/TcgService.h: MdePkg/Include/IndustryStandard/Tpm12.h: * Remove usage of '#pragma push' unsupported usage which is not supported by GCC. MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_dhcp.c: * Fix a warning encountered with GCC/IPF when Index2 (as a INT8) is used as an index to an array on lines 2020 & 2028. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5905 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			3282 lines
		
	
	
		
			96 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3282 lines
		
	
	
		
			96 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_bc_dhcp.c
 | |
| 
 | |
| Abstract:
 | |
|   DHCP and PXE discovery protocol implementations.
 | |
| 
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Bc.h"
 | |
| 
 | |
| #include "PxeArch.h"
 | |
| 
 | |
| STATIC EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort        = DHCP_SERVER_PORT;
 | |
| STATIC EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort        = DHCP_CLIENT_PORT;
 | |
| STATIC EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort  = PXE_DISCOVERY_PORT;
 | |
| #define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort
 | |
| STATIC EFI_IP_ADDRESS             BroadcastIP       = {{0xffffffff}};
 | |
| STATIC EFI_IP_ADDRESS             DefaultSubnetMask = {{0xffffff00}};
 | |
| 
 | |
| typedef union {
 | |
|   DHCPV4_OP_STRUCT          *OpPtr;
 | |
|   PXE_OP_SERVER_LIST        *BootServersStr;
 | |
|   PXE_SERVER_LIST           *BootServerList;
 | |
|   PXE_BOOT_MENU_ENTRY       *BootMenuItem;
 | |
|   PXE_OP_DISCOVERY_CONTROL  *DiscoveryControl;
 | |
|   PXE_OP_BOOT_MENU          *BootMenu;
 | |
|   PXE_OP_BOOT_ITEM          *BootItem;
 | |
|   DHCPV4_OP_VENDOR_OPTIONS  *VendorOptions;
 | |
|   DHCPV4_OP_OVERLOAD        *Overload;
 | |
|   DHCPV4_OP_CLASS           *PxeClassStr;
 | |
|   DHCPV4_OP_SUBNET_MASK     *SubnetMaskStr;
 | |
|   DHCPV4_OP_MESSAGE_TYPE    *MessageType;
 | |
|   UINT8                     *BytePtr;
 | |
| } UNION_PTR;
 | |
| 
 | |
| #pragma pack(1)
 | |
| //
 | |
| // option structure for DHCPREQUEST at end of DISCOVER options
 | |
| // and for DHCPDECLINE
 | |
| //
 | |
| STATIC const struct requestopendstr {
 | |
|   DHCPV4_OP_REQUESTED_IP  OpReqIP;
 | |
|   DHCPV4_OP_SERVER_IP     DhcServerIpPtr;
 | |
|   UINT8                   End[1];
 | |
| }
 | |
| RequestOpEndStr = {
 | |
|   {
 | |
|     {
 | |
|       OP_DHCP_REQ_IP_ADD,
 | |
|       DHCPV4_OPTION_LENGTH(DHCPV4_OP_REQUESTED_IP)
 | |
|     }
 | |
|   },
 | |
|   {
 | |
|     {
 | |
|       OP_DHCP_SERVER_IP,
 | |
|       DHCPV4_OPTION_LENGTH(DHCPV4_OP_SERVER_IP)
 | |
|     }
 | |
|   },
 | |
|   {
 | |
|     OP_END
 | |
|   }
 | |
| };
 | |
| 
 | |
| #define DHCP_REQ_OPTIONS  (*(struct requestopendstr *) DHCPV4_OPTIONS_BUFFER.End)
 | |
| 
 | |
| PXE_OP_BOOT_ITEM                DefaultBootItem = {
 | |
|   {
 | |
|     VEND_PXE_BOOT_ITEM,
 | |
|     DHCPV4_OPTION_LENGTH(PXE_OP_BOOT_ITEM)
 | |
|   },
 | |
|   0,
 | |
|   0
 | |
| };
 | |
| 
 | |
| //
 | |
| // PXE discovery control default structure
 | |
| //
 | |
| STATIC PXE_OP_DISCOVERY_CONTROL DefaultDisCtl = {
 | |
|   { VEND_PXE_DISCOVERY_CONTROL, DHCPV4_OPTION_LENGTH(PXE_OP_DISCOVERY_CONTROL) },
 | |
|   0
 | |
| };
 | |
| 
 | |
| //
 | |
| // PXE credentials option structure
 | |
| //
 | |
| typedef struct {
 | |
|   UINT8 c[4];
 | |
| } PXE_CREDENTIAL;
 | |
| 
 | |
| typedef struct {
 | |
|   DHCPV4_OP_HEADER  Header;
 | |
|   PXE_CREDENTIAL    Credentials[1];
 | |
| } PXE_OP_CREDENTIAL_TYPES;
 | |
| 
 | |
| //
 | |
| // option structure for PXE discover (without credentials)
 | |
| //
 | |
| typedef struct {            // discoveropendstr {
 | |
|   DHCPV4_OP_HEADER  Header; // vendor options
 | |
|   PXE_OP_BOOT_ITEM  BootItem;
 | |
|   UINT8             End[1]; // if credentials option, it starts here
 | |
| } PXE_DISCOVER_OPTIONS;
 | |
| 
 | |
| #define DISCOVERoptions (*(PXE_DISCOVER_OPTIONS *) DHCPV4_OPTIONS_BUFFER.End)
 | |
| #define DISCREDoptions  (*(PXE_OP_CREDENTIAL_TYPES *) DISCOVERoptions.End)
 | |
| 
 | |
| //
 | |
| // common option beginning for all our DHCP messages except
 | |
| // DHCPDECLINE and DHCPRELEASE
 | |
| //
 | |
| STATIC struct optionsstr {
 | |
|   UINT8                       DhcpCookie[4];
 | |
|   DHCPV4_OP_MESSAGE_TYPE      DhcpMessageType;
 | |
|   DHCPV4_OP_MAX_MESSAGE_SIZE  DhcpMaxMessageSize;
 | |
|   DHCPV4_OP_REQUESTED_OPTIONS DhcpRequestedOptions;
 | |
|   DHCPV4_OP_PLATFORM_ID       DhcpPlatformId;
 | |
|   DHCPV4_OP_NETWORK_INTERFACE DhcpNetworkInterface;
 | |
|   DHCPV4_OP_ARCHITECTURE_TYPE DhcpClientArchitecture;
 | |
|   DHCPV4_OP_CLASS_ID          DhcpClassIdentifier;
 | |
|   UINT8                       End[1];
 | |
| } DHCPOpStart;
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| VOID
 | |
| OptionsStrucInit (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   DHCPOpStart.DhcpCookie[0] = 99;
 | |
|   DHCPOpStart.DhcpCookie[1] = 130;
 | |
|   DHCPOpStart.DhcpCookie[2] = 83;
 | |
|   DHCPOpStart.DhcpCookie[3] = 99;
 | |
|   DHCPOpStart.DhcpMessageType.Header.OpCode = OP_DHCP_MESSAGE_TYPE;
 | |
|   DHCPOpStart.DhcpMessageType.Header.Length = 1;
 | |
|   DHCPOpStart.DhcpMessageType.Type = DHCPDISCOVER;
 | |
|   DHCPOpStart.DhcpMaxMessageSize.Header.OpCode = OP_DHCP_MAX_MESSAGE_SZ;
 | |
|   DHCPOpStart.DhcpMaxMessageSize.Header.Length = 2;
 | |
|   DHCPOpStart.DhcpMaxMessageSize.MaxSize[0] = MAX_DHCP_MSG_SZ >> 8;
 | |
|   DHCPOpStart.DhcpMaxMessageSize.MaxSize[1] = MAX_DHCP_MSG_SZ & 0xff;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Header.OpCode = OP_DHCP_PARM_REQ_LIST;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Header.Length = sizeof (DHCPV4_REQUESTED_OPTIONS_DATA);
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_SUBNET_MASK = OP_SUBNET_MASK;                     /* 1 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_OFFSET = OP_TIME_OFFSET;                     /* 2 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_ROUTER_LIST = OP_ROUTER_LIST;                     /* 3 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_SERVERS = OP_TIME_SERVERS;                   /* 4 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_NAME_SERVERS = OP_NAME_SERVERS;                   /* 5 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DNS_SERVERS = OP_DNS_SERVERS;                     /* 6 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_HOST_NAME = OP_HOST_NAME;                         /* 12 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_BOOT_FILE_SZ = OP_BOOT_FILE_SZ;                   /* 13 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DOMAIN_NAME = OP_DOMAIN_NAME;                     /* 15 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_ROOT_PATH = OP_ROOT_PATH;                         /* 17 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_EXTENSION_PATH = OP_EXTENSION_PATH;               /* 18 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_MAX_DATAGRAM_SZ = OP_MAX_DATAGRAM_SZ;             /* 22 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DEFAULT_TTL = OP_DEFAULT_TTL;                     /* 23 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_BROADCAST_ADD = OP_BROADCAST_ADD;                 /* 28 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_DOMAIN_NAME = OP_NIS_DOMAIN_NAME;             /* 40 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_SERVERS = OP_NIS_SERVERS;                     /* 41 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_NTP_SERVERS = OP_NTP_SERVERS;                     /* 42 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_VENDOR_SPECIFIC = OP_VENDOR_SPECIFIC;             /* 43 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REQ_IP_ADD = OP_DHCP_REQ_IP_ADD;             /* 50 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_LEASE_TIME = OP_DHCP_LEASE_TIME;             /* 51 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_SERVER_IP = OP_DHCP_SERVER_IP;               /* 54 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_RENEWAL_TIME = OP_DHCP_RENEWAL_TIME;         /* 58 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REBINDING_TIME = OP_DHCP_REBINDING_TIME;     /* 59 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_CLASS_IDENTIFIER = OP_DHCP_CLASS_IDENTIFIER; /* 60 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_TFTP_SERVER_NAME = OP_DHCP_TFTP_SERVER_NAME; /* 66 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_BOOTFILE = OP_DHCP_BOOTFILE;                 /* 67 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_PLATFORM_ID = OP_DHCP_PLATFORM_ID;           /* 97 */
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption128 = 128;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption129 = 129;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption130 = 130;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption131 = 131;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption132 = 132;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption133 = 133, DHCPOpStart.DhcpRequestedOptions.Data.VendorOption134 = 134;
 | |
|   DHCPOpStart.DhcpRequestedOptions.Data.VendorOption135 = 135;
 | |
|   DHCPOpStart.DhcpPlatformId.Header.OpCode              = OP_DHCP_PLATFORM_ID;
 | |
|   DHCPOpStart.DhcpPlatformId.Header.Length              = DHCPV4_OPTION_LENGTH (DHCPV4_OP_PLATFORM_ID);
 | |
|   DHCPOpStart.DhcpNetworkInterface.Header.OpCode        = OP_DHCP_NETWORK_ARCH;
 | |
|   DHCPOpStart.DhcpNetworkInterface.Header.Length        = DHCPV4_OPTION_LENGTH (DHCPV4_OP_NETWORK_INTERFACE);
 | |
|   DHCPOpStart.DhcpNetworkInterface.Type                 = 0;
 | |
|   DHCPOpStart.DhcpNetworkInterface.MajorVersion         = 0;
 | |
|   DHCPOpStart.DhcpNetworkInterface.MinorVersion         = 0;
 | |
|   DHCPOpStart.DhcpClientArchitecture.Header.OpCode      = OP_DHCP_SYSTEM_ARCH;
 | |
|   DHCPOpStart.DhcpClientArchitecture.Header.Length      = DHCPV4_OPTION_LENGTH (DHCPV4_OP_ARCHITECTURE_TYPE);
 | |
|   DHCPOpStart.DhcpClientArchitecture.Type               = HTONS (SYS_ARCH);
 | |
|   DHCPOpStart.DhcpClassIdentifier.Header.OpCode         = OP_DHCP_CLASS_IDENTIFIER;
 | |
|   DHCPOpStart.DhcpClassIdentifier.Header.Length         = sizeof (DHCPV4_CLASS_ID_DATA);
 | |
|   CopyMem (
 | |
|     DHCPOpStart.DhcpClassIdentifier.Data.ClassIdentifier,
 | |
|     "PXEClient:",
 | |
|     sizeof ("PXEClient:")
 | |
|     );
 | |
|   CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit2, "Arch:", sizeof ("Arch:"));
 | |
|   CopyMem (
 | |
|     DHCPOpStart.DhcpClassIdentifier.Data.ArchitectureType,
 | |
|     "xxxxx",
 | |
|     sizeof ("xxxxx")
 | |
|     );
 | |
|   CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit3, ":", sizeof (":"));
 | |
|   CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.InterfaceName, "XXXX", sizeof ("XXXX"));
 | |
|   CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit4, ":", sizeof (":"));
 | |
|   CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMajor, "yyy", sizeof ("yyy"));
 | |
|   CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMinor, "xxx", sizeof ("xxx"));
 | |
|   DHCPOpStart.End[0] = OP_END;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // DHCPDECLINE option structure
 | |
| //
 | |
| struct opdeclinestr {
 | |
|   UINT8                   DhcpCookie[4];
 | |
|   DHCPV4_OP_MESSAGE_TYPE  DhcpMessageType;
 | |
|   struct requestopendstr  OpDeclineEnd;
 | |
| };
 | |
| 
 | |
| #define DHCPDECLINEoptions  (*(struct opdeclinestr *) DHCPV4_TRANSMIT_BUFFER.options)
 | |
| 
 | |
| //
 | |
| // DHCPRELEASE option structure
 | |
| //
 | |
| struct opreleasestr {
 | |
|   UINT8                   DhcpCookie[4];
 | |
|   DHCPV4_OP_MESSAGE_TYPE  DhcpMessageType;
 | |
|   DHCPV4_OP_SERVER_IP     DhcServerIpPtr;
 | |
|   UINT8                   End[1];
 | |
| };
 | |
| 
 | |
| #define DHCPRELEASEoptions  (*(struct opreleasestr *) DHCPV4_TRANSMIT_BUFFER.options)
 | |
| 
 | |
| //
 | |
| // array of PXE vendor options in which we are interested
 | |
| // value 0 -> not of interest, else value is index into PXE OPTION array
 | |
| // option values from 1 to MAX_OUR_PXE_OPT
 | |
| //
 | |
| STATIC UINT8  ourPXEopts[MAX_OUR_PXE_OPT] = {
 | |
|   VEND_PXE_MTFTP_IP_IX,             // multicast IP address of bootfile for MTFTP listen
 | |
|   VEND_PXE_MTFTP_CPORT_IX,          // UDP Port to monitor for MTFTP responses - Intel order
 | |
|   VEND_PXE_MTFTP_SPORT_IX,          // Server UDP Port for MTFTP open - Intel order
 | |
|   VEND_PXE_MTFTP_TMOUT_IX,          // Listen timeout - secs
 | |
|   VEND_PXE_MTFTP_DELAY_IX,          // Transmission timeout - secs
 | |
|   VEND_PXE_DISCOVERY_CONTROL_IX,    // bit field
 | |
|   VEND_PXE_DISCOVERY_MCAST_ADDR_IX, // boot server discovery multicast address
 | |
|   VEND_PXE_BOOT_SERVERS_IX,         // list of boot servers of form tp(2) cnt(1) ips[cnt]
 | |
|   VEND_PXE_BOOT_MENU_IX,
 | |
|   VEND_PXE_BOOT_PROMPT_IX,
 | |
|   VEND_PXE_MCAST_ADDRS_ALLOC_IX,    // not used by client
 | |
|   VEND_PXE_CREDENTIAL_TYPES_IX,
 | |
|   VEND_13_IX,                       // not used by client
 | |
|   VEND_14_IX,                       // not used by client
 | |
|   VEND_15_IX,                       // not used by client
 | |
|   VEND_16_IX,                       // not used by client
 | |
|   VEND_17_IX,                       // not used by client
 | |
|   VEND_18_IX,                       // not used by client
 | |
|   VEND_19_IX,                       // not used by client
 | |
|   VEND_20_IX,                       // not used by client
 | |
|   VEND_21_IX,                       // not used by client
 | |
|   VEND_22_IX,                       // not used by client
 | |
|   VEND_23_IX,                       // not used by client
 | |
|   VEND_24_IX,                       // not used by client
 | |
|   VEND_25_IX,                       // not used by client
 | |
|   VEND_26_IX,                       // not used by client
 | |
|   VEND_27_IX,                       // not used by client
 | |
|   VEND_28_IX,                       // not used by client
 | |
|   VEND_29_IX,                       // not used by client
 | |
|   VEND_30_IX,                       // not used by client
 | |
|   VEND_31_IX,                       // not used by client
 | |
|   VEND_32_IX,                       // not used by client
 | |
|   VEND_33_IX,                       // not used by client
 | |
|   VEND_34_IX,                       // not used by client
 | |
|   VEND_35_IX,                       // not used by client
 | |
|   VEND_36_IX,                       // not used by client
 | |
|   VEND_37_IX,                       // not used by client
 | |
|   VEND_38_IX,                       // not used by client
 | |
|   VEND_39_IX,                       // not used by client
 | |
|   VEND_40_IX,                       // not used by client
 | |
|   VEND_41_IX,                       // not used by client
 | |
|   VEND_42_IX,                       // not used by client
 | |
|   VEND_43_IX,                       // not used by client
 | |
|   VEND_44_IX,                       // not used by client
 | |
|   VEND_45_IX,                       // not used by client
 | |
|   VEND_46_IX,                       // not used by client
 | |
|   VEND_47_IX,                       // not used by client
 | |
|   VEND_48_IX,                       // not used by client
 | |
|   VEND_49_IX,                       // not used by client
 | |
|   VEND_50_IX,                       // not used by client
 | |
|   VEND_51_IX,                       // not used by client
 | |
|   VEND_52_IX,                       // not used by client
 | |
|   VEND_53_IX,                       // not used by client
 | |
|   VEND_54_IX,                       // not used by client
 | |
|   VEND_55_IX,                       // not used by client
 | |
|   VEND_56_IX,                       // not used by client
 | |
|   VEND_57_IX,                       // not used by client
 | |
|   VEND_58_IX,                       // not used by client
 | |
|   VEND_59_IX,                       // not used by client
 | |
|   VEND_60_IX,                       // not used by client
 | |
|   VEND_61_IX,                       // not used by client
 | |
|   VEND_62_IX,                       // not used by client
 | |
|   VEND_63_IX,                       // not used by client
 | |
|   VEND_64_IX,                       // not used by client
 | |
|   VEND_65_IX,                       // not used by client
 | |
|   VEND_66_IX,                       // not used by client
 | |
|   VEND_67_IX,                       // not used by client
 | |
|   VEND_68_IX,                       // not used by client
 | |
|   VEND_69_IX,                       // not used by client
 | |
|   VEND_70_IX,                       // not used by client
 | |
|   VEND_PXE_BOOT_ITEM_IX
 | |
| };
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // array of options in which we are interested
 | |
| // value 0 -> not of interest, else value is index into OPTION array
 | |
| // option values from 1 to MAX_OUR_OPT
 | |
| //
 | |
| STATIC UINT8  OurDhcpOptions[MAX_OUR_OPT] = {
 | |
|   OP_SUBNET_MASK_IX,                      // OP_SUBNET_MASK   1   // data is the subnet mask
 | |
|   OP_TIME_OFFSET_IX,                      // OP_TIME_OFFSET   2   // data is the time offset of subnet to UTC in seconds
 | |
|   OP_ROUTER_LIST_IX,                      // OP_ROUTER_LIST   3   // list of routers on subnet
 | |
|   OP_TIME_SERVERS_IX,                     // OP_TIME_SERVERS  4   // list of time servers available
 | |
|   OP_NAME_SERVERS_IX,                     // OP_NAME_SERVERS  5   // list of name servers available
 | |
|   OP_DNS_SERVERS_IX,                      // OP_DNS_SERVERS   6   // list of DNS servers available
 | |
|   OP_LOG_SERVERS_IX,                      // OP_LOG_SERVERS   7
 | |
|   OP_COOKIE_SERVERS_IX,                   // OP_COOKIE_SERVERS    8
 | |
|   OP_LPR_SREVERS_IX,                      // OP_LPR_SREVERS   9
 | |
|   OP_IMPRESS_SERVERS_IX,                  // OP_IMPRESS_SERVERS   10
 | |
|   OP_RES_LOC_SERVERS_IX,                  // OP_RES_LOC_SERVERS   11
 | |
|   OP_HOST_NAME_IX,                        // OP_HOST_NAME 12  // client name
 | |
|   OP_BOOT_FILE_SZ_IX,                     // OP_BOOT_FILE_SZ  13  // number of 512 blocks of boot file
 | |
|   OP_DUMP_FILE_IX,                        // OP_DUMP_FILE 14  // path name of dump file if client crashes
 | |
|   OP_DOMAIN_NAME_IX,                      // OP_DOMAIN_NAME   15  // domain name to use
 | |
|   OP_SWAP_SERVER_IX,                      // OP_SWAP_SERVER   16
 | |
|   OP_ROOT_PATH_IX,                        // OP_ROOT_PATH 17  // path name containing root disk
 | |
|   OP_EXTENSION_PATH_IX,                   // OP_EXTENSION_PATH    18  // name of TFTP downloadable file of form of OP
 | |
|   OP_IP_FORWARDING_IX,                    // OP_IP_FORWARDING 19  // enable/disable IP packet forwarding
 | |
|   OP_NON_LOCAL_SRC_RTE_IX,                // OP_NON_LOCAL_SRC_RTE 20  // enable/disable non local source routing
 | |
|   OP_POLICY_FILTER_IX,                    // OP_POLICY_FILTER 21  // policy filters for non local source routing
 | |
|   OP_MAX_DATAGRAM_SZ_IX,                  // OP_MAX_DATAGRAM_SZ   22  // maximum datagram reassembly size
 | |
|   OP_DEFAULT_TTL_IX,                      // OP_DEFAULT_TTL   23  // default IP time to live
 | |
|   OP_MTU_AGING_TIMEOUT_IX,                // OP_MTU_AGING_TIMEOUT 24
 | |
|   OP_MTU_SIZES_IX,                        // OP_MTU_SIZES 25
 | |
|   OP_MTU_TO_USE_IX,                       // OP_MTU_TO_USE    26
 | |
|   OP_ALL_SUBNETS_LOCAL_IX,                // OP_ALL_SUBNETS_LOCAL 27
 | |
|   OP_BROADCAST_ADD_IX,                    // OP_BROADCAST_ADD 28  // broadcast address used on subnet
 | |
|   OP_PERFORM_MASK_DISCOVERY_IX,           // OP_PERFORM_MASK_DISCOVERY    29  // perform mask discovery using ICMP
 | |
|   OP_RESPOND_TO_MASK_REQ_IX,              // OP_RESPOND_TO_MASK_REQ   30  // respond to subnet mask requests using ICMP
 | |
|   OP_PERFORM_ROUTER_DISCOVERY_IX,         // OP_PERFORM_ROUTER_DISCOVERY  31
 | |
|   OP_ROUTER_SOLICIT_ADDRESS_IX,           // OP_ROUTER_SOLICIT_ADDRESS    32
 | |
|   OP_STATIC_ROUTER_LIST_IX,               // OP_STATIC_ROUTER_LIST    33  // list of dest/route pairs
 | |
|   OP_USE_ARP_TRAILERS_IX,                 // OP_USE_ARP_TRAILERS      34
 | |
|   OP_ARP_CACHE_TIMEOUT_IX,                // OP_ARP_CACHE_TIMEOUT 35
 | |
|   OP_ETHERNET_ENCAPSULATION_IX,           // OP_ETHERNET_ENCAPSULATION    36  // 0 -> RFC 894, 1 -> IEEE 802.3 (RFC 1042)
 | |
|   OP_TCP_DEFAULT_TTL_IX,                  // OP_TCP_DEFAULT_TTL   37  // default time to live when sending TCP segments
 | |
|   OP_TCP_KEEP_ALIVE_INT_IX,               // OP_TCP_KEEP_ALIVE_INT    38  // keep alive interval in seconds
 | |
|   OP_KEEP_ALIVE_GARBAGE_IX,               // OP_KEEP_ALIVE_GARBAGE    39
 | |
|   OP_NIS_DOMAIN_NAME_IX,                  // OP_NIS_DOMAIN_NAME   40
 | |
|   OP_NIS_SERVERS_IX,                      // OP_NIS_SERVERS   41
 | |
|   OP_NTP_SERVERS_IX,                      // OP_NTP_SERVERS   42
 | |
|   OP_VENDOR_SPECIFIC_IX,                  // OP_VENDOR_SPECIFIC   43
 | |
|   OP_NBNS_SERVERS_IX,                     // OP_NBNS_SERVERS  44
 | |
|   OP_NBDD_SERVERS_IX,                     // OP_NBDD_SERVERS  45
 | |
|   OP_NETBIOS_NODE_TYPE_IX,                // OP_NETBIOS_NODE_TYPE 46
 | |
|   OP_NETBIOS_SCOPE_IX,                    // OP_NETBIOS_SCOPE 47
 | |
|   OP_XWINDOW_SYSTEM_FONT_SERVERS_IX,      // OP_XWINDOW_SYSTEM_FONT_SERVERS   48
 | |
|   OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX,  // OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS   49
 | |
|   OP_DHCP_REQ_IP_ADD_IX,                  // OP_DHCP_REQ_IP_ADD   50  // requested IP address - in DHCPDISCOVER
 | |
|   OP_DHCP_LEASE_TIME_IX,                  // OP_DHCP_LEASE_TIME   51  // lease time requested/granted
 | |
|   OP_DHCP_OPTION_OVERLOAD_IX,             // OP_DHCP_OPTION_OVERLOAD  52  // file/server name/both used to hold options
 | |
|   OP_DHCP_MESSAGE_TYPE_IX,                // OP_DHCP_MESSAGE_TYPE 53  // message type
 | |
|   OP_DHCP_SERVER_IP_IX,                   // OP_DHCP_SERVER_IP    54      // IP of server
 | |
|   OP_DHCP_PARM_REQ_LIST_IX,               // OP_DHCP_PARM_REQ_LIST    55  // list of requested parameters
 | |
|   OP_DHCP_ERROR_MESSAGE_IX,               // OP_DHCP_ERROR_MESSAGE    56  // in DHCPNAK or DECLINE messages
 | |
|   OP_DHCP_MAX_MESSAGE_SZ_IX,              // OP_DHCP_MAX_MESSAGE_SZ   57  // maximum DHCP message size client will accept
 | |
|   OP_DHCP_RENEWAL_TIME_IX,                // OP_DHCP_RENEWAL_TIME 58  // time in seconds before transitioning to RENEWING state
 | |
|   OP_DHCP_REBINDING_TIME_IX,              // OP_DHCP_REBINDING_TIME   59  // time in seconds before transitioning to REBINDING state
 | |
|   OP_DHCP_CLASS_IDENTIFIER_IX,            // OP_DHCP_CLASS_IDENTIFIER 60
 | |
|   OP_DHCP_CLIENT_IDENTIFIER_IX,           // OP_DHCP_CLIENT_IDENTIFIER    61
 | |
|   OP_RESERVED62_IX,                       // OP_RESERVED62
 | |
|   OP_RESERVED63_IX,                       // OP_RESERVED63
 | |
|   OP_NISPLUS_DOMAIN_NAME_IX,              // OP_NISPLUS_DOMAIN_NAME   64
 | |
|   OP_NISPLUS_SERVERS_IX,                  // OP_NISPLUS_SERVERS   65
 | |
|   OP_DHCP_TFTP_SERVER_NAME_IX,            // OP_DHCP_TFTP_SERVER_NAME 66
 | |
|   OP_DHCP_BOOTFILE_IX                     // OP_DHCP_BOOTFILE 67
 | |
| };
 | |
| 
 | |
| #define RxBuf ((DHCP_RECEIVE_BUFFER *) (Private->ReceiveBuffers))
 | |
| 
 | |
| #pragma pack()
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /**
 | |
| 
 | |
|   @param  Smbios              Pointer to SMBIOS structure
 | |
|   @param  StringNumber        String number to return. 0 is used to skip all
 | |
|                               strings and  point to the next SMBIOS structure.
 | |
| 
 | |
|   @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0
 | |
| 
 | |
| **/
 | |
| CHAR8 *
 | |
| PxeBcLibGetSmbiosString (
 | |
|   IN  SMBIOS_STRUCTURE_POINTER  *Smbios,
 | |
|   IN  UINT16                    StringNumber
 | |
|   )
 | |
| {
 | |
|   UINT16  Index;
 | |
|   CHAR8   *String;
 | |
| 
 | |
|   //
 | |
|   // Skip over formatted section
 | |
|   //
 | |
|   String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);
 | |
| 
 | |
|   //
 | |
|   // Look through unformated section
 | |
|   //
 | |
|   for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {
 | |
|     if (StringNumber == Index) {
 | |
|       return String;
 | |
|     }
 | |
|     //
 | |
|     // Skip string
 | |
|     //
 | |
|     for (; *String != 0; String++)
 | |
|       ;
 | |
|     String++;
 | |
| 
 | |
|     if (*String == 0) {
 | |
|       //
 | |
|       // If double NULL then we are done.
 | |
|       //  Return pointer to next structure in Smbios.
 | |
|       //  if you pass in a 0 you will always get here
 | |
|       //
 | |
|       Smbios->Raw = (UINT8 *)++String;
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function gets system guid and serial number from the smbios table
 | |
| 
 | |
|   @param  SystemGuid          The pointer of returned system guid
 | |
|   @param  SystemSerialNumber  The pointer of returned system serial number
 | |
| 
 | |
|   @retval EFI_SUCCESS         Successfully get the system guid and system serial
 | |
|                               number
 | |
|   @retval EFI_NOT_FOUND       Not find the SMBIOS table
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
 | |
|   IN  EFI_GUID  *SystemGuid,
 | |
|   OUT CHAR8     **SystemSerialNumber
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   SMBIOS_TABLE_ENTRY_POINT  *SmbiosTable;
 | |
|   SMBIOS_STRUCTURE_POINTER  Smbios;
 | |
|   SMBIOS_STRUCTURE_POINTER  SmbiosEnd;
 | |
|   UINT16                    Index;
 | |
| 
 | |
|   Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Smbios.Hdr    = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;
 | |
|   SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
 | |
| 
 | |
|   for (Index = 0; Index < SmbiosTable->TableLength; Index++) {
 | |
|     if (Smbios.Hdr->Type == 1) {
 | |
|       if (Smbios.Hdr->Length < 0x19) {
 | |
|         //
 | |
|         // Older version did not support Guid and Serial number
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
|       //
 | |
|       // SMBIOS tables are byte packed so we need to do a byte copy to
 | |
|       // prevend alignment faults on Itanium-based platform.
 | |
|       //
 | |
|       CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
 | |
|       *SystemSerialNumber = PxeBcLibGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber);
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // Make Smbios point to the next record
 | |
|     //
 | |
|     PxeBcLibGetSmbiosString (&Smbios, 0);
 | |
| 
 | |
|     if (Smbios.Raw >= SmbiosEnd.Raw) {
 | |
|       //
 | |
|       // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.
 | |
|       // given this we must double check against the lenght of
 | |
|       // the structure.
 | |
|       //
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // add router list to list
 | |
| //
 | |
| STATIC
 | |
| VOID
 | |
| Ip4AddRouterList (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   DHCPV4_OP_IP_LIST   *IpListPtr
 | |
|   )
 | |
| {
 | |
|   EFI_IP_ADDRESS  TmpIp;
 | |
|   INTN            Index;
 | |
|   INTN            num;
 | |
| 
 | |
|   if (IpListPtr == NULL) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0, num = IpListPtr->Header.Length >> 2; Index < num; ++Index) {
 | |
|     CopyMem (&TmpIp, &IpListPtr->IpList[Index], 4);
 | |
|     Ip4AddRouter (Private, &TmpIp);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // send ARP for our IP - fail if someone has it
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| SetStationIP (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   EFI_MAC_ADDRESS DestMac;
 | |
|   EFI_STATUS      EfiStatus;
 | |
| 
 | |
|   ZeroMem (&DestMac, sizeof DestMac);
 | |
| 
 | |
|   if (GetHwAddr(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac)
 | |
|     || DoArp(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) == EFI_SUCCESS) {
 | |
|     return FALSE;   // somebody else has this IP
 | |
|   }
 | |
| 
 | |
|   CopyMem (
 | |
|     (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->StationIp,
 | |
|     &DHCP_REQ_OPTIONS.OpReqIP.Ip,
 | |
|     sizeof (EFI_IPv4_ADDRESS)
 | |
|     );
 | |
| 
 | |
|   Private->GoodStationIp = TRUE;
 | |
| 
 | |
|   if (!Private->UseIgmpv1Reporting) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if (Private->Igmpv1TimeoutEvent != NULL) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   EfiStatus = gBS->CreateEvent (
 | |
|                     EVT_TIMER,
 | |
|                     TPL_CALLBACK,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     &Private->Igmpv1TimeoutEvent
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (EfiStatus)) {
 | |
|     Private->Igmpv1TimeoutEvent = NULL;
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   EfiStatus = gBS->SetTimer (
 | |
|                     Private->Igmpv1TimeoutEvent,
 | |
|                     TimerRelative,
 | |
|                     (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
 | |
|                     );  /* 400 seconds */
 | |
| 
 | |
|   if (EFI_ERROR (EfiStatus)) {
 | |
|     gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
 | |
|     Private->Igmpv1TimeoutEvent = NULL;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| VOID
 | |
| AddRouters (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   DHCP_RECEIVE_BUFFER *RxBufPtr
 | |
|   )
 | |
| {
 | |
|   Ip4AddRouterList (
 | |
|     Private,
 | |
|     (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1]
 | |
|     );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| DoUdpWrite (
 | |
|   PXE_BASECODE_DEVICE         *Private,
 | |
|   EFI_IP_ADDRESS              *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ServerPortPtr,
 | |
|   EFI_IP_ADDRESS              *ClientIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  *ClientPortPtr
 | |
|   )
 | |
| {
 | |
|   UINTN Len;
 | |
| 
 | |
|   Len = sizeof DHCPV4_TRANSMIT_BUFFER;
 | |
| 
 | |
|   return UdpWrite (
 | |
|           Private,
 | |
|           EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
 | |
|           ServerIpPtr,
 | |
|           ServerPortPtr,
 | |
|           0,
 | |
|           ClientIpPtr,
 | |
|           ClientPortPtr,
 | |
|           0,
 | |
|           0,
 | |
|           &Len,
 | |
|           Private->TransmitBuffer
 | |
|           );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // initialize the DHCP structure
 | |
| //
 | |
| typedef struct {
 | |
|   UINT8 x[4];
 | |
| } C4Str;
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| InitDhcpv4TxBuf (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   UINTN                   HwAddrLen;
 | |
|   UINT8                   *String;
 | |
|   CHAR8                   *SystemSerialNumber;
 | |
|   EFI_PXE_BASE_CODE_MODE  *PxebcMode;
 | |
| 
 | |
|   PxebcMode = Private->EfiBc.Mode;
 | |
| 
 | |
|   ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT));
 | |
|   DHCPV4_TRANSMIT_BUFFER.op     = BOOTP_REQUEST;
 | |
|   DHCPV4_TRANSMIT_BUFFER.htype  = Private->SimpleNetwork->Mode->IfType;
 | |
|   DHCPV4_TRANSMIT_BUFFER.flags  = HTONS (DHCP_BROADCAST_FLAG);
 | |
|   CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart));
 | |
| 
 | |
|   //
 | |
|   // default to hardware address
 | |
|   //
 | |
|   HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize;
 | |
| 
 | |
|   if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) {
 | |
|     HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr;
 | |
|   }
 | |
| 
 | |
|   String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress;
 | |
| 
 | |
|   if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
 | |
|         (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid,
 | |
|         &SystemSerialNumber
 | |
|         ) == EFI_SUCCESS) {
 | |
|     if (PxebcMode->SendGUID) {
 | |
|       HwAddrLen = sizeof (EFI_GUID);
 | |
|       String    = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // GUID not yet set - send all 0xff's to show programable (via SetVariable)
 | |
|     // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
 | |
|     // GUID not yet set - send all 0's to show not programable
 | |
|     //
 | |
|     ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID));
 | |
|   }
 | |
| 
 | |
|   DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen;
 | |
|   CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen);
 | |
| 
 | |
|   CvtNum (
 | |
|     SYS_ARCH,
 | |
|     (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType,
 | |
|     sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType
 | |
|     );
 | |
| 
 | |
|   DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type                         = Private->NiiPtr->Type;
 | |
|   DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion                 = Private->NiiPtr->MajorVer;
 | |
|   DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion                 = Private->NiiPtr->MinorVer;
 | |
| 
 | |
|   *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId;
 | |
| 
 | |
|   CvtNum (
 | |
|     DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion,
 | |
|     (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor,
 | |
|     sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor
 | |
|     );
 | |
| 
 | |
|   CvtNum (
 | |
|     DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion,
 | |
|     (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor,
 | |
|     sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor
 | |
|     );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| UINT32
 | |
| DecodePxeOptions (
 | |
|   DHCP_RECEIVE_BUFFER *RxBufPtr,
 | |
|   UINT8               *ptr,
 | |
|   INTN                Len
 | |
|   )
 | |
| {
 | |
|   UINT8     Op;
 | |
|   UINT8     *EndPtr;
 | |
|   INTN      Index;
 | |
|   UNION_PTR LocalPtr;
 | |
|   UINT32    status;
 | |
| 
 | |
|   status = 0;
 | |
| 
 | |
|   for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
 | |
|     Op  = ptr[0];
 | |
|     Len = ptr[1];
 | |
| 
 | |
|     switch (Op) {
 | |
|     case OP_PAD:
 | |
|       Len = -1;
 | |
|       break;
 | |
| 
 | |
|     case OP_END:
 | |
|       return status;
 | |
| 
 | |
|     default:
 | |
|       LocalPtr.BytePtr = ptr;
 | |
|       if (Op <= MAX_OUR_PXE_OPT) {
 | |
|         Index = ourPXEopts[Op - 1];
 | |
|         if (Index) {
 | |
|           RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr;
 | |
|           status |= 1 << Index;
 | |
|           if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) {
 | |
|             RxBufPtr->OpAdds.Status |= USE_THREE_BYTE;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| VOID
 | |
| DecodeOptions (
 | |
|   DHCP_RECEIVE_BUFFER *RxBufPtr,
 | |
|   UINT8               *ptr,
 | |
|   INTN                Len
 | |
|   )
 | |
| {
 | |
|   UINT8     Op;
 | |
|   UINT8     *EndPtr;
 | |
|   INTN      Index;
 | |
|   UNION_PTR LocalPtr;
 | |
| 
 | |
|   for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
 | |
|     Op  = ptr[0];
 | |
|     Len = ptr[1];
 | |
| 
 | |
|     switch (Op) {
 | |
|     case OP_PAD:
 | |
|       Len = -1;
 | |
|       break;
 | |
| 
 | |
|     case OP_END:
 | |
|       return ;
 | |
| 
 | |
|     default:
 | |
|       LocalPtr.BytePtr = ptr;
 | |
|       if (Op <= MAX_OUR_OPT) {
 | |
|         Index = OurDhcpOptions[Op - 1];
 | |
|         if (Index) {
 | |
|           RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr;
 | |
|           if (Index == OP_VENDOR_SPECIFIC_IX) {
 | |
|             UINT32  status;
 | |
|             status = DecodePxeOptions (
 | |
|                       RxBufPtr,
 | |
|                       (UINT8 *) LocalPtr.VendorOptions->VendorOptions,
 | |
|                       LocalPtr.VendorOptions->Header.Length
 | |
|                       );
 | |
|             if (status) {
 | |
|               RxBufPtr->OpAdds.Status |= PXE_TYPE;
 | |
|               //
 | |
|               // check for all the MTFTP info options present - any missing is a nogo
 | |
|               //
 | |
|               if ((status & WfM11a_OPTS) == WfM11a_OPTS) {
 | |
|                 RxBufPtr->OpAdds.Status |= WfM11a_TYPE;
 | |
|               }
 | |
| 
 | |
|               if (status & DISCOVER_OPTS) {
 | |
|                 RxBufPtr->OpAdds.Status |= DISCOVER_TYPE;
 | |
|               }
 | |
| 
 | |
|               if (status & CREDENTIALS_OPT) {
 | |
|                 RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| VOID
 | |
| Parse (
 | |
|   DHCP_RECEIVE_BUFFER *RxBufPtr,
 | |
|   INTN                Len
 | |
|   )
 | |
| {
 | |
|   UNION_PTR LocalPtr;
 | |
| 
 | |
|   //
 | |
|   // initialize
 | |
|   //
 | |
|   SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0);
 | |
| 
 | |
|   DecodeOptions (
 | |
|     RxBufPtr,
 | |
|     RxBufPtr->u.Dhcpv4.options + 4,
 | |
|     Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4)
 | |
|     );
 | |
| 
 | |
|   LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1];
 | |
| 
 | |
|   if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) {
 | |
|     DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname);
 | |
|   }
 | |
| 
 | |
|   if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) {
 | |
|     DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file);
 | |
|   } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) {
 | |
|     RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER));
 | |
| 
 | |
|     RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen ((CHAR8 *) RxBufPtr->u.Dhcpv4.file);
 | |
|   }
 | |
| 
 | |
|   LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1];
 | |
| 
 | |
|   if ((LocalPtr.OpPtr) &&
 | |
|       LocalPtr.PxeClassStr->Header.Length >= 9 &&
 | |
|       !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9)
 | |
|         ) {
 | |
|     RxBufPtr->OpAdds.Status |= PXE_TYPE;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| VOID
 | |
| CopyParseRxBuf (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                RxBufIndex,
 | |
|   INTN                PacketIndex
 | |
|   )
 | |
| {
 | |
|   DHCP_RECEIVE_BUFFER *RxBufPtr;
 | |
| 
 | |
|   RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex];
 | |
| 
 | |
|   CopyMem (
 | |
|     &RxBufPtr->u.Dhcpv4,
 | |
|     &RxBuf[RxBufIndex].u.Dhcpv4,
 | |
|     sizeof (RxBuf[RxBufIndex].u.Dhcpv4)
 | |
|     );
 | |
| 
 | |
|   Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer);
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| VOID
 | |
| CopyProxyRxBuf (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                RxBufIndex
 | |
|   )
 | |
| {
 | |
|   Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
 | |
|   CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX);
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| VOID
 | |
| CopyParse (
 | |
|   PXE_BASECODE_DEVICE       *Private,
 | |
|   EFI_PXE_BASE_CODE_PACKET  *PacketPtr,
 | |
|   EFI_PXE_BASE_CODE_PACKET  *NewPacketPtr,
 | |
|   INTN                      Index
 | |
|   )
 | |
| {
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf;
 | |
| 
 | |
|   DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index];
 | |
| 
 | |
|   CopyMem (
 | |
|     (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4,
 | |
|     NewPacketPtr,
 | |
|     sizeof (*NewPacketPtr)
 | |
|     );
 | |
| 
 | |
|   CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr));
 | |
| 
 | |
|   Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer);
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| BOOLEAN
 | |
| AckEdit (
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf
 | |
|   )
 | |
| {
 | |
|   UNION_PTR LocalPtr;
 | |
| 
 | |
|   LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
 | |
| 
 | |
|   //
 | |
|   // check that an ACK
 | |
|   // if a DHCP type, must be DHCPOFFER and must have server id
 | |
|   //
 | |
|   return (BOOLEAN)
 | |
|     (
 | |
|       (LocalPtr.OpPtr) &&
 | |
|       (LocalPtr.MessageType->Type == DHCPACK) &&
 | |
|       DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]
 | |
|     );
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // if a discover type packet, make sure all required fields are present
 | |
| //
 | |
| BOOLEAN
 | |
| DHCPOfferAckEdit (
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf
 | |
|   )
 | |
| {
 | |
|   PXE_OP_SERVER_LIST  *BootServerOpPtr;
 | |
|   UNION_PTR           LocalPtr;
 | |
| 
 | |
|   if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
 | |
| 
 | |
|   if (LocalPtr.OpPtr == NULL) {
 | |
|     LocalPtr.OpPtr  = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
 | |
|     DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
 | |
|   }
 | |
|   //
 | |
|   // make sure all required fields are here
 | |
|   // if mucticast enabled, need multicast address
 | |
|   //
 | |
|   if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) &&
 | |
|       (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1] || !IS_MULTICAST (((DHCPV4_OP_STRUCT *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Data))
 | |
|       ) {
 | |
|     return FALSE;
 | |
|     //
 | |
|     // missing required field
 | |
|     //
 | |
|   }
 | |
|   //
 | |
|   // if a list, it better be good
 | |
|   //
 | |
|   BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1];
 | |
| 
 | |
|   if (BootServerOpPtr != NULL) {
 | |
|     PXE_SERVER_LIST *BootServerListPtr;
 | |
|     INTN            ServerListLen;
 | |
|     INTN            ServerEntryLen;
 | |
| 
 | |
|     BootServerListPtr = BootServerOpPtr->ServerList;
 | |
|     ServerListLen     = BootServerOpPtr->Header.Length;
 | |
| 
 | |
|     do {
 | |
|       EFI_IPv4_ADDRESS  *IpListPtr;
 | |
|       INTN              IpCnt;
 | |
| 
 | |
|       IpCnt           = BootServerListPtr->u.Ipv4List.IpCount;
 | |
| 
 | |
|       ServerEntryLen  = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS);
 | |
| 
 | |
|       if (ServerListLen < ServerEntryLen) {
 | |
|         //
 | |
|         // missing required field
 | |
|         //
 | |
|         return FALSE;
 | |
|       }
 | |
| 
 | |
|       IpListPtr = BootServerListPtr->u.Ipv4List.IpList;
 | |
| 
 | |
|       while (IpCnt--) {
 | |
|         if (IS_MULTICAST (IpListPtr)) {
 | |
|           //
 | |
|           // missing required field
 | |
|           //
 | |
|           return FALSE;
 | |
|         } else {
 | |
|           ++IpListPtr;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr;
 | |
|     } while (ServerListLen -= ServerEntryLen);
 | |
|   }
 | |
|   //
 | |
|   // else there must be a list if use list enabled or multicast and
 | |
|   // broadcast disabled
 | |
|   //
 | |
|   else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) ||
 | |
|            ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
 | |
|           ) {
 | |
|     //
 | |
|     // missing required field
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // if not USE_BOOTFILE or no bootfile given, must have menu stuff
 | |
|   //
 | |
|   if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) ||
 | |
|       !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
 | |
|       ) {
 | |
|     INTN  MenuLth;
 | |
| 
 | |
|     LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
 | |
| 
 | |
|     if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) {
 | |
|       //
 | |
|       // missing required field
 | |
|       //
 | |
|       return FALSE;
 | |
|     }
 | |
|     //
 | |
|     // make sure menu valid
 | |
|     //
 | |
|     MenuLth               = LocalPtr.BootMenu->Header.Length;
 | |
|     LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem;
 | |
| 
 | |
|     do {
 | |
|       INTN  MenuItemLen;
 | |
| 
 | |
|       MenuItemLen = LocalPtr.BootMenuItem->DataLen;
 | |
| 
 | |
|       if (MenuItemLen == 0) {
 | |
|         //
 | |
|         // missing required field
 | |
|         //
 | |
|         return FALSE;
 | |
|       }
 | |
| 
 | |
|       MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data);
 | |
| 
 | |
|       MenuLth -= MenuItemLen;
 | |
|       LocalPtr.BytePtr += MenuItemLen;
 | |
|     } while (MenuLth > 0);
 | |
| 
 | |
|     if (MenuLth != 0) {
 | |
|       //
 | |
|       // missing required field
 | |
|       //
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
 | |
|     DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| BOOLEAN
 | |
| DHCPAckEdit (
 | |
|   DHCP_RECEIVE_BUFFER *RxBufPtr
 | |
|   )
 | |
| {
 | |
|   return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE);
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // get an offer/ack
 | |
| //
 | |
| EFI_STATUS
 | |
| GetOfferAck (
 | |
|   PXE_BASECODE_DEVICE          *Private,
 | |
|   BOOLEAN                     (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf),
 | |
|   UINT16 OpFlags, // for Udp read
 | |
|   EFI_IP_ADDRESS *ServerIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
 | |
|   EFI_IP_ADDRESS *ClientIpPtr,
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr,
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf,
 | |
|   EFI_EVENT TimeoutEvent
 | |
|   )
 | |
| /*++
 | |
| Routine description:
 | |
|   Wait for an OFFER/ACK packet.
 | |
| 
 | |
| Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   ExtraEdit := Pointer to extra option checking function
 | |
|   OpFlags := UdpRead() option flags
 | |
|   ServerIpPtr :=
 | |
|   ServerPortPtr :=
 | |
|   ClientIpPtr :=
 | |
|   ClientPortPtr :=
 | |
|   DhcpRxBuf :=
 | |
|   TimeoutEvent :=
 | |
| 
 | |
| Returns:
 | |
| --*/
 | |
| {
 | |
|   EFI_IP_ADDRESS  ServerIp;
 | |
|   EFI_STATUS      StatCode;
 | |
|   INTN            RxBufLen;
 | |
| 
 | |
|   for (;;) {
 | |
|     //
 | |
|     // Wait until we get a UDP packet.
 | |
|     //
 | |
|     ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
 | |
|     RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer;
 | |
| 
 | |
|     if ((StatCode = UdpRead (
 | |
|                       Private,
 | |
|                       OpFlags,
 | |
|                       ClientIpPtr,
 | |
|                       ClientPortPtr,
 | |
|                       ServerIpPtr,
 | |
|                       ServerPortPtr,
 | |
|                       0,
 | |
|                       0,
 | |
|                       (UINTN *) &RxBufLen,
 | |
|                       &DhcpRxBuf->u.Dhcpv4,
 | |
|                       TimeoutEvent
 | |
|                       )) != EFI_SUCCESS) {
 | |
|       if (StatCode == EFI_TIMEOUT) {
 | |
|         StatCode = EFI_NO_RESPONSE;
 | |
|       }
 | |
| 
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // got a packet - see if a good offer
 | |
|     //
 | |
|     if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (CompareMem (
 | |
|           DhcpRxBuf->u.Dhcpv4.chaddr,
 | |
|           DHCPV4_TRANSMIT_BUFFER.chaddr,
 | |
|           sizeof DhcpRxBuf->u.Dhcpv4.chaddr
 | |
|           )) {
 | |
|       //
 | |
|       // no good
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Parse (DhcpRxBuf, RxBufLen);
 | |
| 
 | |
|     if (!(*ExtraEdit) (DhcpRxBuf)) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Good DHCP packet.
 | |
|     //
 | |
|     StatCode = EFI_SUCCESS;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return StatCode;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // get DHCPOFFER's
 | |
| //
 | |
| EFI_STATUS
 | |
| GetOffers (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   EFI_IP_ADDRESS  ClientIp;
 | |
|   EFI_IP_ADDRESS  ServerIp;
 | |
|   EFI_STATUS      StatCode;
 | |
|   EFI_EVENT       TimeoutEvent;
 | |
|   INTN            NumOffers;
 | |
|   INTN            Index;
 | |
| 
 | |
|   //
 | |
|   //
 | |
|   //
 | |
|   ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
 | |
|   NumOffers = 0;
 | |
| 
 | |
|   for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) {
 | |
|     Private->ServerCount[Index] = 0;
 | |
|     Private->GotProxy[Index]    = 0;
 | |
|   }
 | |
| 
 | |
|   Private->GotBootp               = 0;
 | |
|   //
 | |
|   // these we throw away
 | |
|   //
 | |
|   Private->GotProxy[DHCP_ONLY_IX] = 1;
 | |
|   StatCode = gBS->CreateEvent (
 | |
|                     EVT_TIMER,
 | |
|                     TPL_CALLBACK,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     &TimeoutEvent
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (StatCode)) {
 | |
|     return StatCode;
 | |
|   }
 | |
| 
 | |
|   StatCode = gBS->SetTimer (
 | |
|                     TimeoutEvent,
 | |
|                     TimerRelative,
 | |
|                     Private->Timeout * 10000000 + 1000000
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (StatCode)) {
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|     return StatCode;
 | |
|   }
 | |
|   //
 | |
|   // get offers
 | |
|   //
 | |
|   for (;;) {
 | |
|     DHCP_RECEIVE_BUFFER *DhcpRxBuf;
 | |
|     UNION_PTR           LocalPtr;
 | |
| 
 | |
|     DhcpRxBuf = &RxBuf[NumOffers];
 | |
| 
 | |
|     if ((
 | |
|           StatCode = GetOfferAck (
 | |
|                   Private,
 | |
|         DHCPOfferAckEdit,
 | |
|         EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
 | |
|         EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP |
 | |
|         EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|         &ServerIp,
 | |
|         &DhcpServerPort,
 | |
|         &ClientIp,
 | |
|         &DHCPClientPort,
 | |
|         DhcpRxBuf,
 | |
|         TimeoutEvent
 | |
|         )
 | |
| ) != EFI_SUCCESS
 | |
|         ) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
 | |
| 
 | |
|     //
 | |
|     // check type of offer
 | |
|     //
 | |
|     if (LocalPtr.OpPtr == NULL) {
 | |
|       //
 | |
|       // bootp - we only need one and make sure has bootfile
 | |
|       //
 | |
|       if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       Private->GotBootp = (UINT8) (NumOffers + 1);
 | |
|     }
 | |
|     //
 | |
|     // if a DHCP type, must be DHCPOFFER and must have server id
 | |
|     //
 | |
|     else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) {
 | |
|       continue;
 | |
|     } else {
 | |
|       INTN  TypeIx;
 | |
| 
 | |
|       //
 | |
|       // get type - PXE10, WfM11a, or BINL
 | |
|       //
 | |
|       if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) {
 | |
|         TypeIx = PXE10_IX;
 | |
|       } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) {
 | |
|         //
 | |
|         // WfM - make sure it has a bootfile
 | |
|         //
 | |
|         if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         TypeIx = WfM11a_IX;
 | |
|       } else {
 | |
|         TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX;
 | |
|       }
 | |
|       //
 | |
|       // check DHCP or proxy
 | |
|       //
 | |
|       if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) {
 | |
|         //
 | |
|         // proxy - only need one of each type if not BINL
 | |
|         // and must have at least PXE_TYPE
 | |
|         //
 | |
|         if (TypeIx == BINL_IX) {
 | |
|           Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers;
 | |
|         } else if (Private->GotProxy[TypeIx]) {
 | |
|           continue;
 | |
|         } else {
 | |
|           Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1);
 | |
|         }
 | |
|       } else {
 | |
|         Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (++NumOffers == MAX_OFFERS) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (TimeoutEvent);
 | |
|   Private->NumOffersReceived = NumOffers;
 | |
| 
 | |
|   return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // send DHCPDECLINE
 | |
| //
 | |
| STATIC
 | |
| VOID
 | |
| DeclineOffer (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_MODE  *PxebcMode;
 | |
|   UINT16                  SaveSecs;
 | |
| 
 | |
|   PxebcMode                     = Private->EfiBc.Mode;
 | |
|   SaveSecs                      = DHCPV4_TRANSMIT_BUFFER.secs;
 | |
| 
 | |
|   DHCPV4_TRANSMIT_BUFFER.secs   = 0;
 | |
|   DHCPV4_TRANSMIT_BUFFER.flags  = 0;
 | |
|   SetMem (
 | |
|     DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr),
 | |
|     sizeof (DHCPOpStart) - sizeof (struct opdeclinestr),
 | |
|     OP_PAD
 | |
|     );
 | |
|   DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE;
 | |
|   CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (DHCPDECLINEoptions.OpDeclineEnd));
 | |
| 
 | |
|   {
 | |
|     EFI_IP_ADDRESS  TmpIp;
 | |
| 
 | |
|     CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp);
 | |
| 
 | |
|     DoUdpWrite (
 | |
|       Private,
 | |
|       &TmpIp,
 | |
|       &DhcpServerPort,
 | |
|       &PxebcMode->StationIp,
 | |
|       &DHCPClientPort
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   InitDhcpv4TxBuf (Private);
 | |
|   DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
 | |
|   Private->GoodStationIp      = FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // send DHCPRELEASE
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| Release (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_MODE  *PxebcMode;
 | |
|   UINT16                  SaveSecs;
 | |
| 
 | |
|   PxebcMode                   = Private->EfiBc.Mode;
 | |
|   SaveSecs                    = DHCPV4_TRANSMIT_BUFFER.secs;
 | |
|   DHCPV4_TRANSMIT_BUFFER.secs = 0;
 | |
| 
 | |
|   SetMem (
 | |
|     DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr),
 | |
|     sizeof (DHCPOpStart) - sizeof (struct opreleasestr),
 | |
|     OP_PAD
 | |
|     );
 | |
| 
 | |
|   DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE;
 | |
| 
 | |
|   CopyMem (
 | |
|     &DHCPRELEASEoptions.DhcServerIpPtr,
 | |
|     (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1],
 | |
|     sizeof DHCPRELEASEoptions.DhcServerIpPtr
 | |
|     );
 | |
| 
 | |
|   DHCPRELEASEoptions.End[0] = OP_END;
 | |
| 
 | |
|   {
 | |
|     EFI_IP_ADDRESS  TmpIp;
 | |
| 
 | |
|     CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp);
 | |
| 
 | |
|     DoUdpWrite (
 | |
|       Private,
 | |
|       &TmpIp,
 | |
|       &DhcpServerPort,
 | |
|       &PxebcMode->StationIp,
 | |
|       &DHCPClientPort
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   InitDhcpv4TxBuf (Private);
 | |
| 
 | |
|   DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
 | |
|   Private->GoodStationIp      = FALSE;
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| BOOLEAN
 | |
| GetBINLAck (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   EFI_IP_ADDRESS      *ServerIpPtr
 | |
|   )
 | |
| {
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf;
 | |
|   EFI_STATUS          StatCode;
 | |
|   EFI_EVENT           TimeoutEvent;
 | |
| 
 | |
|   //
 | |
|   //
 | |
|   //
 | |
|   StatCode = gBS->CreateEvent (
 | |
|                     EVT_TIMER,
 | |
|                     TPL_CALLBACK,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     &TimeoutEvent
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (StatCode)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   StatCode = gBS->SetTimer (
 | |
|                     TimeoutEvent,
 | |
|                     TimerRelative,
 | |
|                     Private->Timeout * 10000000 + 1000000
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (StatCode)) {
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   //
 | |
|   //
 | |
|   DhcpRxBuf = &PXE_BINL_BUFFER;
 | |
| 
 | |
|   for (;;) {
 | |
|     EFI_PXE_BASE_CODE_UDP_PORT  BINLSrvPort;
 | |
| 
 | |
|     BINLSrvPort = 0;
 | |
| 
 | |
|     if (GetOfferAck (
 | |
|           Private,
 | |
|           AckEdit,
 | |
|           EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|           ServerIpPtr,
 | |
|           &BINLSrvPort,
 | |
|           &Private->EfiBc.Mode->StationIp,
 | |
|           &PSEUDO_DHCP_CLIENT_PORT,
 | |
|           DhcpRxBuf,
 | |
|           TimeoutEvent
 | |
|           ) != EFI_SUCCESS) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // make sure from whom we wanted
 | |
|     //
 | |
|     if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem (
 | |
|                                           &ServerIpPtr->v4,
 | |
|                                           &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
 | |
|                                           sizeof (ServerIpPtr->v4)
 | |
|                                           )) {
 | |
|       gBS->CloseEvent (TimeoutEvent);
 | |
|       //
 | |
|       // got an ACK from server
 | |
|       //
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (TimeoutEvent);
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // make sure we can get BINL
 | |
| // send DHCPREQUEST to PXE server
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryBINL (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                OfferIx
 | |
|   )
 | |
| {
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf;
 | |
|   EFI_IP_ADDRESS      ServerIp;
 | |
|   UINT16              SaveSecs;
 | |
|   INTN                Index;
 | |
| 
 | |
|   DhcpRxBuf = &RxBuf[OfferIx];
 | |
| 
 | |
|   //
 | |
|   // use next server address first.
 | |
|   //
 | |
|   ServerIp.Addr[0] = DhcpRxBuf->u.Dhcpv4.siaddr;
 | |
|   if (ServerIp.Addr[0] == 0) {
 | |
|     //
 | |
|     // next server address is NULL, use option 54.
 | |
|     //
 | |
|     CopyMem (
 | |
|       ((EFI_IPv4_ADDRESS *) &ServerIp),
 | |
|       &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
 | |
|       sizeof (EFI_IPv4_ADDRESS)
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // client IP address - filled in by client if it knows it
 | |
|   //
 | |
|   CopyMem (
 | |
|     ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr),
 | |
|     &DHCP_REQ_OPTIONS.OpReqIP.Ip,
 | |
|     sizeof (EFI_IPv4_ADDRESS)
 | |
|     );
 | |
| 
 | |
|   SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD);
 | |
|   DHCPV4_TRANSMIT_BUFFER.flags  = 0;
 | |
|   DHCPV4_OPTIONS_BUFFER.End[0]  = OP_END;
 | |
|   AddRouters (Private, DhcpRxBuf);
 | |
|   SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
 | |
| 
 | |
|   for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) {
 | |
|     DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
 | |
| 
 | |
|     //
 | |
|     // unicast DHCPREQUEST to PXE server
 | |
|     //
 | |
|     if (DoUdpWrite (
 | |
|           Private,
 | |
|           &ServerIp,
 | |
|           &PseudoDhcpServerPort,
 | |
|           (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
 | |
|           &PSEUDO_DHCP_CLIENT_PORT
 | |
|           ) != EFI_SUCCESS) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (!GetBINLAck (Private, &ServerIp)) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // early exit failures
 | |
|     // make sure a good ACK
 | |
|     //
 | |
|     if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || (
 | |
|           !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
 | |
|       )
 | |
|         ) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
 | |
|     return TRUE;
 | |
|   }
 | |
|   //
 | |
|   // failed - reset seconds field, etc.
 | |
|   //
 | |
|   Private->EfiBc.Mode->RouteTableEntries = 0;
 | |
|   //
 | |
|   // reset
 | |
|   //
 | |
|   DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryFinishBINL (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                OfferIx
 | |
|   )
 | |
| {
 | |
|   if (TryBINL (Private, OfferIx)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return Release (Private);
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryFinishProxyBINL (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   INTN  Index;
 | |
| 
 | |
|   for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) {
 | |
|     if (TryBINL (Private, Private->BinlProxies[Index])) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Release (Private);
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // try to finish DORA - send DHCP request, wait for ACK, check with ARP
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryFinishDORA (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                OfferIx
 | |
|   )
 | |
| {
 | |
|   DHCP_RECEIVE_BUFFER *DhcpRxBuf;
 | |
|   EFI_IP_ADDRESS      ClientIp;
 | |
|   EFI_IP_ADDRESS      ServerIp;
 | |
|   EFI_STATUS          StatCode;
 | |
|   UNION_PTR           LocalPtr;
 | |
|   EFI_EVENT           TimeoutEvent;
 | |
| 
 | |
|   //
 | |
|   // send DHCP request
 | |
|   // if fail return false
 | |
|   //
 | |
|   DhcpRxBuf = &DHCPV4_ACK_BUFFER;
 | |
|   DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type  = DHCPREQUEST;
 | |
|   CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (DHCP_REQ_OPTIONS));
 | |
|   DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[OfferIx].u.Dhcpv4.yiaddr;
 | |
| 
 | |
|   CopyMem (
 | |
|     &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
 | |
|     &((DHCPV4_OP_SERVER_IP *) RxBuf[OfferIx].OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
 | |
|     sizeof DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip
 | |
|     );
 | |
| 
 | |
|   CopyMem (
 | |
|     Private->EfiBc.Mode->SubnetMask.Addr,
 | |
|     &DefaultSubnetMask,
 | |
|     4
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // broadcast DHCPREQUEST
 | |
|   //
 | |
|   if (DoUdpWrite (
 | |
|         Private,
 | |
|         &BroadcastIP,
 | |
|         &DhcpServerPort,
 | |
|         (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
 | |
|         &DHCPClientPort
 | |
|         ) != EFI_SUCCESS) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   //
 | |
|   //
 | |
|   StatCode = gBS->CreateEvent (
 | |
|                     EVT_TIMER,
 | |
|                     TPL_CALLBACK,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     &TimeoutEvent
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (StatCode)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   StatCode = gBS->SetTimer (
 | |
|                     TimeoutEvent,
 | |
|                     TimerPeriodic,
 | |
|                     Private->Timeout * 10000000 + 1000000
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (StatCode)) {
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // wait for ACK
 | |
|   //
 | |
|   for (;;) {
 | |
|     if (GetOfferAck (
 | |
|           Private,
 | |
|           DHCPAckEdit,
 | |
|           EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,
 | |
|           &ServerIp,
 | |
|           &DhcpServerPort,
 | |
|           &ClientIp,
 | |
|           &DHCPClientPort,
 | |
|           DhcpRxBuf,
 | |
|           TimeoutEvent
 | |
|           ) != EFI_SUCCESS) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // check type of response - need DHCPACK
 | |
|     //
 | |
|     if (CompareMem (
 | |
|           &DHCP_REQ_OPTIONS.OpReqIP.Ip,
 | |
|           &DhcpRxBuf->u.Dhcpv4.yiaddr,
 | |
|           sizeof (EFI_IPv4_ADDRESS)
 | |
|           ) || CompareMem (
 | |
|           &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
 | |
|           &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
 | |
|           sizeof (EFI_IPv4_ADDRESS)
 | |
|           )) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // got ACK
 | |
|     // check with ARP that IP unused - good return true
 | |
|     //
 | |
|     if (!SetStationIP (Private)) {
 | |
|       //
 | |
|       // fail - send DHCPDECLINE and return false
 | |
|       //
 | |
|       DeclineOffer (Private);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     LocalPtr.OpPtr = DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
 | |
| 
 | |
|     if (LocalPtr.OpPtr != NULL) {
 | |
|       CopyMem (
 | |
|         (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask,
 | |
|         &LocalPtr.SubnetMaskStr->Ip,
 | |
|         sizeof (EFI_IPv4_ADDRESS)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     AddRouters (Private, DhcpRxBuf);
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (TimeoutEvent);
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // try a DHCP server of appropriate type
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryDHCPFinishDORA (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                TypeIx
 | |
|   )
 | |
| {
 | |
|   INTN  Index;
 | |
| 
 | |
|   //
 | |
|   // go through the DHCP servers of the requested type
 | |
|   //
 | |
|   for (Index = 0; Index < Private->ServerCount[TypeIx]; ++Index) {
 | |
|     if (TryFinishDORA (Private, Index = Private->OfferCount[TypeIx][Index])) {
 | |
|       if (TypeIx == BINL_IX && !TryFinishBINL (Private, Index)) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // try a DHCP only server and a proxy of appropriate type
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryProxyFinishDORA (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   INTN                TypeIx
 | |
|   )
 | |
| {
 | |
|   INTN  Index;
 | |
| 
 | |
|   if (!Private->GotProxy[TypeIx]) {
 | |
|     //
 | |
|     // no proxies of the type wanted
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // go through the DHCP only servers
 | |
|   //
 | |
|   for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
 | |
|     if (TryFinishDORA (Private, Private->OfferCount[DHCP_ONLY_IX][Index])) {
 | |
|       if (TypeIx != BINL_IX) {
 | |
|         CopyProxyRxBuf (Private, Private->GotProxy[TypeIx] - 1);
 | |
|       } else if (!TryFinishProxyBINL (Private)) {
 | |
|         //
 | |
|         // if didn't work with this DHCP, won't work with any
 | |
|         //
 | |
|         return FALSE;
 | |
|       }
 | |
| 
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // getting to the bottom of the barrel
 | |
| //
 | |
| STATIC
 | |
| BOOLEAN
 | |
| TryAnyWithBootfileFinishDORA (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // try a DHCP only server who has a bootfile
 | |
|   //
 | |
|   UNION_PTR LocalPtr;
 | |
|   INTN      Index;
 | |
| 
 | |
|   for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
 | |
|     INTN  offer;
 | |
| 
 | |
|     offer = Private->OfferCount[DHCP_ONLY_IX][Index];
 | |
| 
 | |
|     if (RxBuf[offer].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && TryFinishDORA (Private, offer)) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // really at bottom - see if be have any bootps
 | |
|   //
 | |
|   if (!Private->GotBootp) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[Private->GotBootp - 1].u.Dhcpv4.yiaddr;
 | |
| 
 | |
|   if (!SetStationIP (Private)) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // treat BOOTP response as DHCP ACK packet
 | |
|   //
 | |
|   CopyParseRxBuf (Private, Private->GotBootp - 1, DHCPV4_ACK_INDEX);
 | |
| 
 | |
|   LocalPtr.OpPtr = RxBuf[Private->GotBootp - 1].OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
 | |
| 
 | |
|   if (LocalPtr.OpPtr != NULL) {
 | |
|     *(EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask = LocalPtr.SubnetMaskStr->Ip;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /* DoDhcpDora()
 | |
|  */
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| DoDhcpDora (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   BOOLEAN             SortOffers
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_IP_FILTER Filter;
 | |
|   EFI_STATUS                  StatCode;
 | |
|   INTN                        NumOffers;
 | |
| 
 | |
|   Filter.Filters  = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
 | |
| 
 | |
|   Filter.IpCnt    = 0;
 | |
|   Filter.reserved = 0;
 | |
| 
 | |
|   //
 | |
|   // set filter unicast or broadcast
 | |
|   //
 | |
|   if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
 | |
|     return StatCode;
 | |
|   }
 | |
|   //
 | |
|   // seed random number with hardware address
 | |
|   //
 | |
|   SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
 | |
| 
 | |
|   for (Private->Timeout = 1;
 | |
|        Private->Timeout < 17;
 | |
|        Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), Private->Timeout <<= 1
 | |
|       ) {
 | |
|     INTN  Index;
 | |
| 
 | |
|     InitDhcpv4TxBuf (Private);
 | |
|     DHCPV4_TRANSMIT_BUFFER.xid  = Random (Private);
 | |
|     DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
 | |
| 
 | |
|     //
 | |
|     // broadcast DHCPDISCOVER
 | |
|     //
 | |
|     StatCode = DoUdpWrite (
 | |
|                 Private,
 | |
|                 &BroadcastIP,
 | |
|                 &DhcpServerPort,
 | |
|                 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
 | |
|                 &DHCPClientPort
 | |
|                 );
 | |
| 
 | |
|     if (StatCode != EFI_SUCCESS) {
 | |
|       return StatCode;
 | |
|     }
 | |
| 
 | |
|     CopyMem (
 | |
|       &Private->EfiBc.Mode->DhcpDiscover,
 | |
|       (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
 | |
|       sizeof (EFI_PXE_BASE_CODE_PACKET)
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // get DHCPOFFER's
 | |
|     //
 | |
|     if ((StatCode = GetOffers (Private)) != EFI_SUCCESS) {
 | |
|       if (StatCode != EFI_NO_RESPONSE) {
 | |
|         return StatCode;
 | |
|       }
 | |
| 
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // select offer and reply DHCPREQUEST
 | |
|     //
 | |
|     if (SortOffers) {
 | |
|       if (TryDHCPFinishDORA(Private, PXE10_IX) || // try DHCP with PXE10
 | |
|         TryDHCPFinishDORA(Private, WfM11a_IX)  || // no - try with WfM
 | |
|         TryProxyFinishDORA(Private, PXE10_IX)  || // no - try DHCP only and proxy with PXE10
 | |
|         TryProxyFinishDORA(Private, WfM11a_IX) || // no - try DHCP only and proxy with WfM
 | |
|         TryDHCPFinishDORA(Private, BINL_IX)    || // no - try with WfM
 | |
|         TryProxyFinishDORA(Private, BINL_IX)   || // no - try DHCP only and proxy with PXE10
 | |
|         TryAnyWithBootfileFinishDORA(Private))
 | |
|       {
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // FIFO order
 | |
|     //
 | |
|     NumOffers = Private->NumOffersReceived;
 | |
| 
 | |
|     for (Index = 0; Index < NumOffers; ++Index) {
 | |
|       //
 | |
|       // ignore proxies
 | |
|       //
 | |
|       if (!RxBuf[Index].u.Dhcpv4.yiaddr) {
 | |
|         continue;
 | |
|       }
 | |
|       //
 | |
|       // check if a bootp server
 | |
|       //
 | |
|       if (!RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]) {
 | |
|         //
 | |
|         // it is - just check ARP
 | |
|         //
 | |
|         if (!SetStationIP (Private)) {
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // else check if a DHCP only server
 | |
|       //
 | |
|       else if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE))) {
 | |
|         //
 | |
|         // it is a normal DHCP offer (without any PXE options), just finish the D.O.R.A by sending DHCP request.
 | |
|         //
 | |
|         if (!TryFinishDORA (Private, Index)) {
 | |
|           continue;
 | |
|         }
 | |
|       } else if (TryFinishDORA (Private, Index)) {
 | |
|         if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) && !TryFinishBINL (Private, Index)) {
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       DEBUG ((DEBUG_WARN, "\nDoDhcpDora()  Got packets.  "));
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // now look for DHCP onlys and a Proxy
 | |
|     //
 | |
|     for (Index = 0; Index < NumOffers; ++Index) {
 | |
|       INTN  Index2;
 | |
| 
 | |
|       //
 | |
|       // ignore proxies, bootps, non DHCP onlys, and bootable DHCPS
 | |
|       //
 | |
|       if (!RxBuf[Index].u.Dhcpv4.yiaddr ||
 | |
|           !RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1] ||
 | |
|           RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE) ||
 | |
|           RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
 | |
|           ) {
 | |
|         continue;
 | |
|       }
 | |
|       //
 | |
|       // found non bootable DHCP only - try to find a proxy
 | |
|       //
 | |
|       for (Index2 = 0; Index2 < NumOffers; ++Index2) {
 | |
|         if (!RxBuf[Index2].u.Dhcpv4.yiaddr) {
 | |
|           if (!TryFinishDORA (Private, Index)) {
 | |
|             //
 | |
|             // DHCP no ACK
 | |
|             //
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (RxBuf[Index2].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) {
 | |
|             CopyProxyRxBuf (Private, Index2);
 | |
|           } else if (!TryFinishBINL (Private, Index2)) {
 | |
|             continue;
 | |
|           }
 | |
| 
 | |
|           DEBUG ((DEBUG_WARN, "\nDoDhcpDora()  Got packets.  "));
 | |
|           return EFI_SUCCESS;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NO_RESPONSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| //
 | |
| // determine if the server ip is in the ip list
 | |
| //
 | |
| BOOLEAN
 | |
| InServerList (
 | |
|   EFI_IP_ADDRESS    *ServerIpPtr,
 | |
|   PXE_SERVER_LISTS  *ServerListPtr
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
| 
 | |
|   if (!ServerListPtr || !ServerListPtr->Ipv4List.IpCount) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
 | |
|     if (!CompareMem (
 | |
|           ServerIpPtr,
 | |
|           &ServerListPtr->Ipv4List.IpList[Index],
 | |
|           sizeof (EFI_IPv4_ADDRESS)
 | |
|           )) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| BOOLEAN
 | |
| ExtractBootServerList (
 | |
|   UINT16            Type,
 | |
|   DHCPV4_OP_STRUCT  *ptr,
 | |
|   PXE_SERVER_LISTS  **ServerListPtr
 | |
|   )
 | |
| {
 | |
|   UNION_PTR LocalPtr;
 | |
|   INTN      ServerListLen;
 | |
| 
 | |
|   LocalPtr.OpPtr  = ptr;
 | |
|   ServerListLen   = LocalPtr.BootServersStr->Header.Length;
 | |
| 
 | |
|   //
 | |
|   // find type
 | |
|   //
 | |
|   LocalPtr.BootServerList = LocalPtr.BootServersStr->ServerList;
 | |
| 
 | |
|   while (ServerListLen) {
 | |
|     INTN  ServerEntryLen;
 | |
| 
 | |
|     ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (LocalPtr.BootServerList->u.Ipv4List.IpCount - 1) *
 | |
|     sizeof (EFI_IPv4_ADDRESS);
 | |
| 
 | |
|     if (NTOHS (LocalPtr.BootServerList->Type) == Type) {
 | |
|       *ServerListPtr = &LocalPtr.BootServerList->u;
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|     (LocalPtr.BytePtr) += ServerEntryLen;
 | |
|     ServerListLen -= ServerEntryLen;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| VOID
 | |
| FreeMem (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   if (Private->TransmitBuffer != NULL) {
 | |
|     gBS->FreePool (Private->TransmitBuffer);
 | |
|     Private->TransmitBuffer = NULL;
 | |
|   }
 | |
| 
 | |
|   if (Private->ReceiveBuffers != NULL) {
 | |
|     gBS->FreePool (Private->ReceiveBuffers);
 | |
|     Private->ReceiveBuffers = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| BOOLEAN
 | |
| GetMem (
 | |
|   PXE_BASECODE_DEVICE *Private
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (Private->DhcpPacketBuffer == NULL) {
 | |
|     Status = gBS->AllocatePool (
 | |
|                     EfiBootServicesData,
 | |
|                     sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
 | |
|                     &Private->DhcpPacketBuffer
 | |
|                     );
 | |
| 
 | |
|     if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
 | |
|       Private->DhcpPacketBuffer = NULL;
 | |
|       FreeMem (Private);
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiBootServicesData,
 | |
|                   sizeof (EFI_PXE_BASE_CODE_PACKET),
 | |
|                   &Private->TransmitBuffer
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status) || Private->TransmitBuffer == NULL) {
 | |
|     gBS->FreePool (Private->DhcpPacketBuffer);
 | |
|     Private->DhcpPacketBuffer = NULL;
 | |
|     Private->TransmitBuffer   = NULL;
 | |
|     FreeMem (Private);
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiBootServicesData,
 | |
|                   sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS),
 | |
|                   &Private->ReceiveBuffers
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status) || Private->ReceiveBuffers == NULL) {
 | |
|     gBS->FreePool (Private->TransmitBuffer);
 | |
|     gBS->FreePool (Private->DhcpPacketBuffer);
 | |
|     Private->DhcpPacketBuffer = NULL;
 | |
|     Private->TransmitBuffer   = NULL;
 | |
|     Private->ReceiveBuffers   = NULL;
 | |
|     FreeMem (Private);
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /**
 | |
| 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BcDhcp (
 | |
|   IN EFI_PXE_BASE_CODE_PROTOCOL *This,
 | |
|   IN BOOLEAN                    SortOffers
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_IP_FILTER Filter;
 | |
|   EFI_PXE_BASE_CODE_MODE      *PxebcMode;
 | |
|   PXE_BASECODE_DEVICE         *Private;
 | |
|   EFI_STATUS                  StatCode;
 | |
| 
 | |
|   //
 | |
|   // 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 pointer == 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;
 | |
|   }
 | |
| 
 | |
|   Filter.Filters  = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
 | |
|   Filter.IpCnt    = 0;
 | |
|   Filter.reserved = 0;
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "\nBcDhcp()  Enter.  "));
 | |
| 
 | |
|   PxebcMode = Private->EfiBc.Mode;
 | |
| 
 | |
|   if (!GetMem (Private)) {
 | |
|     DEBUG ((DEBUG_ERROR, "\nBcDhcp()  GetMem() failed.\n"));
 | |
|     EfiReleaseLock (&Private->Lock);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   PxebcMode->DhcpDiscoverValid = FALSE;
 | |
|   PxebcMode->DhcpAckReceived = FALSE;
 | |
|   PxebcMode->ProxyOfferReceived = FALSE;
 | |
| 
 | |
|   Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
 | |
| 
 | |
|   //
 | |
|   // Issue BC command
 | |
|   //
 | |
|   if (Private->TotalSeconds == 0) {
 | |
|     //
 | |
|     // put in seconds field of DHCP send packets
 | |
|     //
 | |
|     Private->TotalSeconds = 4;
 | |
|   }
 | |
| 
 | |
|   if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) {
 | |
|     //
 | |
|     // success - copy packets
 | |
|     //
 | |
|     PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE;
 | |
| 
 | |
|     CopyMem (
 | |
|       &PxebcMode->DhcpAck,
 | |
|       (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET,
 | |
|       sizeof (EFI_PXE_BASE_CODE_PACKET)
 | |
|       );
 | |
| 
 | |
|     if (PxebcMode->ProxyOfferReceived) {
 | |
|       CopyMem (
 | |
|         &PxebcMode->ProxyOffer,
 | |
|         (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET,
 | |
|         sizeof (EFI_PXE_BASE_CODE_PACKET)
 | |
|         );
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // set filter back to unicast
 | |
|   //
 | |
|   IpFilter (Private, &Filter);
 | |
| 
 | |
|   FreeMem (Private);
 | |
| 
 | |
|   //
 | |
|   // Unlock the instance data
 | |
|   //
 | |
|   DEBUG ((DEBUG_WARN, "\nBcDhcp()  Exit = %xh  ", StatCode));
 | |
| 
 | |
|   EfiReleaseLock (&Private->Lock);
 | |
|   return StatCode;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| STATIC
 | |
| BOOLEAN
 | |
| VerifyCredentialOption (
 | |
|   UINT8 *tx,
 | |
|   UINT8 *rx
 | |
|   )
 | |
| {
 | |
|   UINTN n;
 | |
| 
 | |
|   //
 | |
|   // Fail verification if either pointer is NULL.
 | |
|   //
 | |
|   if (tx == NULL || rx == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // Fail verification if tx[0] is not a credential type option
 | |
|   // or if the length is zero or not a multiple of four.
 | |
|   //
 | |
|   if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // Fail verification if rx[0] is not a credential type option
 | |
|   // or if the length is not equal to four.
 | |
|   //
 | |
|   if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // Look through transmitted credential types for a copy
 | |
|   // of the received credential type.
 | |
|   //
 | |
|   for (n = 0; n < tx[1]; n += 4) {
 | |
|     if (!CompareMem (&tx[n + 2], &rx[2], 4)) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /**
 | |
| 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DoDiscover (
 | |
|   PXE_BASECODE_DEVICE *Private,
 | |
|   UINT16              OpFlags,
 | |
|   IN UINT16           Type,
 | |
|   IN UINT16           *LayerPtr,
 | |
|   IN BOOLEAN          UseBis,
 | |
|   EFI_IP_ADDRESS      *DestPtr,
 | |
|   PXE_SERVER_LISTS    *ServerListPtr
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  ClientPort;
 | |
|   EFI_PXE_BASE_CODE_UDP_PORT  ServerPort;
 | |
|   EFI_PXE_BASE_CODE_MODE      *PxebcMode;
 | |
|   EFI_STATUS                  StatCode;
 | |
|   EFI_EVENT                   TimeoutEvent;
 | |
|   UINT8                       OpLen;
 | |
| 
 | |
|   PxebcMode = Private->EfiBc.Mode;
 | |
| 
 | |
|   if (DestPtr->Addr[0] == 0) {
 | |
|     DEBUG ((DEBUG_WARN, "\nDoDiscover()  !DestPtr->Addr[0]"));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // seed random number with hardware address
 | |
|   //
 | |
|   SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
 | |
| 
 | |
|   if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) {
 | |
|     ClientPort  = DHCPClientPort;
 | |
|     ServerPort  = DhcpServerPort;
 | |
|   } else {
 | |
|     ClientPort  = PSEUDO_DHCP_CLIENT_PORT;
 | |
|     ServerPort  = PseudoDhcpServerPort;
 | |
|   }
 | |
| 
 | |
|   if (UseBis) {
 | |
|     *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG;
 | |
|   } else {
 | |
|     *LayerPtr &= PXE_BOOT_LAYER_MASK;
 | |
|   }
 | |
| 
 | |
|   for (Private->Timeout = 1;
 | |
|        Private->Timeout < 5;
 | |
|        Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout
 | |
|       ) {
 | |
|     InitDhcpv4TxBuf (Private);
 | |
|     //
 | |
|     // initialize DHCP message structure
 | |
|     //
 | |
|     DHCPV4_TRANSMIT_BUFFER.xid  = Random (Private);
 | |
|     DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
 | |
|     CopyMem (
 | |
|       &DHCPV4_TRANSMIT_BUFFER.ciaddr,
 | |
|       &PxebcMode->StationIp,
 | |
|       sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr
 | |
|       );
 | |
| 
 | |
|     DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type  = DHCPREQUEST;
 | |
|     DISCOVERoptions.Header.OpCode               = OP_VENDOR_SPECIFIC;
 | |
|     DISCOVERoptions.BootItem.Header.OpCode      = VEND_PXE_BOOT_ITEM;
 | |
|     DISCOVERoptions.BootItem.Header.Length      = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM);
 | |
|     DISCOVERoptions.BootItem.Type               = HTONS (Type);
 | |
|     DISCOVERoptions.BootItem.Layer              = HTONS (*LayerPtr);
 | |
| 
 | |
|     if (UseBis) {
 | |
|       EFI_BIS_PROTOCOL        *BisPtr;
 | |
|       BIS_APPLICATION_HANDLE  BisAppHandle;
 | |
|       EFI_BIS_DATA            *BisDataSigInfo;
 | |
|       EFI_BIS_SIGNATURE_INFO  *BisSigInfo;
 | |
|       UINTN                   Index;
 | |
|       UINTN                   Index2;
 | |
| 
 | |
|       BisPtr = PxebcBisStart (
 | |
|                 Private,
 | |
|                 &BisAppHandle,
 | |
|                 &BisDataSigInfo
 | |
|                 );
 | |
| 
 | |
|       if (BisPtr == NULL) {
 | |
|         //
 | |
|         // %%TBD - In order to get here, BIS must have
 | |
|         // been present when PXEBC.Start() was called.
 | |
|         // BIS had to be shutdown/removed/damaged
 | |
|         // before PXEBC.Discover() was called.
 | |
|         // Do we need to document a specific error
 | |
|         // for this case?
 | |
|         //
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|       //
 | |
|       // Compute number of credential types.
 | |
|       //
 | |
|       Index2                        = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO);
 | |
| 
 | |
|       DISCREDoptions.Header.OpCode  = VEND_PXE_CREDENTIAL_TYPES;
 | |
| 
 | |
|       DISCREDoptions.Header.Length  = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL));
 | |
| 
 | |
|       OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length);
 | |
| 
 | |
|       BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data;
 | |
| 
 | |
|       for (Index = 0; Index < Index2; ++Index) {
 | |
|         UINT32  x;
 | |
| 
 | |
|         CopyMem (&x, &BisSigInfo[Index], sizeof x);
 | |
|         x = HTONL (x);
 | |
|         CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x);
 | |
|       }
 | |
| 
 | |
|       PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
 | |
|     } else {
 | |
|       OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS);
 | |
|     }
 | |
| 
 | |
|     DISCOVERoptions.Header.Length = OpLen;
 | |
| 
 | |
|     ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END;
 | |
|     ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen]     = OP_END;
 | |
| 
 | |
|     StatCode = DoUdpWrite (
 | |
|                 Private,
 | |
|                 DestPtr,
 | |
|                 &ServerPort,
 | |
|                 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
 | |
|                 &ClientPort
 | |
|                 );
 | |
| 
 | |
|     if (StatCode != EFI_SUCCESS) {
 | |
|       return StatCode;
 | |
|     }
 | |
|     //
 | |
|     //
 | |
|     //
 | |
|     StatCode = gBS->CreateEvent (
 | |
|                       EVT_TIMER,
 | |
|                       TPL_CALLBACK,
 | |
|                       NULL,
 | |
|                       NULL,
 | |
|                       &TimeoutEvent
 | |
|                       );
 | |
| 
 | |
|     if (EFI_ERROR (StatCode)) {
 | |
|       return StatCode;
 | |
|     }
 | |
| 
 | |
|     StatCode = gBS->SetTimer (
 | |
|                       TimeoutEvent,
 | |
|                       TimerRelative,
 | |
|                       Private->Timeout * 10000000 + 1000000
 | |
|                       );
 | |
| 
 | |
|     if (EFI_ERROR (StatCode)) {
 | |
|       gBS->CloseEvent (TimeoutEvent);
 | |
|       return StatCode;
 | |
|     }
 | |
|     //
 | |
|     // wait for ACK
 | |
|     //
 | |
|     for (;;) {
 | |
|       DHCP_RECEIVE_BUFFER *RxBufPtr;
 | |
|       UINT16              TmpType;
 | |
|       UINT16              TmpLayer;
 | |
| 
 | |
|       RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER;
 | |
|       ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
 | |
| 
 | |
|       if (GetOfferAck (
 | |
|             Private,
 | |
|             AckEdit,
 | |
|             OpFlags,
 | |
|             (EFI_IP_ADDRESS *) &Private->ServerIp,
 | |
|             0,
 | |
|             (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
 | |
|             &ClientPort,
 | |
|             RxBufPtr,
 | |
|             TimeoutEvent
 | |
|             ) != EFI_SUCCESS) {
 | |
|         break;
 | |
|       }
 | |
|       //
 | |
|       // check type of response - need PXEClient DHCPACK of proper type with bootfile
 | |
|       //
 | |
|       if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) ||
 | |
|           (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) ||
 | |
|           !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] ||
 | |
|           !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] ||
 | |
|           !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) {
 | |
| 
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       TmpType = TmpLayer = 0;
 | |
| 
 | |
|       if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
 | |
|         TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type);
 | |
| 
 | |
|         if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) {
 | |
|           TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8);
 | |
|         } else {
 | |
|           TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (TmpType != Type) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       if (UseBis) {
 | |
|         if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         if (!VerifyCredentialOption (
 | |
|               (UINT8 *) &DISCREDoptions.Header,
 | |
|               (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]
 | |
|               )) {
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       *LayerPtr = TmpLayer;
 | |
| 
 | |
|       if (UseBis) {
 | |
|         CopyMem (
 | |
|           &PxebcMode->PxeBisReply,
 | |
|           &RxBufPtr->u.Dhcpv4,
 | |
|           sizeof (EFI_PXE_BASE_CODE_PACKET)
 | |
|           );
 | |
| 
 | |
|         PxebcMode->PxeBisReplyReceived = TRUE;
 | |
| 
 | |
|         StatCode = DoDiscover (
 | |
|                     Private,
 | |
|                     EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|                     Type,
 | |
|                     LayerPtr,
 | |
|                     FALSE,
 | |
|                     &Private->ServerIp,
 | |
|                     0
 | |
|                     );
 | |
| 
 | |
|         gBS->CloseEvent (TimeoutEvent);
 | |
|         return StatCode;
 | |
|       }
 | |
| 
 | |
|       PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE;
 | |
| 
 | |
|       CopyMem (
 | |
|         &PxebcMode->PxeDiscover,
 | |
|         &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
 | |
|         sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER)
 | |
|         );
 | |
| 
 | |
|       CopyMem (
 | |
|         &PxebcMode->PxeReply,
 | |
|         &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4,
 | |
|         sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4)
 | |
|         );
 | |
| 
 | |
|       AddRouters (Private, RxBufPtr);
 | |
| 
 | |
|       gBS->CloseEvent (TimeoutEvent);
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     gBS->CloseEvent (TimeoutEvent);
 | |
|   }
 | |
|   //
 | |
|   // end for loop
 | |
|   //
 | |
|   return EFI_TIMEOUT;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /**
 | |
|   Parameters:
 | |
|   Private := Pointer to PxeBc interface
 | |
|   Type :=
 | |
|   LayerPtr :=
 | |
|   UseBis :=
 | |
|   DiscoverInfoPtr :=
 | |
|   McastServerListPtr :=
 | |
|   ServerListPtr :=
 | |
| 
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| Discover (
 | |
|   PXE_BASECODE_DEVICE                 *Private,
 | |
|   IN UINT16                           Type,
 | |
|   IN UINT16                           *LayerPtr,
 | |
|   IN BOOLEAN                          UseBis,
 | |
|   IN EFI_PXE_BASE_CODE_DISCOVER_INFO  *DiscoverInfoPtr,
 | |
|   PXE_SERVER_LISTS                    *McastServerListPtr,
 | |
|   PXE_SERVER_LISTS                    *ServerListPtr
 | |
|   )
 | |
| {
 | |
|   EFI_IP_ADDRESS  DestIp;
 | |
|   EFI_STATUS      StatCode;
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "\nDiscover()  Type=%d  Layer=%d  ", Type, *LayerPtr));
 | |
| 
 | |
|   if (UseBis) {
 | |
|     DEBUG ((DEBUG_INFO, "BIS  "));
 | |
|   }
 | |
|   //
 | |
|   // get dest IP addr - mcast, bcast, or unicast
 | |
|   //
 | |
|   if (DiscoverInfoPtr->UseMCast) {
 | |
|     DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4;
 | |
| 
 | |
|     DEBUG (
 | |
|       (DEBUG_INFO,
 | |
|       "\nDiscover()  MCast %d.%d.%d.%d  ",
 | |
|       DestIp.v4.Addr[0],
 | |
|       DestIp.v4.Addr[1],
 | |
|       DestIp.v4.Addr[2],
 | |
|       DestIp.v4.Addr[3])
 | |
|       );
 | |
| 
 | |
|     if ((StatCode = DoDiscover (
 | |
|                       Private,
 | |
|                       EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|                       Type,
 | |
|                       LayerPtr,
 | |
|                       UseBis,
 | |
|                       &DestIp,
 | |
|                       McastServerListPtr
 | |
|                       )) != EFI_TIMEOUT) {
 | |
|       DEBUG (
 | |
|         (DEBUG_WARN,
 | |
|         "\nDiscover()  status == %r (%Xh)",
 | |
|         StatCode,
 | |
|         StatCode)
 | |
|         );
 | |
| 
 | |
|       return StatCode;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (DiscoverInfoPtr->UseBCast) {
 | |
|     DEBUG ((DEBUG_INFO, "\nDiscver()  BCast  "));
 | |
| 
 | |
|     if ((StatCode = DoDiscover (
 | |
|                       Private,
 | |
|                       EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|                       Type,
 | |
|                       LayerPtr,
 | |
|                       UseBis,
 | |
|                       &BroadcastIP,
 | |
|                       McastServerListPtr
 | |
|                       )) != EFI_TIMEOUT) {
 | |
| 
 | |
|       DEBUG ((DEBUG_WARN, "\nDiscover()  status == %r (%Xh)", StatCode, StatCode));
 | |
| 
 | |
|       return StatCode;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (DiscoverInfoPtr->UseUCast) {
 | |
|     UINTN Index;
 | |
| 
 | |
|     DEBUG (
 | |
|       (DEBUG_INFO,
 | |
|       "\nDiscover()  UCast  IP#=%d  ",
 | |
|       ServerListPtr->Ipv4List.IpCount)
 | |
|       );
 | |
| 
 | |
|     for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
 | |
|       CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4);
 | |
| 
 | |
|       DEBUG (
 | |
|         (DEBUG_INFO,
 | |
|         "\nDiscover()  UCast %d.%d.%d.%d  ",
 | |
|         DestIp.v4.Addr[0],
 | |
|         DestIp.v4.Addr[1],
 | |
|         DestIp.v4.Addr[2],
 | |
|         DestIp.v4.Addr[3])
 | |
|         );
 | |
| 
 | |
|       if ((StatCode = DoDiscover (
 | |
|                         Private,
 | |
|                         EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
 | |
|                         Type,
 | |
|                         LayerPtr,
 | |
|                         UseBis,
 | |
|                         &DestIp,
 | |
|                         0
 | |
|                         )) != EFI_TIMEOUT) {
 | |
|         DEBUG (
 | |
|           (DEBUG_WARN,
 | |
|           "\nDiscover()  status == %r (%Xh)",
 | |
|           StatCode,
 | |
|           StatCode)
 | |
|           );
 | |
| 
 | |
|         return StatCode;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_WARN, "\nDiscover()  TIMEOUT"));
 | |
| 
 | |
|   return EFI_TIMEOUT;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /* BcDiscover()
 | |
|  */
 | |
| 
 | |
| /**
 | |
| 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BcDiscover (
 | |
|   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
 | |
|   IN UINT16                           Type,
 | |
|   IN UINT16                           *LayerPtr,
 | |
|   IN BOOLEAN                          UseBis,
 | |
|   IN EFI_PXE_BASE_CODE_DISCOVER_INFO  * DiscoverInfoPtr OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
 | |
|   EFI_PXE_BASE_CODE_MODE          *PxebcMode;
 | |
|   DHCP_RECEIVE_BUFFER             *DhcpRxBuf;
 | |
|   PXE_SERVER_LISTS                DefaultSrvList;
 | |
|   PXE_SERVER_LISTS                *ServerListPtr;
 | |
|   PXE_SERVER_LISTS                *McastServerListPtr;
 | |
|   UNION_PTR                       LocalPtr;
 | |
|   UINTN                           Index;
 | |
|   UINTN                           Index2;
 | |
|   BOOLEAN                         AcquiredSrvList;
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   ServerListPtr       = NULL;
 | |
|   McastServerListPtr  = NULL;
 | |
|   AcquiredSrvList     = FALSE;
 | |
| 
 | |
|   PxebcMode           = Private->EfiBc.Mode;
 | |
| 
 | |
|   if (!GetMem (Private)) {
 | |
|     EfiReleaseLock (&Private->Lock);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   if (UseBis) {
 | |
|     if (!PxebcMode->BisSupported) {
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
 | |
| 
 | |
|   if (Private->TotalSeconds == 0) {
 | |
|     //
 | |
|     // put in seconds field of DHCP send packets
 | |
|     //
 | |
|     Private->TotalSeconds = 4;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
 | |
| 
 | |
|   //
 | |
|   // if layer number not zero, use previous discover
 | |
|   //
 | |
|   if (*LayerPtr != 0) {
 | |
|     DEBUG ((DEBUG_WARN, "\nBcDiscover()  layer != 0"));
 | |
| 
 | |
|     if (DiscoverInfoPtr != NULL) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  layer != 0 && DiscoverInfoPtr != NULL\n"));
 | |
| 
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (!PxebcMode->PxeDiscoverValid) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  layer != 0 && PxeDiscoverValid == 0\n"));
 | |
| 
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (!PxebcMode->PxeReplyReceived) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  layer != 0 && PxeReplyReceived == 0\n"));
 | |
| 
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (UseBis && !PxebcMode->PxeBisReplyReceived) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  layer != 0 && PxeBisReplyReceived == 0\n"));
 | |
| 
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     DefaultInfo.UseUCast            = TRUE;
 | |
|     DiscoverInfoPtr                 = &DefaultInfo;
 | |
| 
 | |
|     DefaultSrvList.Ipv4List.IpCount = 1;
 | |
|     CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4);
 | |
| 
 | |
|     ServerListPtr = &DefaultSrvList;
 | |
|   }
 | |
|   //
 | |
|   // layer is zero - see if info is supplied or if we need to use info from a cached offer
 | |
|   //
 | |
|   else if (!DiscoverInfoPtr) {
 | |
|     //
 | |
|     // not supplied - generate it
 | |
|     // make sure that there is cached, appropriate information
 | |
|     // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail
 | |
|     //
 | |
|     DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
 | |
| 
 | |
|     if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  !ack && !proxy"));
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     DiscoverInfoPtr = &DefaultInfo;
 | |
| 
 | |
|     LocalPtr.OpPtr  = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
 | |
| 
 | |
|     //
 | |
|     // if multicast enabled, need multicast address
 | |
|     //
 | |
|     if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) {
 | |
|       DefaultInfo.UseMCast = TRUE;
 | |
| 
 | |
|       CopyMem (
 | |
|         ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp),
 | |
|         &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip,
 | |
|         sizeof (EFI_IPv4_ADDRESS)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     DefaultInfo.UseBCast    = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0);
 | |
| 
 | |
|     DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0);
 | |
| 
 | |
|     DefaultInfo.UseUCast = (BOOLEAN)
 | |
|       (
 | |
|         (DefaultInfo.MustUseList) ||
 | |
|         ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
 | |
|       );
 | |
| 
 | |
|     if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList (
 | |
|                                                               Type,
 | |
|                                                               DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1],
 | |
|                                                               &ServerListPtr
 | |
|                                                               )) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  type not in list"));
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Info supplied - make SrvList if required
 | |
|   // if we use ucast discovery or must use list, there better be one
 | |
|   //
 | |
|   else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) {
 | |
|     //
 | |
|     // there better be a list
 | |
|     //
 | |
|     if (DiscoverInfoPtr->IpCnt == 0) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  no bootserver list"));
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     //
 | |
|     // get its size
 | |
|     //
 | |
|     for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
 | |
|       if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
 | |
|         if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) {
 | |
|           if (Index2 != 0) {
 | |
|             DEBUG ((DEBUG_WARN, "\nBcDiscover()  accept any?"));
 | |
|             EfiReleaseLock (&Private->Lock);
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           } else {
 | |
|             Index2                          = 1;
 | |
|             DefaultSrvList.Ipv4List.IpCount = 0;
 | |
|             ServerListPtr                   = &DefaultSrvList;
 | |
|             break;
 | |
|           }
 | |
|         } else {
 | |
|           ++Index2;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (Index2 == 0) {
 | |
|       DEBUG ((DEBUG_WARN, "\nBcDiscover()  !Index2?"));
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (ServerListPtr == NULL) {
 | |
|       ServerListPtr = AllocatePool (
 | |
|                         sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS)
 | |
|                       );
 | |
| 
 | |
|       if (ServerListPtr == NULL) {
 | |
|         EfiReleaseLock (&Private->Lock);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|       //
 | |
|       // build an array of IP addresses from the server list
 | |
|       //
 | |
|       AcquiredSrvList                 = TRUE;
 | |
|       ServerListPtr->Ipv4List.IpCount = (UINT8) Index2;
 | |
| 
 | |
|       for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
 | |
|         if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
 | |
|           CopyMem (
 | |
|             &ServerListPtr->Ipv4List.IpList[Index2++],
 | |
|             &DiscoverInfoPtr->SrvList[Index].IpAddr.v4,
 | |
|             sizeof ServerListPtr->Ipv4List.IpList[0]
 | |
|             );
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (DiscoverInfoPtr->MustUseList) {
 | |
|     McastServerListPtr = ServerListPtr;
 | |
|   }
 | |
| 
 | |
|   if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) {
 | |
|     DEBUG ((DEBUG_WARN, "\nBcDiscover()  Nothing to use!\n"));
 | |
| 
 | |
|     EfiReleaseLock (&Private->Lock);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE;
 | |
| 
 | |
|   StatCode = Discover (
 | |
|               Private,
 | |
|               Type,
 | |
|               LayerPtr,
 | |
|               UseBis,
 | |
|               DiscoverInfoPtr,
 | |
|               McastServerListPtr,
 | |
|               ServerListPtr
 | |
|               );
 | |
| 
 | |
|   if (AcquiredSrvList) {
 | |
|     gBS->FreePool (ServerListPtr);
 | |
|   }
 | |
| 
 | |
|   FreeMem (Private);
 | |
| 
 | |
|   //
 | |
|   // Unlock the instance data
 | |
|   //
 | |
|   DEBUG (
 | |
|     (DEBUG_INFO,
 | |
|     "\nBcDiscover()  status == %r (%Xh)\n",
 | |
|     StatCode,
 | |
|     StatCode)
 | |
|     );
 | |
| 
 | |
|   EfiReleaseLock (&Private->Lock);
 | |
|   return StatCode;
 | |
| }
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| /**
 | |
| 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BcSetPackets (
 | |
|   IN EFI_PXE_BASE_CODE_PROTOCOL   * This,
 | |
|   BOOLEAN                         *NewDhcpDiscoverValid, OPTIONAL
 | |
|   BOOLEAN                         *NewDhcpAckReceived, OPTIONAL
 | |
|   BOOLEAN                         *NewProxyOfferReceived, OPTIONAL
 | |
|   BOOLEAN                         *NewPxeDiscoverValid, OPTIONAL
 | |
|   BOOLEAN                         *NewPxeReplyReceived, OPTIONAL
 | |
|   BOOLEAN                         *NewPxeBisReplyReceived, OPTIONAL
 | |
|   IN EFI_PXE_BASE_CODE_PACKET     * NewDhcpDiscover, OPTIONAL
 | |
|   IN EFI_PXE_BASE_CODE_PACKET     * NewDhcpAck, OPTIONAL
 | |
|   IN EFI_PXE_BASE_CODE_PACKET     * NewProxyOffer, OPTIONAL
 | |
|   IN EFI_PXE_BASE_CODE_PACKET     * NewPxeDiscover, OPTIONAL
 | |
|   IN EFI_PXE_BASE_CODE_PACKET     * NewPxeReply, OPTIONAL
 | |
|   IN EFI_PXE_BASE_CODE_PACKET     * NewPxeBisReply OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_MODE  *PxebcMode;
 | |
|   EFI_STATUS              Status;
 | |
|   PXE_BASECODE_DEVICE     *Private;
 | |
| 
 | |
|   //
 | |
|   // Lock the instance data and make sure started
 | |
|   //
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   PxebcMode = Private->EfiBc.Mode;
 | |
| 
 | |
|   if (Private->DhcpPacketBuffer == NULL) {
 | |
|     Status = gBS->AllocatePool (
 | |
|                     EfiBootServicesData,
 | |
|                     sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
 | |
|                     &Private->DhcpPacketBuffer
 | |
|                     );
 | |
| 
 | |
|     if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
 | |
|       Private->DhcpPacketBuffer = NULL;
 | |
|       EfiReleaseLock (&Private->Lock);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Issue BC command
 | |
|   //
 | |
|   //
 | |
|   // reset
 | |
|   //
 | |
|   Private->FileSize = 0;
 | |
|   if (NewDhcpDiscoverValid != NULL) {
 | |
|     PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
 | |
|   }
 | |
| 
 | |
|   if (NewDhcpAckReceived != NULL) {
 | |
|     PxebcMode->DhcpAckReceived = *NewDhcpAckReceived;
 | |
|   }
 | |
| 
 | |
|   if (NewProxyOfferReceived != NULL) {
 | |
|     PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived;
 | |
|   }
 | |
| 
 | |
|   if (NewPxeDiscoverValid != NULL) {
 | |
|     PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid;
 | |
|   }
 | |
| 
 | |
|   if (NewPxeReplyReceived != NULL) {
 | |
|     PxebcMode->PxeReplyReceived = *NewPxeReplyReceived;
 | |
|   }
 | |
| 
 | |
|   if (NewPxeBisReplyReceived != NULL) {
 | |
|     PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
 | |
|   }
 | |
| 
 | |
|   if (NewDhcpDiscover != NULL) {
 | |
|     CopyMem (
 | |
|       &PxebcMode->DhcpDiscover,
 | |
|       NewDhcpDiscover,
 | |
|       sizeof *NewDhcpDiscover
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   if (NewDhcpAck != NULL) {
 | |
|     CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX);
 | |
|   }
 | |
| 
 | |
|   if (NewProxyOffer != NULL) {
 | |
|     CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX);
 | |
|   }
 | |
| 
 | |
|   if (NewPxeDiscover != NULL) {
 | |
|     CopyMem (
 | |
|       &PxebcMode->PxeDiscover,
 | |
|       NewPxeDiscover,
 | |
|       sizeof *NewPxeDiscover
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   if (NewPxeReply != NULL) {
 | |
|     CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX);
 | |
|   }
 | |
| 
 | |
|   if (NewPxeBisReply != NULL) {
 | |
|     CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX);
 | |
|   }
 | |
|   //
 | |
|   // Unlock the instance data
 | |
|   //
 | |
|   EfiReleaseLock (&Private->Lock);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* eof - pxe_bc_dhcp.c */
 |