/*++ Copyright (c) 2006 - 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" 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() /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC CHAR8 * PxeBcLibGetSmbiosString ( IN SMBIOS_STRUCTURE_POINTER *Smbios, IN UINT16 StringNumber ) /*++ Routine description: Return SMBIOS string given the string number. Arguments: Smbios - Pointer to SMBIOS structure StringNumber - String number to return. 0 is used to skip all strings and point to the next SMBIOS structure. Returns: Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0 --*/ { 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; } EFI_STATUS PxeBcLibGetSmbiosSystemGuidAndSerialNumber ( IN EFI_GUID *SystemGuid, OUT CHAR8 **SystemSerialNumber ) /*++ Routine Description: This function gets system guid and serial number from the smbios table Arguments: SystemGuid - The pointer of returned system guid SystemSerialNumber - The pointer of returned system serial number Returns: EFI_SUCCESS - Successfully get the system guid and system serial number EFI_NOT_FOUND - Not find the SMBIOS table --*/ { 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; } } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC 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); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC 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 // STATIC 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; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC BOOLEAN DHCPAckEdit ( DHCP_RECEIVE_BUFFER *RxBufPtr ) { return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // // get an offer/ack // STATIC 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 // STATIC 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 (struct requestopendstr)); // DHCPDECLINEoptions.OpDeclineEnd = DHCP_REQ_OPTIONS; { 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; DHCPV4_OP_SERVER_IP *Point; 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; Point = (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]; CopyMem ( &DHCPRELEASEoptions.DhcServerIpPtr, &Point, 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 (RequestOpEndStr)); // DHCP_REQ_OPTIONS = RequestOpEndStr; 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 ((EFI_D_WARN, "\nDoDhcpDora() Got packets. ")); return EFI_SUCCESS; } // // now look for DHCP onlys and a Proxy // for (Index = 0; Index < NumOffers; ++Index) { UINT8 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 ((EFI_D_WARN, "\nDoDhcpDora() Got packets. ")); return EFI_SUCCESS; } } } } return EFI_NO_RESPONSE; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // // determine if the server ip is in the ip list // STATIC 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; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC 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; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC VOID FreeMem ( PXE_BASECODE_DEVICE *Private ) { if (Private->TransmitBuffer != NULL) { FreePool (Private->TransmitBuffer); Private->TransmitBuffer = NULL; } if (Private->ReceiveBuffers != NULL) { FreePool (Private->ReceiveBuffers); Private->ReceiveBuffers = NULL; } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC BOOLEAN GetMem ( PXE_BASECODE_DEVICE *Private ) { if (Private->DhcpPacketBuffer == NULL) { Private->DhcpPacketBuffer = AllocatePool (sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1)); if (Private->DhcpPacketBuffer == NULL) { FreeMem (Private); return FALSE; } } Private->TransmitBuffer = AllocatePool (sizeof (EFI_PXE_BASE_CODE_PACKET)); if (Private->TransmitBuffer == NULL) { FreePool (Private->DhcpPacketBuffer); Private->DhcpPacketBuffer = NULL; FreeMem (Private); return FALSE; } Private->ReceiveBuffers = AllocatePool (sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS)); if (Private->ReceiveBuffers == NULL) { FreePool (Private->TransmitBuffer); FreePool (Private->DhcpPacketBuffer); Private->DhcpPacketBuffer = NULL; Private->TransmitBuffer = NULL; FreeMem (Private); return FALSE; } return TRUE; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ EFI_STATUS EFIAPI BcDhcp ( IN EFI_PXE_BASE_CODE_PROTOCOL *This, IN BOOLEAN SortOffers ) /*++ Routine description: standard DHCP Discover/Offer/Request/Ack session broadcast DHCPDISCOVER receive DHCPOFFER's broadcast DHCPREQUEST receive DHCPACK check (ARP) good IP Parameters: This := Pointer to PxeBc interface SortOffers := Returns: --*/ { 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 ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); if (This->Mode == NULL || !This->Mode->Started) { DEBUG ((EFI_D_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 ((EFI_D_INFO, "\nBcDhcp() Enter. ")); PxebcMode = Private->EfiBc.Mode; if (!GetMem (Private)) { DEBUG ((EFI_D_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 ((EFI_D_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; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ STATIC 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 ) /*++ Routine description: This function tries to complete the PXE Bootserver and/or boot image discovery sequence. When this command completes successfully, the PXEdiscover and PXEreply fields in the BC instance data structure are updated. If the Info pointer is set to NULL, the discovery information in the DHCPack and ProxyOffer packets must be valid and will be used. If Info is not set to NULL, the discovery methods in the Info field must be set and will be used. When discovering any layer number other than zero (the credential flag does not count), only unicast discovery is used. Parameters: Private := Pointer to PxeBc interface OpFlags := Type := LayerPtr := UseBis := DestPtr := ServerListPtr := Returns: --*/ { 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 ((EFI_D_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; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 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 ) /*++ Routine Description: Parameters: Private := Pointer to PxeBc interface Type := LayerPtr := UseBis := DiscoverInfoPtr := McastServerListPtr := ServerListPtr := Returns: --*/ { EFI_IP_ADDRESS DestIp; EFI_STATUS StatCode; DEBUG ((EFI_D_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr)); if (UseBis) { DEBUG ((EFI_D_INFO, "BIS ")); } // // get dest IP addr - mcast, bcast, or unicast // if (DiscoverInfoPtr->UseMCast) { DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4; DEBUG ( (EFI_D_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 ( (EFI_D_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode) ); return StatCode; } } if (DiscoverInfoPtr->UseBCast) { DEBUG ((EFI_D_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 ((EFI_D_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode)); return StatCode; } } if (DiscoverInfoPtr->UseUCast) { UINTN Index; DEBUG ( (EFI_D_INFO, "\nDiscover() UCast IP#=%d ", ServerListPtr->Ipv4List.IpCount) ); for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) { CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4); DEBUG ( (EFI_D_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 ( (EFI_D_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode) ); return StatCode; } } } DEBUG ((EFI_D_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 ) /*++ Routine description: Parameters: This := Type := LayerPtr := UseBis := DiscoverInfoPtr := Returns: --*/ { 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 ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); if (This->Mode == NULL || !This->Mode->Started) { DEBUG ((EFI_D_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 ((EFI_D_WARN, "\nBcDiscover() layer != 0")); if (DiscoverInfoPtr != NULL) { DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n")); EfiReleaseLock (&Private->Lock); return EFI_INVALID_PARAMETER; } if (!PxebcMode->PxeDiscoverValid) { DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n")); EfiReleaseLock (&Private->Lock); return EFI_INVALID_PARAMETER; } if (!PxebcMode->PxeReplyReceived) { DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n")); EfiReleaseLock (&Private->Lock); return EFI_INVALID_PARAMETER; } if (UseBis && !PxebcMode->PxeBisReplyReceived) { DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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) { FreePool (ServerListPtr); } FreeMem (Private); // // Unlock the instance data // DEBUG ( (EFI_D_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 ) /*++ Routine description: Parameters: Returns: --*/ { EFI_PXE_BASE_CODE_MODE *PxebcMode; PXE_BASECODE_DEVICE *Private; // // Lock the instance data and make sure started // if (This == NULL) { DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); return EFI_INVALID_PARAMETER; } Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); return EFI_INVALID_PARAMETER; } EfiAcquireLock (&Private->Lock); if (This->Mode == NULL || !This->Mode->Started) { DEBUG ((EFI_D_ERROR, "BC was not started.")); EfiReleaseLock (&Private->Lock); return EFI_NOT_STARTED; } PxebcMode = Private->EfiBc.Mode; if (Private->DhcpPacketBuffer == NULL) { Private->DhcpPacketBuffer = AllocatePool (sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1)); if (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 */