]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_dhcp.c
a61b6acff7865a3ebb94366567154da4ad4dec7c
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_bc_dhcp.c
1 /** @file
2
3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13 pxe_bc_dhcp.c
14
15 Abstract:
16 DHCP and PXE discovery protocol implementations.
17
18
19 **/
20
21 #include "Bc.h"
22
23 #include "PxeArch.h"
24
25 STATIC EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort = DHCP_SERVER_PORT;
26 STATIC EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort = DHCP_CLIENT_PORT;
27 STATIC EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort = PXE_DISCOVERY_PORT;
28 #define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort
29 STATIC EFI_IP_ADDRESS BroadcastIP = {{0xffffffff}};
30 STATIC EFI_IP_ADDRESS DefaultSubnetMask = {{0xffffff00}};
31
32 typedef union {
33 DHCPV4_OP_STRUCT *OpPtr;
34 PXE_OP_SERVER_LIST *BootServersStr;
35 PXE_SERVER_LIST *BootServerList;
36 PXE_BOOT_MENU_ENTRY *BootMenuItem;
37 PXE_OP_DISCOVERY_CONTROL *DiscoveryControl;
38 PXE_OP_BOOT_MENU *BootMenu;
39 PXE_OP_BOOT_ITEM *BootItem;
40 DHCPV4_OP_VENDOR_OPTIONS *VendorOptions;
41 DHCPV4_OP_OVERLOAD *Overload;
42 DHCPV4_OP_CLASS *PxeClassStr;
43 DHCPV4_OP_SUBNET_MASK *SubnetMaskStr;
44 DHCPV4_OP_MESSAGE_TYPE *MessageType;
45 UINT8 *BytePtr;
46 } UNION_PTR;
47
48 #pragma pack(1)
49 //
50 // option structure for DHCPREQUEST at end of DISCOVER options
51 // and for DHCPDECLINE
52 //
53 STATIC const struct requestopendstr {
54 DHCPV4_OP_REQUESTED_IP OpReqIP;
55 DHCPV4_OP_SERVER_IP DhcServerIpPtr;
56 UINT8 End[1];
57 }
58 RequestOpEndStr = {
59 {
60 {
61 OP_DHCP_REQ_IP_ADD,
62 DHCPV4_OPTION_LENGTH(DHCPV4_OP_REQUESTED_IP)
63 }
64 },
65 {
66 {
67 OP_DHCP_SERVER_IP,
68 DHCPV4_OPTION_LENGTH(DHCPV4_OP_SERVER_IP)
69 }
70 },
71 {
72 OP_END
73 }
74 };
75
76 #define DHCP_REQ_OPTIONS (*(struct requestopendstr *) DHCPV4_OPTIONS_BUFFER.End)
77
78 PXE_OP_BOOT_ITEM DefaultBootItem = {
79 {
80 VEND_PXE_BOOT_ITEM,
81 DHCPV4_OPTION_LENGTH(PXE_OP_BOOT_ITEM)
82 },
83 0,
84 0
85 };
86
87 //
88 // PXE discovery control default structure
89 //
90 STATIC PXE_OP_DISCOVERY_CONTROL DefaultDisCtl = {
91 { VEND_PXE_DISCOVERY_CONTROL, DHCPV4_OPTION_LENGTH(PXE_OP_DISCOVERY_CONTROL) },
92 0
93 };
94
95 //
96 // PXE credentials option structure
97 //
98 typedef struct {
99 UINT8 c[4];
100 } PXE_CREDENTIAL;
101
102 typedef struct {
103 DHCPV4_OP_HEADER Header;
104 PXE_CREDENTIAL Credentials[1];
105 } PXE_OP_CREDENTIAL_TYPES;
106
107 //
108 // option structure for PXE discover (without credentials)
109 //
110 typedef struct { // discoveropendstr {
111 DHCPV4_OP_HEADER Header; // vendor options
112 PXE_OP_BOOT_ITEM BootItem;
113 UINT8 End[1]; // if credentials option, it starts here
114 } PXE_DISCOVER_OPTIONS;
115
116 #define DISCOVERoptions (*(PXE_DISCOVER_OPTIONS *) DHCPV4_OPTIONS_BUFFER.End)
117 #define DISCREDoptions (*(PXE_OP_CREDENTIAL_TYPES *) DISCOVERoptions.End)
118
119 //
120 // common option beginning for all our DHCP messages except
121 // DHCPDECLINE and DHCPRELEASE
122 //
123 STATIC struct optionsstr {
124 UINT8 DhcpCookie[4];
125 DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
126 DHCPV4_OP_MAX_MESSAGE_SIZE DhcpMaxMessageSize;
127 DHCPV4_OP_REQUESTED_OPTIONS DhcpRequestedOptions;
128 DHCPV4_OP_PLATFORM_ID DhcpPlatformId;
129 DHCPV4_OP_NETWORK_INTERFACE DhcpNetworkInterface;
130 DHCPV4_OP_ARCHITECTURE_TYPE DhcpClientArchitecture;
131 DHCPV4_OP_CLASS_ID DhcpClassIdentifier;
132 UINT8 End[1];
133 } DHCPOpStart;
134
135 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
136 VOID
137 OptionsStrucInit (
138 VOID
139 )
140 {
141 DHCPOpStart.DhcpCookie[0] = 99;
142 DHCPOpStart.DhcpCookie[1] = 130;
143 DHCPOpStart.DhcpCookie[2] = 83;
144 DHCPOpStart.DhcpCookie[3] = 99;
145 DHCPOpStart.DhcpMessageType.Header.OpCode = OP_DHCP_MESSAGE_TYPE;
146 DHCPOpStart.DhcpMessageType.Header.Length = 1;
147 DHCPOpStart.DhcpMessageType.Type = DHCPDISCOVER;
148 DHCPOpStart.DhcpMaxMessageSize.Header.OpCode = OP_DHCP_MAX_MESSAGE_SZ;
149 DHCPOpStart.DhcpMaxMessageSize.Header.Length = 2;
150 DHCPOpStart.DhcpMaxMessageSize.MaxSize[0] = MAX_DHCP_MSG_SZ >> 8;
151 DHCPOpStart.DhcpMaxMessageSize.MaxSize[1] = MAX_DHCP_MSG_SZ & 0xff;
152 DHCPOpStart.DhcpRequestedOptions.Header.OpCode = OP_DHCP_PARM_REQ_LIST;
153 DHCPOpStart.DhcpRequestedOptions.Header.Length = sizeof (DHCPV4_REQUESTED_OPTIONS_DATA);
154 DHCPOpStart.DhcpRequestedOptions.Data._OP_SUBNET_MASK = OP_SUBNET_MASK; /* 1 */
155 DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_OFFSET = OP_TIME_OFFSET; /* 2 */
156 DHCPOpStart.DhcpRequestedOptions.Data._OP_ROUTER_LIST = OP_ROUTER_LIST; /* 3 */
157 DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_SERVERS = OP_TIME_SERVERS; /* 4 */
158 DHCPOpStart.DhcpRequestedOptions.Data._OP_NAME_SERVERS = OP_NAME_SERVERS; /* 5 */
159 DHCPOpStart.DhcpRequestedOptions.Data._OP_DNS_SERVERS = OP_DNS_SERVERS; /* 6 */
160 DHCPOpStart.DhcpRequestedOptions.Data._OP_HOST_NAME = OP_HOST_NAME; /* 12 */
161 DHCPOpStart.DhcpRequestedOptions.Data._OP_BOOT_FILE_SZ = OP_BOOT_FILE_SZ; /* 13 */
162 DHCPOpStart.DhcpRequestedOptions.Data._OP_DOMAIN_NAME = OP_DOMAIN_NAME; /* 15 */
163 DHCPOpStart.DhcpRequestedOptions.Data._OP_ROOT_PATH = OP_ROOT_PATH; /* 17 */
164 DHCPOpStart.DhcpRequestedOptions.Data._OP_EXTENSION_PATH = OP_EXTENSION_PATH; /* 18 */
165 DHCPOpStart.DhcpRequestedOptions.Data._OP_MAX_DATAGRAM_SZ = OP_MAX_DATAGRAM_SZ; /* 22 */
166 DHCPOpStart.DhcpRequestedOptions.Data._OP_DEFAULT_TTL = OP_DEFAULT_TTL; /* 23 */
167 DHCPOpStart.DhcpRequestedOptions.Data._OP_BROADCAST_ADD = OP_BROADCAST_ADD; /* 28 */
168 DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_DOMAIN_NAME = OP_NIS_DOMAIN_NAME; /* 40 */
169 DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_SERVERS = OP_NIS_SERVERS; /* 41 */
170 DHCPOpStart.DhcpRequestedOptions.Data._OP_NTP_SERVERS = OP_NTP_SERVERS; /* 42 */
171 DHCPOpStart.DhcpRequestedOptions.Data._OP_VENDOR_SPECIFIC = OP_VENDOR_SPECIFIC; /* 43 */
172 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REQ_IP_ADD = OP_DHCP_REQ_IP_ADD; /* 50 */
173 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_LEASE_TIME = OP_DHCP_LEASE_TIME; /* 51 */
174 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_SERVER_IP = OP_DHCP_SERVER_IP; /* 54 */
175 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_RENEWAL_TIME = OP_DHCP_RENEWAL_TIME; /* 58 */
176 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REBINDING_TIME = OP_DHCP_REBINDING_TIME; /* 59 */
177 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_CLASS_IDENTIFIER = OP_DHCP_CLASS_IDENTIFIER; /* 60 */
178 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_TFTP_SERVER_NAME = OP_DHCP_TFTP_SERVER_NAME; /* 66 */
179 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_BOOTFILE = OP_DHCP_BOOTFILE; /* 67 */
180 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_PLATFORM_ID = OP_DHCP_PLATFORM_ID; /* 97 */
181 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption128 = 128;
182 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption129 = 129;
183 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption130 = 130;
184 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption131 = 131;
185 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption132 = 132;
186 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption133 = 133, DHCPOpStart.DhcpRequestedOptions.Data.VendorOption134 = 134;
187 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption135 = 135;
188 DHCPOpStart.DhcpPlatformId.Header.OpCode = OP_DHCP_PLATFORM_ID;
189 DHCPOpStart.DhcpPlatformId.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_PLATFORM_ID);
190 DHCPOpStart.DhcpNetworkInterface.Header.OpCode = OP_DHCP_NETWORK_ARCH;
191 DHCPOpStart.DhcpNetworkInterface.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_NETWORK_INTERFACE);
192 DHCPOpStart.DhcpNetworkInterface.Type = 0;
193 DHCPOpStart.DhcpNetworkInterface.MajorVersion = 0;
194 DHCPOpStart.DhcpNetworkInterface.MinorVersion = 0;
195 DHCPOpStart.DhcpClientArchitecture.Header.OpCode = OP_DHCP_SYSTEM_ARCH;
196 DHCPOpStart.DhcpClientArchitecture.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_ARCHITECTURE_TYPE);
197 DHCPOpStart.DhcpClientArchitecture.Type = HTONS (SYS_ARCH);
198 DHCPOpStart.DhcpClassIdentifier.Header.OpCode = OP_DHCP_CLASS_IDENTIFIER;
199 DHCPOpStart.DhcpClassIdentifier.Header.Length = sizeof (DHCPV4_CLASS_ID_DATA);
200 CopyMem (
201 DHCPOpStart.DhcpClassIdentifier.Data.ClassIdentifier,
202 "PXEClient:",
203 sizeof ("PXEClient:")
204 );
205 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit2, "Arch:", sizeof ("Arch:"));
206 CopyMem (
207 DHCPOpStart.DhcpClassIdentifier.Data.ArchitectureType,
208 "xxxxx",
209 sizeof ("xxxxx")
210 );
211 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit3, ":", sizeof (":"));
212 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.InterfaceName, "XXXX", sizeof ("XXXX"));
213 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit4, ":", sizeof (":"));
214 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMajor, "yyy", sizeof ("yyy"));
215 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMinor, "xxx", sizeof ("xxx"));
216 DHCPOpStart.End[0] = OP_END;
217 }
218
219 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
220
221 //
222 // DHCPDECLINE option structure
223 //
224 struct opdeclinestr {
225 UINT8 DhcpCookie[4];
226 DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
227 struct requestopendstr OpDeclineEnd;
228 };
229
230 #define DHCPDECLINEoptions (*(struct opdeclinestr *) DHCPV4_TRANSMIT_BUFFER.options)
231
232 //
233 // DHCPRELEASE option structure
234 //
235 struct opreleasestr {
236 UINT8 DhcpCookie[4];
237 DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
238 DHCPV4_OP_SERVER_IP DhcServerIpPtr;
239 UINT8 End[1];
240 };
241
242 #define DHCPRELEASEoptions (*(struct opreleasestr *) DHCPV4_TRANSMIT_BUFFER.options)
243
244 //
245 // array of PXE vendor options in which we are interested
246 // value 0 -> not of interest, else value is index into PXE OPTION array
247 // option values from 1 to MAX_OUR_PXE_OPT
248 //
249 STATIC UINT8 ourPXEopts[MAX_OUR_PXE_OPT] = {
250 VEND_PXE_MTFTP_IP_IX, // multicast IP address of bootfile for MTFTP listen
251 VEND_PXE_MTFTP_CPORT_IX, // UDP Port to monitor for MTFTP responses - Intel order
252 VEND_PXE_MTFTP_SPORT_IX, // Server UDP Port for MTFTP open - Intel order
253 VEND_PXE_MTFTP_TMOUT_IX, // Listen timeout - secs
254 VEND_PXE_MTFTP_DELAY_IX, // Transmission timeout - secs
255 VEND_PXE_DISCOVERY_CONTROL_IX, // bit field
256 VEND_PXE_DISCOVERY_MCAST_ADDR_IX, // boot server discovery multicast address
257 VEND_PXE_BOOT_SERVERS_IX, // list of boot servers of form tp(2) cnt(1) ips[cnt]
258 VEND_PXE_BOOT_MENU_IX,
259 VEND_PXE_BOOT_PROMPT_IX,
260 VEND_PXE_MCAST_ADDRS_ALLOC_IX, // not used by client
261 VEND_PXE_CREDENTIAL_TYPES_IX,
262 VEND_13_IX, // not used by client
263 VEND_14_IX, // not used by client
264 VEND_15_IX, // not used by client
265 VEND_16_IX, // not used by client
266 VEND_17_IX, // not used by client
267 VEND_18_IX, // not used by client
268 VEND_19_IX, // not used by client
269 VEND_20_IX, // not used by client
270 VEND_21_IX, // not used by client
271 VEND_22_IX, // not used by client
272 VEND_23_IX, // not used by client
273 VEND_24_IX, // not used by client
274 VEND_25_IX, // not used by client
275 VEND_26_IX, // not used by client
276 VEND_27_IX, // not used by client
277 VEND_28_IX, // not used by client
278 VEND_29_IX, // not used by client
279 VEND_30_IX, // not used by client
280 VEND_31_IX, // not used by client
281 VEND_32_IX, // not used by client
282 VEND_33_IX, // not used by client
283 VEND_34_IX, // not used by client
284 VEND_35_IX, // not used by client
285 VEND_36_IX, // not used by client
286 VEND_37_IX, // not used by client
287 VEND_38_IX, // not used by client
288 VEND_39_IX, // not used by client
289 VEND_40_IX, // not used by client
290 VEND_41_IX, // not used by client
291 VEND_42_IX, // not used by client
292 VEND_43_IX, // not used by client
293 VEND_44_IX, // not used by client
294 VEND_45_IX, // not used by client
295 VEND_46_IX, // not used by client
296 VEND_47_IX, // not used by client
297 VEND_48_IX, // not used by client
298 VEND_49_IX, // not used by client
299 VEND_50_IX, // not used by client
300 VEND_51_IX, // not used by client
301 VEND_52_IX, // not used by client
302 VEND_53_IX, // not used by client
303 VEND_54_IX, // not used by client
304 VEND_55_IX, // not used by client
305 VEND_56_IX, // not used by client
306 VEND_57_IX, // not used by client
307 VEND_58_IX, // not used by client
308 VEND_59_IX, // not used by client
309 VEND_60_IX, // not used by client
310 VEND_61_IX, // not used by client
311 VEND_62_IX, // not used by client
312 VEND_63_IX, // not used by client
313 VEND_64_IX, // not used by client
314 VEND_65_IX, // not used by client
315 VEND_66_IX, // not used by client
316 VEND_67_IX, // not used by client
317 VEND_68_IX, // not used by client
318 VEND_69_IX, // not used by client
319 VEND_70_IX, // not used by client
320 VEND_PXE_BOOT_ITEM_IX
321 };
322
323 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
324
325 //
326 // array of options in which we are interested
327 // value 0 -> not of interest, else value is index into OPTION array
328 // option values from 1 to MAX_OUR_OPT
329 //
330 STATIC UINT8 OurDhcpOptions[MAX_OUR_OPT] = {
331 OP_SUBNET_MASK_IX, // OP_SUBNET_MASK 1 // data is the subnet mask
332 OP_TIME_OFFSET_IX, // OP_TIME_OFFSET 2 // data is the time offset of subnet to UTC in seconds
333 OP_ROUTER_LIST_IX, // OP_ROUTER_LIST 3 // list of routers on subnet
334 OP_TIME_SERVERS_IX, // OP_TIME_SERVERS 4 // list of time servers available
335 OP_NAME_SERVERS_IX, // OP_NAME_SERVERS 5 // list of name servers available
336 OP_DNS_SERVERS_IX, // OP_DNS_SERVERS 6 // list of DNS servers available
337 OP_LOG_SERVERS_IX, // OP_LOG_SERVERS 7
338 OP_COOKIE_SERVERS_IX, // OP_COOKIE_SERVERS 8
339 OP_LPR_SREVERS_IX, // OP_LPR_SREVERS 9
340 OP_IMPRESS_SERVERS_IX, // OP_IMPRESS_SERVERS 10
341 OP_RES_LOC_SERVERS_IX, // OP_RES_LOC_SERVERS 11
342 OP_HOST_NAME_IX, // OP_HOST_NAME 12 // client name
343 OP_BOOT_FILE_SZ_IX, // OP_BOOT_FILE_SZ 13 // number of 512 blocks of boot file
344 OP_DUMP_FILE_IX, // OP_DUMP_FILE 14 // path name of dump file if client crashes
345 OP_DOMAIN_NAME_IX, // OP_DOMAIN_NAME 15 // domain name to use
346 OP_SWAP_SERVER_IX, // OP_SWAP_SERVER 16
347 OP_ROOT_PATH_IX, // OP_ROOT_PATH 17 // path name containing root disk
348 OP_EXTENSION_PATH_IX, // OP_EXTENSION_PATH 18 // name of TFTP downloadable file of form of OP
349 OP_IP_FORWARDING_IX, // OP_IP_FORWARDING 19 // enable/disable IP packet forwarding
350 OP_NON_LOCAL_SRC_RTE_IX, // OP_NON_LOCAL_SRC_RTE 20 // enable/disable non local source routing
351 OP_POLICY_FILTER_IX, // OP_POLICY_FILTER 21 // policy filters for non local source routing
352 OP_MAX_DATAGRAM_SZ_IX, // OP_MAX_DATAGRAM_SZ 22 // maximum datagram reassembly size
353 OP_DEFAULT_TTL_IX, // OP_DEFAULT_TTL 23 // default IP time to live
354 OP_MTU_AGING_TIMEOUT_IX, // OP_MTU_AGING_TIMEOUT 24
355 OP_MTU_SIZES_IX, // OP_MTU_SIZES 25
356 OP_MTU_TO_USE_IX, // OP_MTU_TO_USE 26
357 OP_ALL_SUBNETS_LOCAL_IX, // OP_ALL_SUBNETS_LOCAL 27
358 OP_BROADCAST_ADD_IX, // OP_BROADCAST_ADD 28 // broadcast address used on subnet
359 OP_PERFORM_MASK_DISCOVERY_IX, // OP_PERFORM_MASK_DISCOVERY 29 // perform mask discovery using ICMP
360 OP_RESPOND_TO_MASK_REQ_IX, // OP_RESPOND_TO_MASK_REQ 30 // respond to subnet mask requests using ICMP
361 OP_PERFORM_ROUTER_DISCOVERY_IX, // OP_PERFORM_ROUTER_DISCOVERY 31
362 OP_ROUTER_SOLICIT_ADDRESS_IX, // OP_ROUTER_SOLICIT_ADDRESS 32
363 OP_STATIC_ROUTER_LIST_IX, // OP_STATIC_ROUTER_LIST 33 // list of dest/route pairs
364 OP_USE_ARP_TRAILERS_IX, // OP_USE_ARP_TRAILERS 34
365 OP_ARP_CACHE_TIMEOUT_IX, // OP_ARP_CACHE_TIMEOUT 35
366 OP_ETHERNET_ENCAPSULATION_IX, // OP_ETHERNET_ENCAPSULATION 36 // 0 -> RFC 894, 1 -> IEEE 802.3 (RFC 1042)
367 OP_TCP_DEFAULT_TTL_IX, // OP_TCP_DEFAULT_TTL 37 // default time to live when sending TCP segments
368 OP_TCP_KEEP_ALIVE_INT_IX, // OP_TCP_KEEP_ALIVE_INT 38 // keep alive interval in seconds
369 OP_KEEP_ALIVE_GARBAGE_IX, // OP_KEEP_ALIVE_GARBAGE 39
370 OP_NIS_DOMAIN_NAME_IX, // OP_NIS_DOMAIN_NAME 40
371 OP_NIS_SERVERS_IX, // OP_NIS_SERVERS 41
372 OP_NTP_SERVERS_IX, // OP_NTP_SERVERS 42
373 OP_VENDOR_SPECIFIC_IX, // OP_VENDOR_SPECIFIC 43
374 OP_NBNS_SERVERS_IX, // OP_NBNS_SERVERS 44
375 OP_NBDD_SERVERS_IX, // OP_NBDD_SERVERS 45
376 OP_NETBIOS_NODE_TYPE_IX, // OP_NETBIOS_NODE_TYPE 46
377 OP_NETBIOS_SCOPE_IX, // OP_NETBIOS_SCOPE 47
378 OP_XWINDOW_SYSTEM_FONT_SERVERS_IX, // OP_XWINDOW_SYSTEM_FONT_SERVERS 48
379 OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX, // OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49
380 OP_DHCP_REQ_IP_ADD_IX, // OP_DHCP_REQ_IP_ADD 50 // requested IP address - in DHCPDISCOVER
381 OP_DHCP_LEASE_TIME_IX, // OP_DHCP_LEASE_TIME 51 // lease time requested/granted
382 OP_DHCP_OPTION_OVERLOAD_IX, // OP_DHCP_OPTION_OVERLOAD 52 // file/server name/both used to hold options
383 OP_DHCP_MESSAGE_TYPE_IX, // OP_DHCP_MESSAGE_TYPE 53 // message type
384 OP_DHCP_SERVER_IP_IX, // OP_DHCP_SERVER_IP 54 // IP of server
385 OP_DHCP_PARM_REQ_LIST_IX, // OP_DHCP_PARM_REQ_LIST 55 // list of requested parameters
386 OP_DHCP_ERROR_MESSAGE_IX, // OP_DHCP_ERROR_MESSAGE 56 // in DHCPNAK or DECLINE messages
387 OP_DHCP_MAX_MESSAGE_SZ_IX, // OP_DHCP_MAX_MESSAGE_SZ 57 // maximum DHCP message size client will accept
388 OP_DHCP_RENEWAL_TIME_IX, // OP_DHCP_RENEWAL_TIME 58 // time in seconds before transitioning to RENEWING state
389 OP_DHCP_REBINDING_TIME_IX, // OP_DHCP_REBINDING_TIME 59 // time in seconds before transitioning to REBINDING state
390 OP_DHCP_CLASS_IDENTIFIER_IX, // OP_DHCP_CLASS_IDENTIFIER 60
391 OP_DHCP_CLIENT_IDENTIFIER_IX, // OP_DHCP_CLIENT_IDENTIFIER 61
392 OP_RESERVED62_IX, // OP_RESERVED62
393 OP_RESERVED63_IX, // OP_RESERVED63
394 OP_NISPLUS_DOMAIN_NAME_IX, // OP_NISPLUS_DOMAIN_NAME 64
395 OP_NISPLUS_SERVERS_IX, // OP_NISPLUS_SERVERS 65
396 OP_DHCP_TFTP_SERVER_NAME_IX, // OP_DHCP_TFTP_SERVER_NAME 66
397 OP_DHCP_BOOTFILE_IX // OP_DHCP_BOOTFILE 67
398 };
399
400 #define RxBuf ((DHCP_RECEIVE_BUFFER *) (Private->ReceiveBuffers))
401
402 #pragma pack()
403
404 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
405
406 /**
407
408 @param Smbios Pointer to SMBIOS structure
409 @param StringNumber String number to return. 0 is used to skip all
410 strings and point to the next SMBIOS structure.
411
412 @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0
413
414 **/
415 CHAR8 *
416 PxeBcLibGetSmbiosString (
417 IN SMBIOS_STRUCTURE_POINTER *Smbios,
418 IN UINT16 StringNumber
419 )
420 {
421 UINT16 Index;
422 CHAR8 *String;
423
424 //
425 // Skip over formatted section
426 //
427 String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);
428
429 //
430 // Look through unformated section
431 //
432 for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {
433 if (StringNumber == Index) {
434 return String;
435 }
436 //
437 // Skip string
438 //
439 for (; *String != 0; String++)
440 ;
441 String++;
442
443 if (*String == 0) {
444 //
445 // If double NULL then we are done.
446 // Return pointer to next structure in Smbios.
447 // if you pass in a 0 you will always get here
448 //
449 Smbios->Raw = (UINT8 *)++String;
450 return NULL;
451 }
452 }
453
454 return NULL;
455 }
456
457
458 /**
459 This function gets system guid and serial number from the smbios table
460
461 @param SystemGuid The pointer of returned system guid
462 @param SystemSerialNumber The pointer of returned system serial number
463
464 @retval EFI_SUCCESS Successfully get the system guid and system serial
465 number
466 @retval EFI_NOT_FOUND Not find the SMBIOS table
467
468 **/
469 EFI_STATUS
470 PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
471 IN EFI_GUID *SystemGuid,
472 OUT CHAR8 **SystemSerialNumber
473 )
474 {
475 EFI_STATUS Status;
476 SMBIOS_STRUCTURE_TABLE *SmbiosTable;
477 SMBIOS_STRUCTURE_POINTER Smbios;
478 SMBIOS_STRUCTURE_POINTER SmbiosEnd;
479 UINT16 Index;
480
481 Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
482
483 if (EFI_ERROR (Status)) {
484 return EFI_NOT_FOUND;
485 }
486
487 Smbios.Hdr = (SMBIOS_HEADER *) (UINTN) SmbiosTable->TableAddress;
488 SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
489
490 for (Index = 0; Index < SmbiosTable->TableLength; Index++) {
491 if (Smbios.Hdr->Type == 1) {
492 if (Smbios.Hdr->Length < 0x19) {
493 //
494 // Older version did not support Guid and Serial number
495 //
496 continue;
497 }
498 //
499 // SMBIOS tables are byte packed so we need to do a byte copy to
500 // prevend alignment faults on Itanium-based platform.
501 //
502 CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
503 *SystemSerialNumber = PxeBcLibGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber);
504
505 return EFI_SUCCESS;
506 }
507 //
508 // Make Smbios point to the next record
509 //
510 PxeBcLibGetSmbiosString (&Smbios, 0);
511
512 if (Smbios.Raw >= SmbiosEnd.Raw) {
513 //
514 // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.
515 // given this we must double check against the lenght of
516 // the structure.
517 //
518 return EFI_SUCCESS;
519 }
520 }
521
522 return EFI_SUCCESS;
523 }
524
525 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
526
527 //
528 // add router list to list
529 //
530 STATIC
531 VOID
532 Ip4AddRouterList (
533 PXE_BASECODE_DEVICE *Private,
534 DHCPV4_OP_IP_LIST *IpListPtr
535 )
536 {
537 EFI_IP_ADDRESS TmpIp;
538 INTN Index;
539 INTN num;
540
541 if (IpListPtr == NULL) {
542 return ;
543 }
544
545 for (Index = 0, num = IpListPtr->Header.Length >> 2; Index < num; ++Index) {
546 CopyMem (&TmpIp, &IpListPtr->IpList[Index], 4);
547 Ip4AddRouter (Private, &TmpIp);
548 }
549 }
550
551 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
552
553 //
554 // send ARP for our IP - fail if someone has it
555 //
556 STATIC
557 BOOLEAN
558 SetStationIP (
559 PXE_BASECODE_DEVICE *Private
560 )
561 {
562 EFI_MAC_ADDRESS DestMac;
563 EFI_STATUS EfiStatus;
564
565 ZeroMem (&DestMac, sizeof DestMac);
566
567 if (GetHwAddr(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac)
568 || DoArp(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) == EFI_SUCCESS) {
569 return FALSE; // somebody else has this IP
570 }
571
572 CopyMem (
573 (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->StationIp,
574 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
575 sizeof (EFI_IPv4_ADDRESS)
576 );
577
578 Private->GoodStationIp = TRUE;
579
580 if (!Private->UseIgmpv1Reporting) {
581 return TRUE;
582 }
583
584 if (Private->Igmpv1TimeoutEvent != NULL) {
585 return TRUE;
586 }
587
588 EfiStatus = gBS->CreateEvent (
589 EVT_TIMER,
590 TPL_CALLBACK,
591 NULL,
592 NULL,
593 &Private->Igmpv1TimeoutEvent
594 );
595
596 if (EFI_ERROR (EfiStatus)) {
597 Private->Igmpv1TimeoutEvent = NULL;
598 return TRUE;
599 }
600
601 EfiStatus = gBS->SetTimer (
602 Private->Igmpv1TimeoutEvent,
603 TimerRelative,
604 (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
605 ); /* 400 seconds */
606
607 if (EFI_ERROR (EfiStatus)) {
608 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
609 Private->Igmpv1TimeoutEvent = NULL;
610 }
611
612 return TRUE;
613 }
614
615 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
616 STATIC
617 VOID
618 AddRouters (
619 PXE_BASECODE_DEVICE *Private,
620 DHCP_RECEIVE_BUFFER *RxBufPtr
621 )
622 {
623 Ip4AddRouterList (
624 Private,
625 (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1]
626 );
627 }
628
629 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
630 STATIC
631 EFI_STATUS
632 DoUdpWrite (
633 PXE_BASECODE_DEVICE *Private,
634 EFI_IP_ADDRESS *ServerIpPtr,
635 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
636 EFI_IP_ADDRESS *ClientIpPtr,
637 EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr
638 )
639 {
640 UINTN Len;
641
642 Len = sizeof DHCPV4_TRANSMIT_BUFFER;
643
644 return UdpWrite (
645 Private,
646 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
647 ServerIpPtr,
648 ServerPortPtr,
649 0,
650 ClientIpPtr,
651 ClientPortPtr,
652 0,
653 0,
654 &Len,
655 Private->TransmitBuffer
656 );
657 }
658
659 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
660
661 //
662 // initialize the DHCP structure
663 //
664 typedef struct {
665 UINT8 x[4];
666 } C4Str;
667
668 STATIC
669 VOID
670 InitDhcpv4TxBuf (
671 PXE_BASECODE_DEVICE *Private
672 )
673 {
674 UINTN HwAddrLen;
675 UINT8 *String;
676 CHAR8 *SystemSerialNumber;
677 EFI_PXE_BASE_CODE_MODE *PxebcMode;
678
679 PxebcMode = Private->EfiBc.Mode;
680
681 ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT));
682 DHCPV4_TRANSMIT_BUFFER.op = BOOTP_REQUEST;
683 DHCPV4_TRANSMIT_BUFFER.htype = Private->SimpleNetwork->Mode->IfType;
684 DHCPV4_TRANSMIT_BUFFER.flags = HTONS (DHCP_BROADCAST_FLAG);
685 CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart));
686
687 //
688 // default to hardware address
689 //
690 HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize;
691
692 if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) {
693 HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr;
694 }
695
696 String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress;
697
698 if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
699 (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid,
700 &SystemSerialNumber
701 ) == EFI_SUCCESS) {
702 if (PxebcMode->SendGUID) {
703 HwAddrLen = sizeof (EFI_GUID);
704 String = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid;
705 }
706 } else {
707 //
708 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
709 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
710 // GUID not yet set - send all 0's to show not programable
711 //
712 ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID));
713 }
714
715 DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen;
716 CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen);
717
718 CvtNum (
719 SYS_ARCH,
720 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType,
721 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType
722 );
723
724 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type = Private->NiiPtr->Type;
725 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion = Private->NiiPtr->MajorVer;
726 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion = Private->NiiPtr->MinorVer;
727
728 *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId;
729
730 CvtNum (
731 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion,
732 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor,
733 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor
734 );
735
736 CvtNum (
737 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion,
738 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor,
739 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor
740 );
741 }
742
743 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
744 STATIC
745 UINT32
746 DecodePxeOptions (
747 DHCP_RECEIVE_BUFFER *RxBufPtr,
748 UINT8 *ptr,
749 INTN Len
750 )
751 {
752 UINT8 Op;
753 UINT8 *EndPtr;
754 INTN Index;
755 UNION_PTR LocalPtr;
756 UINT32 status;
757
758 status = 0;
759
760 for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
761 Op = ptr[0];
762 Len = ptr[1];
763
764 switch (Op) {
765 case OP_PAD:
766 Len = -1;
767 break;
768
769 case OP_END:
770 return status;
771
772 default:
773 LocalPtr.BytePtr = ptr;
774 if (Op <= MAX_OUR_PXE_OPT) {
775 Index = ourPXEopts[Op - 1];
776 if (Index) {
777 RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr;
778 status |= 1 << Index;
779 if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) {
780 RxBufPtr->OpAdds.Status |= USE_THREE_BYTE;
781 }
782 }
783 }
784 break;
785 }
786 }
787
788 return status;
789 }
790
791 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
792 STATIC
793 VOID
794 DecodeOptions (
795 DHCP_RECEIVE_BUFFER *RxBufPtr,
796 UINT8 *ptr,
797 INTN Len
798 )
799 {
800 UINT8 Op;
801 UINT8 *EndPtr;
802 INTN Index;
803 UNION_PTR LocalPtr;
804
805 for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
806 Op = ptr[0];
807 Len = ptr[1];
808
809 switch (Op) {
810 case OP_PAD:
811 Len = -1;
812 break;
813
814 case OP_END:
815 return ;
816
817 default:
818 LocalPtr.BytePtr = ptr;
819 if (Op <= MAX_OUR_OPT) {
820 Index = OurDhcpOptions[Op - 1];
821 if (Index) {
822 RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr;
823 if (Index == OP_VENDOR_SPECIFIC_IX) {
824 UINT32 status;
825 status = DecodePxeOptions (
826 RxBufPtr,
827 (UINT8 *) LocalPtr.VendorOptions->VendorOptions,
828 LocalPtr.VendorOptions->Header.Length
829 );
830 if (status) {
831 RxBufPtr->OpAdds.Status |= PXE_TYPE;
832 //
833 // check for all the MTFTP info options present - any missing is a nogo
834 //
835 if ((status & WfM11a_OPTS) == WfM11a_OPTS) {
836 RxBufPtr->OpAdds.Status |= WfM11a_TYPE;
837 }
838
839 if (status & DISCOVER_OPTS) {
840 RxBufPtr->OpAdds.Status |= DISCOVER_TYPE;
841 }
842
843 if (status & CREDENTIALS_OPT) {
844 RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE;
845 }
846 }
847 }
848 }
849 }
850 break;
851 }
852 }
853 }
854
855 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
856 VOID
857 Parse (
858 DHCP_RECEIVE_BUFFER *RxBufPtr,
859 INTN Len
860 )
861 {
862 UNION_PTR LocalPtr;
863
864 //
865 // initialize
866 //
867 SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0);
868
869 DecodeOptions (
870 RxBufPtr,
871 RxBufPtr->u.Dhcpv4.options + 4,
872 Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4)
873 );
874
875 LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1];
876
877 if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) {
878 DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname);
879 }
880
881 if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) {
882 DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file);
883 } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) {
884 RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER));
885
886 RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen ((CHAR8 *) RxBufPtr->u.Dhcpv4.file);
887 }
888
889 LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1];
890
891 if ((LocalPtr.OpPtr) &&
892 LocalPtr.PxeClassStr->Header.Length >= 9 &&
893 !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9)
894 ) {
895 RxBufPtr->OpAdds.Status |= PXE_TYPE;
896 }
897 }
898
899 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
900 STATIC
901 VOID
902 CopyParseRxBuf (
903 PXE_BASECODE_DEVICE *Private,
904 INTN RxBufIndex,
905 INTN PacketIndex
906 )
907 {
908 DHCP_RECEIVE_BUFFER *RxBufPtr;
909
910 RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex];
911
912 CopyMem (
913 &RxBufPtr->u.Dhcpv4,
914 &RxBuf[RxBufIndex].u.Dhcpv4,
915 sizeof (RxBuf[RxBufIndex].u.Dhcpv4)
916 );
917
918 Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer);
919 }
920
921 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
922 STATIC
923 VOID
924 CopyProxyRxBuf (
925 PXE_BASECODE_DEVICE *Private,
926 INTN RxBufIndex
927 )
928 {
929 Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
930 CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX);
931 }
932
933 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
934 STATIC
935 VOID
936 CopyParse (
937 PXE_BASECODE_DEVICE *Private,
938 EFI_PXE_BASE_CODE_PACKET *PacketPtr,
939 EFI_PXE_BASE_CODE_PACKET *NewPacketPtr,
940 INTN Index
941 )
942 {
943 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
944
945 DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index];
946
947 CopyMem (
948 (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4,
949 NewPacketPtr,
950 sizeof (*NewPacketPtr)
951 );
952
953 CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr));
954
955 Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer);
956 }
957
958 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
959 BOOLEAN
960 AckEdit (
961 DHCP_RECEIVE_BUFFER *DhcpRxBuf
962 )
963 {
964 UNION_PTR LocalPtr;
965
966 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
967
968 //
969 // check that an ACK
970 // if a DHCP type, must be DHCPOFFER and must have server id
971 //
972 return (BOOLEAN)
973 (
974 (LocalPtr.OpPtr) &&
975 (LocalPtr.MessageType->Type == DHCPACK) &&
976 DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]
977 );
978 }
979
980 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
981
982 //
983 // if a discover type packet, make sure all required fields are present
984 //
985 BOOLEAN
986 DHCPOfferAckEdit (
987 DHCP_RECEIVE_BUFFER *DhcpRxBuf
988 )
989 {
990 PXE_OP_SERVER_LIST *BootServerOpPtr;
991 UNION_PTR LocalPtr;
992
993 if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) {
994 return TRUE;
995 }
996
997 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
998
999 if (LocalPtr.OpPtr == NULL) {
1000 LocalPtr.OpPtr = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
1001 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
1002 }
1003 //
1004 // make sure all required fields are here
1005 // if mucticast enabled, need multicast address
1006 //
1007 if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) &&
1008 (!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))
1009 ) {
1010 return FALSE;
1011 //
1012 // missing required field
1013 //
1014 }
1015 //
1016 // if a list, it better be good
1017 //
1018 BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1];
1019
1020 if (BootServerOpPtr != NULL) {
1021 PXE_SERVER_LIST *BootServerListPtr;
1022 INTN ServerListLen;
1023 INTN ServerEntryLen;
1024
1025 BootServerListPtr = BootServerOpPtr->ServerList;
1026 ServerListLen = BootServerOpPtr->Header.Length;
1027
1028 do {
1029 EFI_IPv4_ADDRESS *IpListPtr;
1030 INTN IpCnt;
1031
1032 IpCnt = BootServerListPtr->u.Ipv4List.IpCount;
1033
1034 ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS);
1035
1036 if (ServerListLen < ServerEntryLen) {
1037 //
1038 // missing required field
1039 //
1040 return FALSE;
1041 }
1042
1043 IpListPtr = BootServerListPtr->u.Ipv4List.IpList;
1044
1045 while (IpCnt--) {
1046 if (IS_MULTICAST (IpListPtr)) {
1047 //
1048 // missing required field
1049 //
1050 return FALSE;
1051 } else {
1052 ++IpListPtr;
1053 }
1054 }
1055
1056 BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr;
1057 } while (ServerListLen -= ServerEntryLen);
1058 }
1059 //
1060 // else there must be a list if use list enabled or multicast and
1061 // broadcast disabled
1062 //
1063 else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) ||
1064 ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
1065 ) {
1066 //
1067 // missing required field
1068 //
1069 return FALSE;
1070 }
1071 //
1072 // if not USE_BOOTFILE or no bootfile given, must have menu stuff
1073 //
1074 if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) ||
1075 !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
1076 ) {
1077 INTN MenuLth;
1078
1079 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
1080
1081 if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) {
1082 //
1083 // missing required field
1084 //
1085 return FALSE;
1086 }
1087 //
1088 // make sure menu valid
1089 //
1090 MenuLth = LocalPtr.BootMenu->Header.Length;
1091 LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem;
1092
1093 do {
1094 INTN MenuItemLen;
1095
1096 MenuItemLen = LocalPtr.BootMenuItem->DataLen;
1097
1098 if (MenuItemLen == 0) {
1099 //
1100 // missing required field
1101 //
1102 return FALSE;
1103 }
1104
1105 MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data);
1106
1107 MenuLth -= MenuItemLen;
1108 LocalPtr.BytePtr += MenuItemLen;
1109 } while (MenuLth > 0);
1110
1111 if (MenuLth != 0) {
1112 //
1113 // missing required field
1114 //
1115 return FALSE;
1116 }
1117 }
1118
1119 if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
1120 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem;
1121 }
1122
1123 return TRUE;
1124 }
1125
1126 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1127 BOOLEAN
1128 DHCPAckEdit (
1129 DHCP_RECEIVE_BUFFER *RxBufPtr
1130 )
1131 {
1132 return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE);
1133 }
1134
1135 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1136
1137 //
1138 // get an offer/ack
1139 //
1140 EFI_STATUS
1141 GetOfferAck (
1142 PXE_BASECODE_DEVICE *Private,
1143 BOOLEAN (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf),
1144 UINT16 OpFlags, // for Udp read
1145 EFI_IP_ADDRESS *ServerIpPtr,
1146 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
1147 EFI_IP_ADDRESS *ClientIpPtr,
1148 EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr,
1149 DHCP_RECEIVE_BUFFER *DhcpRxBuf,
1150 EFI_EVENT TimeoutEvent
1151 )
1152 /*++
1153 Routine description:
1154 Wait for an OFFER/ACK packet.
1155
1156 Parameters:
1157 Private := Pointer to PxeBc interface
1158 ExtraEdit := Pointer to extra option checking function
1159 OpFlags := UdpRead() option flags
1160 ServerIpPtr :=
1161 ServerPortPtr :=
1162 ClientIpPtr :=
1163 ClientPortPtr :=
1164 DhcpRxBuf :=
1165 TimeoutEvent :=
1166
1167 Returns:
1168 --*/
1169 {
1170 EFI_IP_ADDRESS ServerIp;
1171 EFI_STATUS StatCode;
1172 INTN RxBufLen;
1173
1174 for (;;) {
1175 //
1176 // Wait until we get a UDP packet.
1177 //
1178 ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
1179 RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer;
1180
1181 if ((StatCode = UdpRead (
1182 Private,
1183 OpFlags,
1184 ClientIpPtr,
1185 ClientPortPtr,
1186 ServerIpPtr,
1187 ServerPortPtr,
1188 0,
1189 0,
1190 (UINTN *) &RxBufLen,
1191 &DhcpRxBuf->u.Dhcpv4,
1192 TimeoutEvent
1193 )) != EFI_SUCCESS) {
1194 if (StatCode == EFI_TIMEOUT) {
1195 StatCode = EFI_NO_RESPONSE;
1196 }
1197
1198 break;
1199 }
1200 //
1201 // got a packet - see if a good offer
1202 //
1203 if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) {
1204 continue;
1205 }
1206
1207 if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) {
1208 continue;
1209 }
1210
1211 if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) {
1212 continue;
1213 }
1214
1215 if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) {
1216 continue;
1217 }
1218
1219 if (CompareMem (
1220 DhcpRxBuf->u.Dhcpv4.chaddr,
1221 DHCPV4_TRANSMIT_BUFFER.chaddr,
1222 sizeof DhcpRxBuf->u.Dhcpv4.chaddr
1223 )) {
1224 //
1225 // no good
1226 //
1227 continue;
1228 }
1229
1230 Parse (DhcpRxBuf, RxBufLen);
1231
1232 if (!(*ExtraEdit) (DhcpRxBuf)) {
1233 continue;
1234 }
1235 //
1236 // Good DHCP packet.
1237 //
1238 StatCode = EFI_SUCCESS;
1239 break;
1240 }
1241
1242 return StatCode;
1243 }
1244
1245 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1246
1247 //
1248 // get DHCPOFFER's
1249 //
1250 EFI_STATUS
1251 GetOffers (
1252 PXE_BASECODE_DEVICE *Private
1253 )
1254 {
1255 EFI_IP_ADDRESS ClientIp;
1256 EFI_IP_ADDRESS ServerIp;
1257 EFI_STATUS StatCode;
1258 EFI_EVENT TimeoutEvent;
1259 INTN NumOffers;
1260 INTN Index;
1261
1262 //
1263 //
1264 //
1265 ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
1266 NumOffers = 0;
1267
1268 for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) {
1269 Private->ServerCount[Index] = 0;
1270 Private->GotProxy[Index] = 0;
1271 }
1272
1273 Private->GotBootp = 0;
1274 //
1275 // these we throw away
1276 //
1277 Private->GotProxy[DHCP_ONLY_IX] = 1;
1278 StatCode = gBS->CreateEvent (
1279 EVT_TIMER,
1280 TPL_CALLBACK,
1281 NULL,
1282 NULL,
1283 &TimeoutEvent
1284 );
1285
1286 if (EFI_ERROR (StatCode)) {
1287 return StatCode;
1288 }
1289
1290 StatCode = gBS->SetTimer (
1291 TimeoutEvent,
1292 TimerRelative,
1293 Private->Timeout * 10000000 + 1000000
1294 );
1295
1296 if (EFI_ERROR (StatCode)) {
1297 gBS->CloseEvent (TimeoutEvent);
1298 return StatCode;
1299 }
1300 //
1301 // get offers
1302 //
1303 for (;;) {
1304 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1305 UNION_PTR LocalPtr;
1306
1307 DhcpRxBuf = &RxBuf[NumOffers];
1308
1309 if ((
1310 StatCode = GetOfferAck (
1311 Private,
1312 DHCPOfferAckEdit,
1313 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
1314 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP |
1315 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
1316 &ServerIp,
1317 &DhcpServerPort,
1318 &ClientIp,
1319 &DHCPClientPort,
1320 DhcpRxBuf,
1321 TimeoutEvent
1322 )
1323 ) != EFI_SUCCESS
1324 ) {
1325 break;
1326 }
1327
1328 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
1329
1330 //
1331 // check type of offer
1332 //
1333 if (LocalPtr.OpPtr == NULL) {
1334 //
1335 // bootp - we only need one and make sure has bootfile
1336 //
1337 if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1338 continue;
1339 }
1340
1341 Private->GotBootp = (UINT8) (NumOffers + 1);
1342 }
1343 //
1344 // if a DHCP type, must be DHCPOFFER and must have server id
1345 //
1346 else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) {
1347 continue;
1348 } else {
1349 INTN TypeIx;
1350
1351 //
1352 // get type - PXE10, WfM11a, or BINL
1353 //
1354 if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) {
1355 TypeIx = PXE10_IX;
1356 } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) {
1357 //
1358 // WfM - make sure it has a bootfile
1359 //
1360 if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1361 continue;
1362 }
1363
1364 TypeIx = WfM11a_IX;
1365 } else {
1366 TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX;
1367 }
1368 //
1369 // check DHCP or proxy
1370 //
1371 if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) {
1372 //
1373 // proxy - only need one of each type if not BINL
1374 // and must have at least PXE_TYPE
1375 //
1376 if (TypeIx == BINL_IX) {
1377 Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers;
1378 } else if (Private->GotProxy[TypeIx]) {
1379 continue;
1380 } else {
1381 Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1);
1382 }
1383 } else {
1384 Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers;
1385 }
1386 }
1387
1388 if (++NumOffers == MAX_OFFERS) {
1389 break;
1390 }
1391 }
1392
1393 gBS->CloseEvent (TimeoutEvent);
1394 Private->NumOffersReceived = NumOffers;
1395
1396 return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE;
1397 }
1398
1399 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1400
1401 //
1402 // send DHCPDECLINE
1403 //
1404 STATIC
1405 VOID
1406 DeclineOffer (
1407 PXE_BASECODE_DEVICE *Private
1408 )
1409 {
1410 EFI_PXE_BASE_CODE_MODE *PxebcMode;
1411 UINT16 SaveSecs;
1412
1413 PxebcMode = Private->EfiBc.Mode;
1414 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1415
1416 DHCPV4_TRANSMIT_BUFFER.secs = 0;
1417 DHCPV4_TRANSMIT_BUFFER.flags = 0;
1418 SetMem (
1419 DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr),
1420 sizeof (DHCPOpStart) - sizeof (struct opdeclinestr),
1421 OP_PAD
1422 );
1423 DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE;
1424 CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (DHCPDECLINEoptions.OpDeclineEnd));
1425
1426 {
1427 EFI_IP_ADDRESS TmpIp;
1428
1429 CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp);
1430
1431 DoUdpWrite (
1432 Private,
1433 &TmpIp,
1434 &DhcpServerPort,
1435 &PxebcMode->StationIp,
1436 &DHCPClientPort
1437 );
1438 }
1439
1440 InitDhcpv4TxBuf (Private);
1441 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1442 Private->GoodStationIp = FALSE;
1443 }
1444
1445 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1446
1447 //
1448 // send DHCPRELEASE
1449 //
1450 STATIC
1451 BOOLEAN
1452 Release (
1453 PXE_BASECODE_DEVICE *Private
1454 )
1455 {
1456 EFI_PXE_BASE_CODE_MODE *PxebcMode;
1457 UINT16 SaveSecs;
1458
1459 PxebcMode = Private->EfiBc.Mode;
1460 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1461 DHCPV4_TRANSMIT_BUFFER.secs = 0;
1462
1463 SetMem (
1464 DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr),
1465 sizeof (DHCPOpStart) - sizeof (struct opreleasestr),
1466 OP_PAD
1467 );
1468
1469 DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE;
1470
1471 CopyMem (
1472 &DHCPRELEASEoptions.DhcServerIpPtr,
1473 (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1],
1474 sizeof DHCPRELEASEoptions.DhcServerIpPtr
1475 );
1476
1477 DHCPRELEASEoptions.End[0] = OP_END;
1478
1479 {
1480 EFI_IP_ADDRESS TmpIp;
1481
1482 CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp);
1483
1484 DoUdpWrite (
1485 Private,
1486 &TmpIp,
1487 &DhcpServerPort,
1488 &PxebcMode->StationIp,
1489 &DHCPClientPort
1490 );
1491 }
1492
1493 InitDhcpv4TxBuf (Private);
1494
1495 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1496 Private->GoodStationIp = FALSE;
1497 return FALSE;
1498 }
1499
1500 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1501 STATIC
1502 BOOLEAN
1503 GetBINLAck (
1504 PXE_BASECODE_DEVICE *Private,
1505 EFI_IP_ADDRESS *ServerIpPtr
1506 )
1507 {
1508 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1509 EFI_STATUS StatCode;
1510 EFI_EVENT TimeoutEvent;
1511
1512 //
1513 //
1514 //
1515 StatCode = gBS->CreateEvent (
1516 EVT_TIMER,
1517 TPL_CALLBACK,
1518 NULL,
1519 NULL,
1520 &TimeoutEvent
1521 );
1522
1523 if (EFI_ERROR (StatCode)) {
1524 return FALSE;
1525 }
1526
1527 StatCode = gBS->SetTimer (
1528 TimeoutEvent,
1529 TimerRelative,
1530 Private->Timeout * 10000000 + 1000000
1531 );
1532
1533 if (EFI_ERROR (StatCode)) {
1534 gBS->CloseEvent (TimeoutEvent);
1535 return FALSE;
1536 }
1537 //
1538 //
1539 //
1540 DhcpRxBuf = &PXE_BINL_BUFFER;
1541
1542 for (;;) {
1543 EFI_PXE_BASE_CODE_UDP_PORT BINLSrvPort;
1544
1545 BINLSrvPort = 0;
1546
1547 if (GetOfferAck (
1548 Private,
1549 AckEdit,
1550 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
1551 ServerIpPtr,
1552 &BINLSrvPort,
1553 &Private->EfiBc.Mode->StationIp,
1554 &PSEUDO_DHCP_CLIENT_PORT,
1555 DhcpRxBuf,
1556 TimeoutEvent
1557 ) != EFI_SUCCESS) {
1558 break;
1559 }
1560 //
1561 // make sure from whom we wanted
1562 //
1563 if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem (
1564 &ServerIpPtr->v4,
1565 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1566 sizeof (ServerIpPtr->v4)
1567 )) {
1568 gBS->CloseEvent (TimeoutEvent);
1569 //
1570 // got an ACK from server
1571 //
1572 return TRUE;
1573 }
1574 }
1575
1576 gBS->CloseEvent (TimeoutEvent);
1577 return FALSE;
1578 }
1579
1580 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1581
1582 //
1583 // make sure we can get BINL
1584 // send DHCPREQUEST to PXE server
1585 //
1586 STATIC
1587 BOOLEAN
1588 TryBINL (
1589 PXE_BASECODE_DEVICE *Private,
1590 INTN OfferIx
1591 )
1592 {
1593 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1594 EFI_IP_ADDRESS ServerIp;
1595 UINT16 SaveSecs;
1596 INTN Index;
1597
1598 DhcpRxBuf = &RxBuf[OfferIx];
1599
1600 //
1601 // use next server address first.
1602 //
1603 ServerIp.Addr[0] = DhcpRxBuf->u.Dhcpv4.siaddr;
1604 if (ServerIp.Addr[0] == 0) {
1605 //
1606 // next server address is NULL, use option 54.
1607 //
1608 CopyMem (
1609 ((EFI_IPv4_ADDRESS *) &ServerIp),
1610 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1611 sizeof (EFI_IPv4_ADDRESS)
1612 );
1613 }
1614
1615 //
1616 // client IP address - filled in by client if it knows it
1617 //
1618 CopyMem (
1619 ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr),
1620 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
1621 sizeof (EFI_IPv4_ADDRESS)
1622 );
1623
1624 SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD);
1625 DHCPV4_TRANSMIT_BUFFER.flags = 0;
1626 DHCPV4_OPTIONS_BUFFER.End[0] = OP_END;
1627 AddRouters (Private, DhcpRxBuf);
1628 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1629
1630 for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) {
1631 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
1632
1633 //
1634 // unicast DHCPREQUEST to PXE server
1635 //
1636 if (DoUdpWrite (
1637 Private,
1638 &ServerIp,
1639 &PseudoDhcpServerPort,
1640 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
1641 &PSEUDO_DHCP_CLIENT_PORT
1642 ) != EFI_SUCCESS) {
1643 break;
1644 }
1645
1646 if (!GetBINLAck (Private, &ServerIp)) {
1647 continue;
1648 }
1649 //
1650 // early exit failures
1651 // make sure a good ACK
1652 //
1653 if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || (
1654 !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
1655 )
1656 ) {
1657 break;
1658 }
1659
1660 Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
1661 return TRUE;
1662 }
1663 //
1664 // failed - reset seconds field, etc.
1665 //
1666 Private->EfiBc.Mode->RouteTableEntries = 0;
1667 //
1668 // reset
1669 //
1670 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1671 return FALSE;
1672 }
1673
1674 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1675 STATIC
1676 BOOLEAN
1677 TryFinishBINL (
1678 PXE_BASECODE_DEVICE *Private,
1679 INTN OfferIx
1680 )
1681 {
1682 if (TryBINL (Private, OfferIx)) {
1683 return TRUE;
1684 }
1685
1686 return Release (Private);
1687 }
1688
1689 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1690 STATIC
1691 BOOLEAN
1692 TryFinishProxyBINL (
1693 PXE_BASECODE_DEVICE *Private
1694 )
1695 {
1696 INTN Index;
1697
1698 for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) {
1699 if (TryBINL (Private, Private->BinlProxies[Index])) {
1700 return TRUE;
1701 }
1702 }
1703
1704 return Release (Private);
1705 }
1706
1707 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1708
1709 //
1710 // try to finish DORA - send DHCP request, wait for ACK, check with ARP
1711 //
1712 STATIC
1713 BOOLEAN
1714 TryFinishDORA (
1715 PXE_BASECODE_DEVICE *Private,
1716 INTN OfferIx
1717 )
1718 {
1719 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1720 EFI_IP_ADDRESS ClientIp;
1721 EFI_IP_ADDRESS ServerIp;
1722 EFI_STATUS StatCode;
1723 UNION_PTR LocalPtr;
1724 EFI_EVENT TimeoutEvent;
1725
1726 //
1727 // send DHCP request
1728 // if fail return false
1729 //
1730 DhcpRxBuf = &DHCPV4_ACK_BUFFER;
1731 DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
1732 CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (DHCP_REQ_OPTIONS));
1733 DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[OfferIx].u.Dhcpv4.yiaddr;
1734
1735 CopyMem (
1736 &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
1737 &((DHCPV4_OP_SERVER_IP *) RxBuf[OfferIx].OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1738 sizeof DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip
1739 );
1740
1741 CopyMem (
1742 Private->EfiBc.Mode->SubnetMask.Addr,
1743 &DefaultSubnetMask,
1744 4
1745 );
1746
1747 //
1748 // broadcast DHCPREQUEST
1749 //
1750 if (DoUdpWrite (
1751 Private,
1752 &BroadcastIP,
1753 &DhcpServerPort,
1754 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
1755 &DHCPClientPort
1756 ) != EFI_SUCCESS) {
1757 return FALSE;
1758 }
1759 //
1760 //
1761 //
1762 StatCode = gBS->CreateEvent (
1763 EVT_TIMER,
1764 TPL_CALLBACK,
1765 NULL,
1766 NULL,
1767 &TimeoutEvent
1768 );
1769
1770 if (EFI_ERROR (StatCode)) {
1771 return FALSE;
1772 }
1773
1774 StatCode = gBS->SetTimer (
1775 TimeoutEvent,
1776 TimerPeriodic,
1777 Private->Timeout * 10000000 + 1000000
1778 );
1779
1780 if (EFI_ERROR (StatCode)) {
1781 gBS->CloseEvent (TimeoutEvent);
1782 return FALSE;
1783 }
1784 //
1785 // wait for ACK
1786 //
1787 for (;;) {
1788 if (GetOfferAck (
1789 Private,
1790 DHCPAckEdit,
1791 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,
1792 &ServerIp,
1793 &DhcpServerPort,
1794 &ClientIp,
1795 &DHCPClientPort,
1796 DhcpRxBuf,
1797 TimeoutEvent
1798 ) != EFI_SUCCESS) {
1799 break;
1800 }
1801 //
1802 // check type of response - need DHCPACK
1803 //
1804 if (CompareMem (
1805 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
1806 &DhcpRxBuf->u.Dhcpv4.yiaddr,
1807 sizeof (EFI_IPv4_ADDRESS)
1808 ) || CompareMem (
1809 &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
1810 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1811 sizeof (EFI_IPv4_ADDRESS)
1812 )) {
1813 continue;
1814 }
1815 //
1816 // got ACK
1817 // check with ARP that IP unused - good return true
1818 //
1819 if (!SetStationIP (Private)) {
1820 //
1821 // fail - send DHCPDECLINE and return false
1822 //
1823 DeclineOffer (Private);
1824 break;
1825 }
1826
1827 LocalPtr.OpPtr = DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
1828
1829 if (LocalPtr.OpPtr != NULL) {
1830 CopyMem (
1831 (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask,
1832 &LocalPtr.SubnetMaskStr->Ip,
1833 sizeof (EFI_IPv4_ADDRESS)
1834 );
1835 }
1836
1837 AddRouters (Private, DhcpRxBuf);
1838 gBS->CloseEvent (TimeoutEvent);
1839 return TRUE;
1840 }
1841
1842 gBS->CloseEvent (TimeoutEvent);
1843 return FALSE;
1844 }
1845
1846 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1847
1848 //
1849 // try a DHCP server of appropriate type
1850 //
1851 STATIC
1852 BOOLEAN
1853 TryDHCPFinishDORA (
1854 PXE_BASECODE_DEVICE *Private,
1855 INTN TypeIx
1856 )
1857 {
1858 INTN Index;
1859
1860 //
1861 // go through the DHCP servers of the requested type
1862 //
1863 for (Index = 0; Index < Private->ServerCount[TypeIx]; ++Index) {
1864 if (TryFinishDORA (Private, Index = Private->OfferCount[TypeIx][Index])) {
1865 if (TypeIx == BINL_IX && !TryFinishBINL (Private, Index)) {
1866 continue;
1867 }
1868
1869 return TRUE;
1870 }
1871 }
1872
1873 return FALSE;
1874 }
1875
1876 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1877
1878 //
1879 // try a DHCP only server and a proxy of appropriate type
1880 //
1881 STATIC
1882 BOOLEAN
1883 TryProxyFinishDORA (
1884 PXE_BASECODE_DEVICE *Private,
1885 INTN TypeIx
1886 )
1887 {
1888 INTN Index;
1889
1890 if (!Private->GotProxy[TypeIx]) {
1891 //
1892 // no proxies of the type wanted
1893 //
1894 return FALSE;
1895 }
1896 //
1897 // go through the DHCP only servers
1898 //
1899 for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
1900 if (TryFinishDORA (Private, Private->OfferCount[DHCP_ONLY_IX][Index])) {
1901 if (TypeIx != BINL_IX) {
1902 CopyProxyRxBuf (Private, Private->GotProxy[TypeIx] - 1);
1903 } else if (!TryFinishProxyBINL (Private)) {
1904 //
1905 // if didn't work with this DHCP, won't work with any
1906 //
1907 return FALSE;
1908 }
1909
1910 return TRUE;
1911 }
1912 }
1913
1914 return FALSE;
1915 }
1916
1917 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1918
1919 //
1920 // getting to the bottom of the barrel
1921 //
1922 STATIC
1923 BOOLEAN
1924 TryAnyWithBootfileFinishDORA (
1925 PXE_BASECODE_DEVICE *Private
1926 )
1927 {
1928 //
1929 // try a DHCP only server who has a bootfile
1930 //
1931 UNION_PTR LocalPtr;
1932 INTN Index;
1933
1934 for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
1935 INTN offer;
1936
1937 offer = Private->OfferCount[DHCP_ONLY_IX][Index];
1938
1939 if (RxBuf[offer].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && TryFinishDORA (Private, offer)) {
1940 return TRUE;
1941 }
1942 }
1943 //
1944 // really at bottom - see if be have any bootps
1945 //
1946 if (!Private->GotBootp) {
1947 return FALSE;
1948 }
1949
1950 DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[Private->GotBootp - 1].u.Dhcpv4.yiaddr;
1951
1952 if (!SetStationIP (Private)) {
1953 return FALSE;
1954 }
1955 //
1956 // treat BOOTP response as DHCP ACK packet
1957 //
1958 CopyParseRxBuf (Private, Private->GotBootp - 1, DHCPV4_ACK_INDEX);
1959
1960 LocalPtr.OpPtr = RxBuf[Private->GotBootp - 1].OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
1961
1962 if (LocalPtr.OpPtr != NULL) {
1963 *(EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask = LocalPtr.SubnetMaskStr->Ip;
1964 }
1965
1966 return TRUE;
1967 }
1968
1969 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1970
1971 /* DoDhcpDora()
1972 */
1973 STATIC
1974 EFI_STATUS
1975 DoDhcpDora (
1976 PXE_BASECODE_DEVICE *Private,
1977 BOOLEAN SortOffers
1978 )
1979 {
1980 EFI_PXE_BASE_CODE_IP_FILTER Filter;
1981 EFI_STATUS StatCode;
1982 INTN NumOffers;
1983
1984 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
1985
1986 Filter.IpCnt = 0;
1987 Filter.reserved = 0;
1988
1989 //
1990 // set filter unicast or broadcast
1991 //
1992 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1993 return StatCode;
1994 }
1995 //
1996 // seed random number with hardware address
1997 //
1998 SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
1999
2000 for (Private->Timeout = 1;
2001 Private->Timeout < 17;
2002 Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), Private->Timeout <<= 1
2003 ) {
2004 INTN Index;
2005
2006 InitDhcpv4TxBuf (Private);
2007 DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
2008 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
2009
2010 //
2011 // broadcast DHCPDISCOVER
2012 //
2013 StatCode = DoUdpWrite (
2014 Private,
2015 &BroadcastIP,
2016 &DhcpServerPort,
2017 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2018 &DHCPClientPort
2019 );
2020
2021 if (StatCode != EFI_SUCCESS) {
2022 return StatCode;
2023 }
2024
2025 CopyMem (
2026 &Private->EfiBc.Mode->DhcpDiscover,
2027 (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
2028 sizeof (EFI_PXE_BASE_CODE_PACKET)
2029 );
2030
2031 //
2032 // get DHCPOFFER's
2033 //
2034 if ((StatCode = GetOffers (Private)) != EFI_SUCCESS) {
2035 if (StatCode != EFI_NO_RESPONSE) {
2036 return StatCode;
2037 }
2038
2039 continue;
2040 }
2041 //
2042 // select offer and reply DHCPREQUEST
2043 //
2044 if (SortOffers) {
2045 if (TryDHCPFinishDORA(Private, PXE10_IX) || // try DHCP with PXE10
2046 TryDHCPFinishDORA(Private, WfM11a_IX) || // no - try with WfM
2047 TryProxyFinishDORA(Private, PXE10_IX) || // no - try DHCP only and proxy with PXE10
2048 TryProxyFinishDORA(Private, WfM11a_IX) || // no - try DHCP only and proxy with WfM
2049 TryDHCPFinishDORA(Private, BINL_IX) || // no - try with WfM
2050 TryProxyFinishDORA(Private, BINL_IX) || // no - try DHCP only and proxy with PXE10
2051 TryAnyWithBootfileFinishDORA(Private))
2052 {
2053 return EFI_SUCCESS;
2054 }
2055
2056 continue;
2057 }
2058 //
2059 // FIFO order
2060 //
2061 NumOffers = Private->NumOffersReceived;
2062
2063 for (Index = 0; Index < NumOffers; ++Index) {
2064 //
2065 // ignore proxies
2066 //
2067 if (!RxBuf[Index].u.Dhcpv4.yiaddr) {
2068 continue;
2069 }
2070 //
2071 // check if a bootp server
2072 //
2073 if (!RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]) {
2074 //
2075 // it is - just check ARP
2076 //
2077 if (!SetStationIP (Private)) {
2078 continue;
2079 }
2080 }
2081 //
2082 // else check if a DHCP only server
2083 //
2084 else if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE))) {
2085 //
2086 // it is a normal DHCP offer (without any PXE options), just finish the D.O.R.A by sending DHCP request.
2087 //
2088 if (!TryFinishDORA (Private, Index)) {
2089 continue;
2090 }
2091 } else if (TryFinishDORA (Private, Index)) {
2092 if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) && !TryFinishBINL (Private, Index)) {
2093 continue;
2094 }
2095 }
2096
2097 DEBUG ((DEBUG_WARN, "\nDoDhcpDora() Got packets. "));
2098 return EFI_SUCCESS;
2099 }
2100 //
2101 // now look for DHCP onlys and a Proxy
2102 //
2103 for (Index = 0; Index < NumOffers; ++Index) {
2104 INT8 Index2;
2105
2106 //
2107 // ignore proxies, bootps, non DHCP onlys, and bootable DHCPS
2108 //
2109 if (!RxBuf[Index].u.Dhcpv4.yiaddr ||
2110 !RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1] ||
2111 RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE) ||
2112 RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
2113 ) {
2114 continue;
2115 }
2116 //
2117 // found non bootable DHCP only - try to find a proxy
2118 //
2119 for (Index2 = 0; Index2 < NumOffers; ++Index2) {
2120 if (!RxBuf[Index2].u.Dhcpv4.yiaddr) {
2121 if (!TryFinishDORA (Private, Index)) {
2122 //
2123 // DHCP no ACK
2124 //
2125 break;
2126 }
2127
2128 if (RxBuf[Index2].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) {
2129 CopyProxyRxBuf (Private, Index2);
2130 } else if (!TryFinishBINL (Private, Index2)) {
2131 continue;
2132 }
2133
2134 DEBUG ((DEBUG_WARN, "\nDoDhcpDora() Got packets. "));
2135 return EFI_SUCCESS;
2136 }
2137 }
2138 }
2139 }
2140
2141 return EFI_NO_RESPONSE;
2142 }
2143
2144 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2145
2146 //
2147 // determine if the server ip is in the ip list
2148 //
2149 BOOLEAN
2150 InServerList (
2151 EFI_IP_ADDRESS *ServerIpPtr,
2152 PXE_SERVER_LISTS *ServerListPtr
2153 )
2154 {
2155 UINTN Index;
2156
2157 if (!ServerListPtr || !ServerListPtr->Ipv4List.IpCount) {
2158 return TRUE;
2159 }
2160
2161 for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
2162 if (!CompareMem (
2163 ServerIpPtr,
2164 &ServerListPtr->Ipv4List.IpList[Index],
2165 sizeof (EFI_IPv4_ADDRESS)
2166 )) {
2167 return TRUE;
2168 }
2169 }
2170
2171 return FALSE;
2172 }
2173
2174 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2175 BOOLEAN
2176 ExtractBootServerList (
2177 UINT16 Type,
2178 DHCPV4_OP_STRUCT *ptr,
2179 PXE_SERVER_LISTS **ServerListPtr
2180 )
2181 {
2182 UNION_PTR LocalPtr;
2183 INTN ServerListLen;
2184
2185 LocalPtr.OpPtr = ptr;
2186 ServerListLen = LocalPtr.BootServersStr->Header.Length;
2187
2188 //
2189 // find type
2190 //
2191 LocalPtr.BootServerList = LocalPtr.BootServersStr->ServerList;
2192
2193 while (ServerListLen) {
2194 INTN ServerEntryLen;
2195
2196 ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (LocalPtr.BootServerList->u.Ipv4List.IpCount - 1) *
2197 sizeof (EFI_IPv4_ADDRESS);
2198
2199 if (NTOHS (LocalPtr.BootServerList->Type) == Type) {
2200 *ServerListPtr = &LocalPtr.BootServerList->u;
2201 return TRUE;
2202 }
2203
2204 (LocalPtr.BytePtr) += ServerEntryLen;
2205 ServerListLen -= ServerEntryLen;
2206 }
2207
2208 return FALSE;
2209 }
2210
2211 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2212 VOID
2213 FreeMem (
2214 PXE_BASECODE_DEVICE *Private
2215 )
2216 {
2217 if (Private->TransmitBuffer != NULL) {
2218 gBS->FreePool (Private->TransmitBuffer);
2219 Private->TransmitBuffer = NULL;
2220 }
2221
2222 if (Private->ReceiveBuffers != NULL) {
2223 gBS->FreePool (Private->ReceiveBuffers);
2224 Private->ReceiveBuffers = NULL;
2225 }
2226 }
2227
2228 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2229 BOOLEAN
2230 GetMem (
2231 PXE_BASECODE_DEVICE *Private
2232 )
2233 {
2234 EFI_STATUS Status;
2235
2236 if (Private->DhcpPacketBuffer == NULL) {
2237 Status = gBS->AllocatePool (
2238 EfiBootServicesData,
2239 sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
2240 &Private->DhcpPacketBuffer
2241 );
2242
2243 if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
2244 Private->DhcpPacketBuffer = NULL;
2245 FreeMem (Private);
2246 return FALSE;
2247 }
2248 }
2249
2250 Status = gBS->AllocatePool (
2251 EfiBootServicesData,
2252 sizeof (EFI_PXE_BASE_CODE_PACKET),
2253 &Private->TransmitBuffer
2254 );
2255
2256 if (EFI_ERROR (Status) || Private->TransmitBuffer == NULL) {
2257 gBS->FreePool (Private->DhcpPacketBuffer);
2258 Private->DhcpPacketBuffer = NULL;
2259 Private->TransmitBuffer = NULL;
2260 FreeMem (Private);
2261 return FALSE;
2262 }
2263
2264 Status = gBS->AllocatePool (
2265 EfiBootServicesData,
2266 sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS),
2267 &Private->ReceiveBuffers
2268 );
2269
2270 if (EFI_ERROR (Status) || Private->ReceiveBuffers == NULL) {
2271 gBS->FreePool (Private->TransmitBuffer);
2272 gBS->FreePool (Private->DhcpPacketBuffer);
2273 Private->DhcpPacketBuffer = NULL;
2274 Private->TransmitBuffer = NULL;
2275 Private->ReceiveBuffers = NULL;
2276 FreeMem (Private);
2277 return FALSE;
2278 }
2279
2280 return TRUE;
2281 }
2282
2283 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2284
2285 /**
2286
2287
2288 **/
2289 EFI_STATUS
2290 EFIAPI
2291 BcDhcp (
2292 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
2293 IN BOOLEAN SortOffers
2294 )
2295 {
2296 EFI_PXE_BASE_CODE_IP_FILTER Filter;
2297 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2298 PXE_BASECODE_DEVICE *Private;
2299 EFI_STATUS StatCode;
2300
2301 //
2302 // Lock the instance data and make sure started
2303 //
2304 StatCode = EFI_SUCCESS;
2305
2306 if (This == NULL) {
2307 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
2308 return EFI_INVALID_PARAMETER;
2309 }
2310
2311 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2312
2313 if (Private == NULL) {
2314 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));
2315 return EFI_INVALID_PARAMETER;
2316 }
2317
2318 EfiAcquireLock (&Private->Lock);
2319
2320 if (This->Mode == NULL || !This->Mode->Started) {
2321 DEBUG ((DEBUG_ERROR, "BC was not started."));
2322 EfiReleaseLock (&Private->Lock);
2323 return EFI_NOT_STARTED;
2324 }
2325
2326 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
2327 Filter.IpCnt = 0;
2328 Filter.reserved = 0;
2329
2330 DEBUG ((DEBUG_INFO, "\nBcDhcp() Enter. "));
2331
2332 PxebcMode = Private->EfiBc.Mode;
2333
2334 if (!GetMem (Private)) {
2335 DEBUG ((DEBUG_ERROR, "\nBcDhcp() GetMem() failed.\n"));
2336 EfiReleaseLock (&Private->Lock);
2337 return EFI_OUT_OF_RESOURCES;
2338 }
2339
2340 PxebcMode->DhcpDiscoverValid = FALSE;
2341 PxebcMode->DhcpAckReceived = FALSE;
2342 PxebcMode->ProxyOfferReceived = FALSE;
2343
2344 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
2345
2346 //
2347 // Issue BC command
2348 //
2349 if (Private->TotalSeconds == 0) {
2350 //
2351 // put in seconds field of DHCP send packets
2352 //
2353 Private->TotalSeconds = 4;
2354 }
2355
2356 if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) {
2357 //
2358 // success - copy packets
2359 //
2360 PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE;
2361
2362 CopyMem (
2363 &PxebcMode->DhcpAck,
2364 (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET,
2365 sizeof (EFI_PXE_BASE_CODE_PACKET)
2366 );
2367
2368 if (PxebcMode->ProxyOfferReceived) {
2369 CopyMem (
2370 &PxebcMode->ProxyOffer,
2371 (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET,
2372 sizeof (EFI_PXE_BASE_CODE_PACKET)
2373 );
2374 }
2375 }
2376 //
2377 // set filter back to unicast
2378 //
2379 IpFilter (Private, &Filter);
2380
2381 FreeMem (Private);
2382
2383 //
2384 // Unlock the instance data
2385 //
2386 DEBUG ((DEBUG_WARN, "\nBcDhcp() Exit = %xh ", StatCode));
2387
2388 EfiReleaseLock (&Private->Lock);
2389 return StatCode;
2390 }
2391
2392 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2393 STATIC
2394 BOOLEAN
2395 VerifyCredentialOption (
2396 UINT8 *tx,
2397 UINT8 *rx
2398 )
2399 {
2400 UINTN n;
2401
2402 //
2403 // Fail verification if either pointer is NULL.
2404 //
2405 if (tx == NULL || rx == NULL) {
2406 return FALSE;
2407 }
2408 //
2409 // Fail verification if tx[0] is not a credential type option
2410 // or if the length is zero or not a multiple of four.
2411 //
2412 if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) {
2413 return FALSE;
2414 }
2415 //
2416 // Fail verification if rx[0] is not a credential type option
2417 // or if the length is not equal to four.
2418 //
2419 if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) {
2420 return FALSE;
2421 }
2422 //
2423 // Look through transmitted credential types for a copy
2424 // of the received credential type.
2425 //
2426 for (n = 0; n < tx[1]; n += 4) {
2427 if (!CompareMem (&tx[n + 2], &rx[2], 4)) {
2428 return TRUE;
2429 }
2430 }
2431
2432 return FALSE;
2433 }
2434
2435 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2436
2437 /**
2438
2439
2440 **/
2441 EFI_STATUS
2442 DoDiscover (
2443 PXE_BASECODE_DEVICE *Private,
2444 UINT16 OpFlags,
2445 IN UINT16 Type,
2446 IN UINT16 *LayerPtr,
2447 IN BOOLEAN UseBis,
2448 EFI_IP_ADDRESS *DestPtr,
2449 PXE_SERVER_LISTS *ServerListPtr
2450 )
2451 {
2452 EFI_PXE_BASE_CODE_UDP_PORT ClientPort;
2453 EFI_PXE_BASE_CODE_UDP_PORT ServerPort;
2454 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2455 EFI_STATUS StatCode;
2456 EFI_EVENT TimeoutEvent;
2457 UINT8 OpLen;
2458
2459 PxebcMode = Private->EfiBc.Mode;
2460
2461 if (DestPtr->Addr[0] == 0) {
2462 DEBUG ((DEBUG_WARN, "\nDoDiscover() !DestPtr->Addr[0]"));
2463 return EFI_INVALID_PARAMETER;
2464 }
2465 //
2466 // seed random number with hardware address
2467 //
2468 SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
2469
2470 if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) {
2471 ClientPort = DHCPClientPort;
2472 ServerPort = DhcpServerPort;
2473 } else {
2474 ClientPort = PSEUDO_DHCP_CLIENT_PORT;
2475 ServerPort = PseudoDhcpServerPort;
2476 }
2477
2478 if (UseBis) {
2479 *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG;
2480 } else {
2481 *LayerPtr &= PXE_BOOT_LAYER_MASK;
2482 }
2483
2484 for (Private->Timeout = 1;
2485 Private->Timeout < 5;
2486 Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout
2487 ) {
2488 InitDhcpv4TxBuf (Private);
2489 //
2490 // initialize DHCP message structure
2491 //
2492 DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
2493 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
2494 CopyMem (
2495 &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2496 &PxebcMode->StationIp,
2497 sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr
2498 );
2499
2500 DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
2501 DISCOVERoptions.Header.OpCode = OP_VENDOR_SPECIFIC;
2502 DISCOVERoptions.BootItem.Header.OpCode = VEND_PXE_BOOT_ITEM;
2503 DISCOVERoptions.BootItem.Header.Length = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM);
2504 DISCOVERoptions.BootItem.Type = HTONS (Type);
2505 DISCOVERoptions.BootItem.Layer = HTONS (*LayerPtr);
2506
2507 if (UseBis) {
2508 EFI_BIS_PROTOCOL *BisPtr;
2509 BIS_APPLICATION_HANDLE BisAppHandle;
2510 EFI_BIS_DATA *BisDataSigInfo;
2511 EFI_BIS_SIGNATURE_INFO *BisSigInfo;
2512 UINTN Index;
2513 UINTN Index2;
2514
2515 BisPtr = PxebcBisStart (
2516 Private,
2517 &BisAppHandle,
2518 &BisDataSigInfo
2519 );
2520
2521 if (BisPtr == NULL) {
2522 //
2523 // %%TBD - In order to get here, BIS must have
2524 // been present when PXEBC.Start() was called.
2525 // BIS had to be shutdown/removed/damaged
2526 // before PXEBC.Discover() was called.
2527 // Do we need to document a specific error
2528 // for this case?
2529 //
2530 return EFI_OUT_OF_RESOURCES;
2531 }
2532 //
2533 // Compute number of credential types.
2534 //
2535 Index2 = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO);
2536
2537 DISCREDoptions.Header.OpCode = VEND_PXE_CREDENTIAL_TYPES;
2538
2539 DISCREDoptions.Header.Length = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL));
2540
2541 OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length);
2542
2543 BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data;
2544
2545 for (Index = 0; Index < Index2; ++Index) {
2546 UINT32 x;
2547
2548 CopyMem (&x, &BisSigInfo[Index], sizeof x);
2549 x = HTONL (x);
2550 CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x);
2551 }
2552
2553 PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
2554 } else {
2555 OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS);
2556 }
2557
2558 DISCOVERoptions.Header.Length = OpLen;
2559
2560 ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END;
2561 ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen] = OP_END;
2562
2563 StatCode = DoUdpWrite (
2564 Private,
2565 DestPtr,
2566 &ServerPort,
2567 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2568 &ClientPort
2569 );
2570
2571 if (StatCode != EFI_SUCCESS) {
2572 return StatCode;
2573 }
2574 //
2575 //
2576 //
2577 StatCode = gBS->CreateEvent (
2578 EVT_TIMER,
2579 TPL_CALLBACK,
2580 NULL,
2581 NULL,
2582 &TimeoutEvent
2583 );
2584
2585 if (EFI_ERROR (StatCode)) {
2586 return StatCode;
2587 }
2588
2589 StatCode = gBS->SetTimer (
2590 TimeoutEvent,
2591 TimerRelative,
2592 Private->Timeout * 10000000 + 1000000
2593 );
2594
2595 if (EFI_ERROR (StatCode)) {
2596 gBS->CloseEvent (TimeoutEvent);
2597 return StatCode;
2598 }
2599 //
2600 // wait for ACK
2601 //
2602 for (;;) {
2603 DHCP_RECEIVE_BUFFER *RxBufPtr;
2604 UINT16 TmpType;
2605 UINT16 TmpLayer;
2606
2607 RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER;
2608 ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
2609
2610 if (GetOfferAck (
2611 Private,
2612 AckEdit,
2613 OpFlags,
2614 (EFI_IP_ADDRESS *) &Private->ServerIp,
2615 0,
2616 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2617 &ClientPort,
2618 RxBufPtr,
2619 TimeoutEvent
2620 ) != EFI_SUCCESS) {
2621 break;
2622 }
2623 //
2624 // check type of response - need PXEClient DHCPACK of proper type with bootfile
2625 //
2626 if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) ||
2627 (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) ||
2628 !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] ||
2629 !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] ||
2630 !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) {
2631
2632 continue;
2633 }
2634
2635 TmpType = TmpLayer = 0;
2636
2637 if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
2638 TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type);
2639
2640 if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) {
2641 TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8);
2642 } else {
2643 TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer);
2644 }
2645 }
2646
2647 if (TmpType != Type) {
2648 continue;
2649 }
2650
2651 if (UseBis) {
2652 if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) {
2653 continue;
2654 }
2655
2656 if (!VerifyCredentialOption (
2657 (UINT8 *) &DISCREDoptions.Header,
2658 (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]
2659 )) {
2660 continue;
2661 }
2662 }
2663
2664 *LayerPtr = TmpLayer;
2665
2666 if (UseBis) {
2667 CopyMem (
2668 &PxebcMode->PxeBisReply,
2669 &RxBufPtr->u.Dhcpv4,
2670 sizeof (EFI_PXE_BASE_CODE_PACKET)
2671 );
2672
2673 PxebcMode->PxeBisReplyReceived = TRUE;
2674
2675 StatCode = DoDiscover (
2676 Private,
2677 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2678 Type,
2679 LayerPtr,
2680 FALSE,
2681 &Private->ServerIp,
2682 0
2683 );
2684
2685 gBS->CloseEvent (TimeoutEvent);
2686 return StatCode;
2687 }
2688
2689 PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE;
2690
2691 CopyMem (
2692 &PxebcMode->PxeDiscover,
2693 &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
2694 sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER)
2695 );
2696
2697 CopyMem (
2698 &PxebcMode->PxeReply,
2699 &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4,
2700 sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4)
2701 );
2702
2703 AddRouters (Private, RxBufPtr);
2704
2705 gBS->CloseEvent (TimeoutEvent);
2706 return EFI_SUCCESS;
2707 }
2708
2709 gBS->CloseEvent (TimeoutEvent);
2710 }
2711 //
2712 // end for loop
2713 //
2714 return EFI_TIMEOUT;
2715 }
2716
2717 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2718
2719 /**
2720 Parameters:
2721 Private := Pointer to PxeBc interface
2722 Type :=
2723 LayerPtr :=
2724 UseBis :=
2725 DiscoverInfoPtr :=
2726 McastServerListPtr :=
2727 ServerListPtr :=
2728
2729
2730 **/
2731 STATIC
2732 EFI_STATUS
2733 Discover (
2734 PXE_BASECODE_DEVICE *Private,
2735 IN UINT16 Type,
2736 IN UINT16 *LayerPtr,
2737 IN BOOLEAN UseBis,
2738 IN EFI_PXE_BASE_CODE_DISCOVER_INFO *DiscoverInfoPtr,
2739 PXE_SERVER_LISTS *McastServerListPtr,
2740 PXE_SERVER_LISTS *ServerListPtr
2741 )
2742 {
2743 EFI_IP_ADDRESS DestIp;
2744 EFI_STATUS StatCode;
2745
2746 DEBUG ((DEBUG_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr));
2747
2748 if (UseBis) {
2749 DEBUG ((DEBUG_INFO, "BIS "));
2750 }
2751 //
2752 // get dest IP addr - mcast, bcast, or unicast
2753 //
2754 if (DiscoverInfoPtr->UseMCast) {
2755 DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4;
2756
2757 DEBUG (
2758 (DEBUG_INFO,
2759 "\nDiscover() MCast %d.%d.%d.%d ",
2760 DestIp.v4.Addr[0],
2761 DestIp.v4.Addr[1],
2762 DestIp.v4.Addr[2],
2763 DestIp.v4.Addr[3])
2764 );
2765
2766 if ((StatCode = DoDiscover (
2767 Private,
2768 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2769 Type,
2770 LayerPtr,
2771 UseBis,
2772 &DestIp,
2773 McastServerListPtr
2774 )) != EFI_TIMEOUT) {
2775 DEBUG (
2776 (DEBUG_WARN,
2777 "\nDiscover() status == %r (%Xh)",
2778 StatCode,
2779 StatCode)
2780 );
2781
2782 return StatCode;
2783 }
2784 }
2785
2786 if (DiscoverInfoPtr->UseBCast) {
2787 DEBUG ((DEBUG_INFO, "\nDiscver() BCast "));
2788
2789 if ((StatCode = DoDiscover (
2790 Private,
2791 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2792 Type,
2793 LayerPtr,
2794 UseBis,
2795 &BroadcastIP,
2796 McastServerListPtr
2797 )) != EFI_TIMEOUT) {
2798
2799 DEBUG ((DEBUG_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode));
2800
2801 return StatCode;
2802 }
2803 }
2804
2805 if (DiscoverInfoPtr->UseUCast) {
2806 UINTN Index;
2807
2808 DEBUG (
2809 (DEBUG_INFO,
2810 "\nDiscover() UCast IP#=%d ",
2811 ServerListPtr->Ipv4List.IpCount)
2812 );
2813
2814 for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
2815 CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4);
2816
2817 DEBUG (
2818 (DEBUG_INFO,
2819 "\nDiscover() UCast %d.%d.%d.%d ",
2820 DestIp.v4.Addr[0],
2821 DestIp.v4.Addr[1],
2822 DestIp.v4.Addr[2],
2823 DestIp.v4.Addr[3])
2824 );
2825
2826 if ((StatCode = DoDiscover (
2827 Private,
2828 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2829 Type,
2830 LayerPtr,
2831 UseBis,
2832 &DestIp,
2833 0
2834 )) != EFI_TIMEOUT) {
2835 DEBUG (
2836 (DEBUG_WARN,
2837 "\nDiscover() status == %r (%Xh)",
2838 StatCode,
2839 StatCode)
2840 );
2841
2842 return StatCode;
2843 }
2844 }
2845 }
2846
2847 DEBUG ((DEBUG_WARN, "\nDiscover() TIMEOUT"));
2848
2849 return EFI_TIMEOUT;
2850 }
2851
2852 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2853
2854 /* BcDiscover()
2855 */
2856
2857 /**
2858
2859
2860 **/
2861 EFI_STATUS
2862 EFIAPI
2863 BcDiscover (
2864 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
2865 IN UINT16 Type,
2866 IN UINT16 *LayerPtr,
2867 IN BOOLEAN UseBis,
2868 IN EFI_PXE_BASE_CODE_DISCOVER_INFO * DiscoverInfoPtr OPTIONAL
2869 )
2870 {
2871 EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
2872 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2873 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
2874 PXE_SERVER_LISTS DefaultSrvList;
2875 PXE_SERVER_LISTS *ServerListPtr;
2876 PXE_SERVER_LISTS *McastServerListPtr;
2877 UNION_PTR LocalPtr;
2878 UINTN Index;
2879 UINTN Index2;
2880 BOOLEAN AcquiredSrvList;
2881 EFI_STATUS StatCode;
2882 PXE_BASECODE_DEVICE *Private;
2883
2884 //
2885 // Lock the instance data and make sure started
2886 //
2887 StatCode = EFI_SUCCESS;
2888
2889 if (This == NULL) {
2890 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
2891 return EFI_INVALID_PARAMETER;
2892 }
2893
2894 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2895
2896 if (Private == NULL) {
2897 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
2898 return EFI_INVALID_PARAMETER;
2899 }
2900
2901 EfiAcquireLock (&Private->Lock);
2902
2903 if (This->Mode == NULL || !This->Mode->Started) {
2904 DEBUG ((DEBUG_ERROR, "BC was not started."));
2905 EfiReleaseLock (&Private->Lock);
2906 return EFI_NOT_STARTED;
2907 }
2908
2909 ServerListPtr = NULL;
2910 McastServerListPtr = NULL;
2911 AcquiredSrvList = FALSE;
2912
2913 PxebcMode = Private->EfiBc.Mode;
2914
2915 if (!GetMem (Private)) {
2916 EfiReleaseLock (&Private->Lock);
2917 return EFI_OUT_OF_RESOURCES;
2918 }
2919
2920 if (UseBis) {
2921 if (!PxebcMode->BisSupported) {
2922 EfiReleaseLock (&Private->Lock);
2923 return EFI_INVALID_PARAMETER;
2924 }
2925 }
2926
2927 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
2928
2929 if (Private->TotalSeconds == 0) {
2930 //
2931 // put in seconds field of DHCP send packets
2932 //
2933 Private->TotalSeconds = 4;
2934 }
2935
2936 ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
2937
2938 //
2939 // if layer number not zero, use previous discover
2940 //
2941 if (*LayerPtr != 0) {
2942 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0"));
2943
2944 if (DiscoverInfoPtr != NULL) {
2945 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n"));
2946
2947 EfiReleaseLock (&Private->Lock);
2948 return EFI_INVALID_PARAMETER;
2949 }
2950
2951 if (!PxebcMode->PxeDiscoverValid) {
2952 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n"));
2953
2954 EfiReleaseLock (&Private->Lock);
2955 return EFI_INVALID_PARAMETER;
2956 }
2957
2958 if (!PxebcMode->PxeReplyReceived) {
2959 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n"));
2960
2961 EfiReleaseLock (&Private->Lock);
2962 return EFI_INVALID_PARAMETER;
2963 }
2964
2965 if (UseBis && !PxebcMode->PxeBisReplyReceived) {
2966 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeBisReplyReceived == 0\n"));
2967
2968 EfiReleaseLock (&Private->Lock);
2969 return EFI_INVALID_PARAMETER;
2970 }
2971
2972 DefaultInfo.UseUCast = TRUE;
2973 DiscoverInfoPtr = &DefaultInfo;
2974
2975 DefaultSrvList.Ipv4List.IpCount = 1;
2976 CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4);
2977
2978 ServerListPtr = &DefaultSrvList;
2979 }
2980 //
2981 // layer is zero - see if info is supplied or if we need to use info from a cached offer
2982 //
2983 else if (!DiscoverInfoPtr) {
2984 //
2985 // not supplied - generate it
2986 // make sure that there is cached, appropriate information
2987 // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail
2988 //
2989 DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
2990
2991 if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) {
2992 DEBUG ((DEBUG_WARN, "\nBcDiscover() !ack && !proxy"));
2993 EfiReleaseLock (&Private->Lock);
2994 return EFI_INVALID_PARAMETER;
2995 }
2996
2997 DiscoverInfoPtr = &DefaultInfo;
2998
2999 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
3000
3001 //
3002 // if multicast enabled, need multicast address
3003 //
3004 if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) {
3005 DefaultInfo.UseMCast = TRUE;
3006
3007 CopyMem (
3008 ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp),
3009 &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip,
3010 sizeof (EFI_IPv4_ADDRESS)
3011 );
3012 }
3013
3014 DefaultInfo.UseBCast = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0);
3015
3016 DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0);
3017
3018 DefaultInfo.UseUCast = (BOOLEAN)
3019 (
3020 (DefaultInfo.MustUseList) ||
3021 ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
3022 );
3023
3024 if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList (
3025 Type,
3026 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1],
3027 &ServerListPtr
3028 )) {
3029 DEBUG ((DEBUG_WARN, "\nBcDiscover() type not in list"));
3030 EfiReleaseLock (&Private->Lock);
3031 return EFI_INVALID_PARAMETER;
3032 }
3033 }
3034 //
3035 // Info supplied - make SrvList if required
3036 // if we use ucast discovery or must use list, there better be one
3037 //
3038 else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) {
3039 //
3040 // there better be a list
3041 //
3042 if (DiscoverInfoPtr->IpCnt == 0) {
3043 DEBUG ((DEBUG_WARN, "\nBcDiscover() no bootserver list"));
3044 EfiReleaseLock (&Private->Lock);
3045 return EFI_INVALID_PARAMETER;
3046 }
3047 //
3048 // get its size
3049 //
3050 for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
3051 if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
3052 if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) {
3053 if (Index2 != 0) {
3054 DEBUG ((DEBUG_WARN, "\nBcDiscover() accept any?"));
3055 EfiReleaseLock (&Private->Lock);
3056 return EFI_INVALID_PARAMETER;
3057 } else {
3058 Index2 = 1;
3059 DefaultSrvList.Ipv4List.IpCount = 0;
3060 ServerListPtr = &DefaultSrvList;
3061 break;
3062 }
3063 } else {
3064 ++Index2;
3065 }
3066 }
3067 }
3068
3069 if (Index2 == 0) {
3070 DEBUG ((DEBUG_WARN, "\nBcDiscover() !Index2?"));
3071 EfiReleaseLock (&Private->Lock);
3072 return EFI_INVALID_PARAMETER;
3073 }
3074
3075 if (ServerListPtr == NULL) {
3076 ServerListPtr = AllocatePool (
3077 sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS)
3078 );
3079
3080 if (ServerListPtr == NULL) {
3081 EfiReleaseLock (&Private->Lock);
3082 return EFI_OUT_OF_RESOURCES;
3083 }
3084 //
3085 // build an array of IP addresses from the server list
3086 //
3087 AcquiredSrvList = TRUE;
3088 ServerListPtr->Ipv4List.IpCount = (UINT8) Index2;
3089
3090 for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
3091 if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
3092 CopyMem (
3093 &ServerListPtr->Ipv4List.IpList[Index2++],
3094 &DiscoverInfoPtr->SrvList[Index].IpAddr.v4,
3095 sizeof ServerListPtr->Ipv4List.IpList[0]
3096 );
3097 }
3098 }
3099 }
3100 }
3101
3102 if (DiscoverInfoPtr->MustUseList) {
3103 McastServerListPtr = ServerListPtr;
3104 }
3105
3106 if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) {
3107 DEBUG ((DEBUG_WARN, "\nBcDiscover() Nothing to use!\n"));
3108
3109 EfiReleaseLock (&Private->Lock);
3110 return EFI_INVALID_PARAMETER;
3111 }
3112
3113 PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE;
3114
3115 StatCode = Discover (
3116 Private,
3117 Type,
3118 LayerPtr,
3119 UseBis,
3120 DiscoverInfoPtr,
3121 McastServerListPtr,
3122 ServerListPtr
3123 );
3124
3125 if (AcquiredSrvList) {
3126 gBS->FreePool (ServerListPtr);
3127 }
3128
3129 FreeMem (Private);
3130
3131 //
3132 // Unlock the instance data
3133 //
3134 DEBUG (
3135 (DEBUG_INFO,
3136 "\nBcDiscover() status == %r (%Xh)\n",
3137 StatCode,
3138 StatCode)
3139 );
3140
3141 EfiReleaseLock (&Private->Lock);
3142 return StatCode;
3143 }
3144
3145 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3146
3147 /**
3148
3149
3150 **/
3151 EFI_STATUS
3152 EFIAPI
3153 BcSetPackets (
3154 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
3155 BOOLEAN *NewDhcpDiscoverValid, OPTIONAL
3156 BOOLEAN *NewDhcpAckReceived, OPTIONAL
3157 BOOLEAN *NewProxyOfferReceived, OPTIONAL
3158 BOOLEAN *NewPxeDiscoverValid, OPTIONAL
3159 BOOLEAN *NewPxeReplyReceived, OPTIONAL
3160 BOOLEAN *NewPxeBisReplyReceived, OPTIONAL
3161 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
3162 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
3163 IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
3164 IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
3165 IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
3166 IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
3167 )
3168 {
3169 EFI_PXE_BASE_CODE_MODE *PxebcMode;
3170 EFI_STATUS Status;
3171 PXE_BASECODE_DEVICE *Private;
3172
3173 //
3174 // Lock the instance data and make sure started
3175 //
3176
3177 if (This == NULL) {
3178 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
3179 return EFI_INVALID_PARAMETER;
3180 }
3181
3182 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
3183
3184 if (Private == NULL) {
3185 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
3186 return EFI_INVALID_PARAMETER;
3187 }
3188
3189 EfiAcquireLock (&Private->Lock);
3190
3191 if (This->Mode == NULL || !This->Mode->Started) {
3192 DEBUG ((DEBUG_ERROR, "BC was not started."));
3193 EfiReleaseLock (&Private->Lock);
3194 return EFI_NOT_STARTED;
3195 }
3196
3197 PxebcMode = Private->EfiBc.Mode;
3198
3199 if (Private->DhcpPacketBuffer == NULL) {
3200 Status = gBS->AllocatePool (
3201 EfiBootServicesData,
3202 sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
3203 &Private->DhcpPacketBuffer
3204 );
3205
3206 if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
3207 Private->DhcpPacketBuffer = NULL;
3208 EfiReleaseLock (&Private->Lock);
3209 return EFI_OUT_OF_RESOURCES;
3210 }
3211 }
3212 //
3213 // Issue BC command
3214 //
3215 //
3216 // reset
3217 //
3218 Private->FileSize = 0;
3219 if (NewDhcpDiscoverValid != NULL) {
3220 PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
3221 }
3222
3223 if (NewDhcpAckReceived != NULL) {
3224 PxebcMode->DhcpAckReceived = *NewDhcpAckReceived;
3225 }
3226
3227 if (NewProxyOfferReceived != NULL) {
3228 PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived;
3229 }
3230
3231 if (NewPxeDiscoverValid != NULL) {
3232 PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid;
3233 }
3234
3235 if (NewPxeReplyReceived != NULL) {
3236 PxebcMode->PxeReplyReceived = *NewPxeReplyReceived;
3237 }
3238
3239 if (NewPxeBisReplyReceived != NULL) {
3240 PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
3241 }
3242
3243 if (NewDhcpDiscover != NULL) {
3244 CopyMem (
3245 &PxebcMode->DhcpDiscover,
3246 NewDhcpDiscover,
3247 sizeof *NewDhcpDiscover
3248 );
3249 }
3250
3251 if (NewDhcpAck != NULL) {
3252 CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX);
3253 }
3254
3255 if (NewProxyOffer != NULL) {
3256 CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX);
3257 }
3258
3259 if (NewPxeDiscover != NULL) {
3260 CopyMem (
3261 &PxebcMode->PxeDiscover,
3262 NewPxeDiscover,
3263 sizeof *NewPxeDiscover
3264 );
3265 }
3266
3267 if (NewPxeReply != NULL) {
3268 CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX);
3269 }
3270
3271 if (NewPxeBisReply != NULL) {
3272 CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX);
3273 }
3274 //
3275 // Unlock the instance data
3276 //
3277 EfiReleaseLock (&Private->Lock);
3278 return EFI_SUCCESS;
3279 }
3280
3281 /* eof - pxe_bc_dhcp.c */