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