audk/MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_dhcp.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_STRUCTURE_TABLE *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_HEADER *) (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) {
INT8 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 */