]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c
Make MDE package pass intel IPF compiler with /W4 /WX switched on.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_dhcp.c
1 /*++
2
3 Copyright (c) 2006, 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 STATIC EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort = DHCP_SERVER_PORT;
24 STATIC EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort = DHCP_CLIENT_PORT;
25 STATIC EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort = PXE_DISCOVERY_PORT;
26 #define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort
27 STATIC EFI_IP_ADDRESS BroadcastIP = { { 0xffffffff } };
28 STATIC EFI_IP_ADDRESS DefaultSubnetMask = { { 0xffffff00 } };
29
30 typedef union {
31 DHCPV4_OP_STRUCT *OpPtr;
32 PXE_OP_SERVER_LIST *BootServersStr;
33 PXE_SERVER_LIST *BootServerList;
34 PXE_BOOT_MENU_ENTRY *BootMenuItem;
35 PXE_OP_DISCOVERY_CONTROL *DiscoveryControl;
36 PXE_OP_BOOT_MENU *BootMenu;
37 PXE_OP_BOOT_ITEM *BootItem;
38 DHCPV4_OP_VENDOR_OPTIONS *VendorOptions;
39 DHCPV4_OP_OVERLOAD *Overload;
40 DHCPV4_OP_CLASS *PxeClassStr;
41 DHCPV4_OP_SUBNET_MASK *SubnetMaskStr;
42 DHCPV4_OP_MESSAGE_TYPE *MessageType;
43 UINT8 *BytePtr;
44 } UNION_PTR;
45
46 #pragma pack(1)
47 //
48 // option structure for DHCPREQUEST at end of DISCOVER options
49 // and for DHCPDECLINE
50 //
51 STATIC const struct requestopendstr {
52 DHCPV4_OP_REQUESTED_IP OpReqIP;
53 DHCPV4_OP_SERVER_IP DhcServerIpPtr;
54 UINT8 End[1];
55 }
56 RequestOpEndStr = {
57 {
58 {
59 OP_DHCP_REQ_IP_ADD,
60 DHCPV4_OPTION_LENGTH(DHCPV4_OP_REQUESTED_IP)
61 }
62 },
63 {
64 {
65 OP_DHCP_SERVER_IP,
66 DHCPV4_OPTION_LENGTH(DHCPV4_OP_SERVER_IP)
67 }
68 },
69 {
70 OP_END
71 }
72 };
73
74 #define DHCP_REQ_OPTIONS (*(struct requestopendstr *) DHCPV4_OPTIONS_BUFFER.End)
75
76 PXE_OP_BOOT_ITEM DefaultBootItem = {
77 {
78 VEND_PXE_BOOT_ITEM,
79 DHCPV4_OPTION_LENGTH(PXE_OP_BOOT_ITEM)
80 },
81 0, 0,
82 };
83
84 //
85 // PXE discovery control default structure
86 //
87 STATIC PXE_OP_DISCOVERY_CONTROL DefaultDisCtl = {
88 { VEND_PXE_DISCOVERY_CONTROL, DHCPV4_OPTION_LENGTH(PXE_OP_DISCOVERY_CONTROL) },
89 0
90 };
91
92 //
93 // PXE credentials option structure
94 //
95 typedef struct {
96 UINT8 c[4];
97 } PXE_CREDENTIAL;
98
99 typedef struct {
100 DHCPV4_OP_HEADER Header;
101 PXE_CREDENTIAL Credentials[1];
102 } PXE_OP_CREDENTIAL_TYPES;
103
104 //
105 // option structure for PXE discover (without credentials)
106 //
107 typedef struct { // discoveropendstr {
108 DHCPV4_OP_HEADER Header; // vendor options
109 PXE_OP_BOOT_ITEM BootItem;
110 UINT8 End[1]; // if credentials option, it starts here
111 } PXE_DISCOVER_OPTIONS;
112
113 #define DISCOVERoptions (*(PXE_DISCOVER_OPTIONS *) DHCPV4_OPTIONS_BUFFER.End)
114 #define DISCREDoptions (*(PXE_OP_CREDENTIAL_TYPES *) DISCOVERoptions.End)
115
116 //
117 // common option beginning for all our DHCP messages except
118 // DHCPDECLINE and DHCPRELEASE
119 //
120 STATIC struct optionsstr {
121 UINT8 DhcpCookie[4];
122 DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
123 DHCPV4_OP_MAX_MESSAGE_SIZE DhcpMaxMessageSize;
124 DHCPV4_OP_REQUESTED_OPTIONS DhcpRequestedOptions;
125 DHCPV4_OP_PLATFORM_ID DhcpPlatformId;
126 DHCPV4_OP_NETWORK_INTERFACE DhcpNetworkInterface;
127 DHCPV4_OP_ARCHITECTURE_TYPE DhcpClientArchitecture;
128 DHCPV4_OP_CLASS_ID DhcpClassIdentifier;
129 UINT8 End[1];
130 } DHCPOpStart;
131
132 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
133 VOID
134 OptionsStrucInit (
135 VOID
136 )
137 {
138 DHCPOpStart.DhcpCookie[0] = 99;
139 DHCPOpStart.DhcpCookie[1] = 130;
140 DHCPOpStart.DhcpCookie[2] = 83;
141 DHCPOpStart.DhcpCookie[3] = 99;
142 DHCPOpStart.DhcpMessageType.Header.OpCode = OP_DHCP_MESSAGE_TYPE;
143 DHCPOpStart.DhcpMessageType.Header.Length = 1;
144 DHCPOpStart.DhcpMessageType.Type = DHCPDISCOVER;
145 DHCPOpStart.DhcpMaxMessageSize.Header.OpCode = OP_DHCP_MAX_MESSAGE_SZ;
146 DHCPOpStart.DhcpMaxMessageSize.Header.Length = 2;
147 DHCPOpStart.DhcpMaxMessageSize.MaxSize[0] = MAX_DHCP_MSG_SZ >> 8;
148 DHCPOpStart.DhcpMaxMessageSize.MaxSize[1] = MAX_DHCP_MSG_SZ & 0xff;
149 DHCPOpStart.DhcpRequestedOptions.Header.OpCode = OP_DHCP_PARM_REQ_LIST;
150 DHCPOpStart.DhcpRequestedOptions.Header.Length = sizeof (DHCPV4_REQUESTED_OPTIONS_DATA);
151 DHCPOpStart.DhcpRequestedOptions.Data._OP_SUBNET_MASK = OP_SUBNET_MASK; /* 1 */
152 DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_OFFSET = OP_TIME_OFFSET; /* 2 */
153 DHCPOpStart.DhcpRequestedOptions.Data._OP_ROUTER_LIST = OP_ROUTER_LIST; /* 3 */
154 DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_SERVERS = OP_TIME_SERVERS; /* 4 */
155 DHCPOpStart.DhcpRequestedOptions.Data._OP_NAME_SERVERS = OP_NAME_SERVERS; /* 5 */
156 DHCPOpStart.DhcpRequestedOptions.Data._OP_DNS_SERVERS = OP_DNS_SERVERS; /* 6 */
157 DHCPOpStart.DhcpRequestedOptions.Data._OP_HOST_NAME = OP_HOST_NAME; /* 12 */
158 DHCPOpStart.DhcpRequestedOptions.Data._OP_BOOT_FILE_SZ = OP_BOOT_FILE_SZ; /* 13 */
159 DHCPOpStart.DhcpRequestedOptions.Data._OP_DOMAIN_NAME = OP_DOMAIN_NAME; /* 15 */
160 DHCPOpStart.DhcpRequestedOptions.Data._OP_ROOT_PATH = OP_ROOT_PATH; /* 17 */
161 DHCPOpStart.DhcpRequestedOptions.Data._OP_EXTENSION_PATH = OP_EXTENSION_PATH; /* 18 */
162 DHCPOpStart.DhcpRequestedOptions.Data._OP_MAX_DATAGRAM_SZ = OP_MAX_DATAGRAM_SZ; /* 22 */
163 DHCPOpStart.DhcpRequestedOptions.Data._OP_DEFAULT_TTL = OP_DEFAULT_TTL; /* 23 */
164 DHCPOpStart.DhcpRequestedOptions.Data._OP_BROADCAST_ADD = OP_BROADCAST_ADD; /* 28 */
165 DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_DOMAIN_NAME = OP_NIS_DOMAIN_NAME; /* 40 */
166 DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_SERVERS = OP_NIS_SERVERS; /* 41 */
167 DHCPOpStart.DhcpRequestedOptions.Data._OP_NTP_SERVERS = OP_NTP_SERVERS; /* 42 */
168 DHCPOpStart.DhcpRequestedOptions.Data._OP_VENDOR_SPECIFIC = OP_VENDOR_SPECIFIC; /* 43 */
169 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REQ_IP_ADD = OP_DHCP_REQ_IP_ADD; /* 50 */
170 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_LEASE_TIME = OP_DHCP_LEASE_TIME; /* 51 */
171 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_SERVER_IP = OP_DHCP_SERVER_IP; /* 54 */
172 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_RENEWAL_TIME = OP_DHCP_RENEWAL_TIME; /* 58 */
173 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REBINDING_TIME = OP_DHCP_REBINDING_TIME; /* 59 */
174 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_CLASS_IDENTIFIER = OP_DHCP_CLASS_IDENTIFIER; /* 60 */
175 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_TFTP_SERVER_NAME = OP_DHCP_TFTP_SERVER_NAME; /* 66 */
176 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_BOOTFILE = OP_DHCP_BOOTFILE; /* 67 */
177 DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_PLATFORM_ID = OP_DHCP_PLATFORM_ID; /* 97 */
178 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption128 = 128;
179 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption129 = 129;
180 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption130 = 130;
181 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption131 = 131;
182 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption132 = 132;
183 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption133 = 133, DHCPOpStart.DhcpRequestedOptions.Data.VendorOption134 = 134;
184 DHCPOpStart.DhcpRequestedOptions.Data.VendorOption135 = 135;
185 DHCPOpStart.DhcpPlatformId.Header.OpCode = OP_DHCP_PLATFORM_ID;
186 DHCPOpStart.DhcpPlatformId.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_PLATFORM_ID);
187 DHCPOpStart.DhcpNetworkInterface.Header.OpCode = OP_DHCP_NETWORK_ARCH;
188 DHCPOpStart.DhcpNetworkInterface.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_NETWORK_INTERFACE);
189 DHCPOpStart.DhcpNetworkInterface.Type = 0;
190 DHCPOpStart.DhcpNetworkInterface.MajorVersion = 0;
191 DHCPOpStart.DhcpNetworkInterface.MinorVersion = 0;
192 DHCPOpStart.DhcpClientArchitecture.Header.OpCode = OP_DHCP_SYSTEM_ARCH;
193 DHCPOpStart.DhcpClientArchitecture.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_ARCHITECTURE_TYPE);
194 DHCPOpStart.DhcpClientArchitecture.Type = HTONS (SYS_ARCH);
195 DHCPOpStart.DhcpClassIdentifier.Header.OpCode = OP_DHCP_CLASS_IDENTIFIER;
196 DHCPOpStart.DhcpClassIdentifier.Header.Length = sizeof (DHCPV4_CLASS_ID_DATA);
197 CopyMem (
198 DHCPOpStart.DhcpClassIdentifier.Data.ClassIdentifier,
199 "PXEClient:",
200 sizeof ("PXEClient:")
201 );
202 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit2, "Arch:", sizeof ("Arch:"));
203 CopyMem (
204 DHCPOpStart.DhcpClassIdentifier.Data.ArchitectureType,
205 "xxxxx",
206 sizeof ("xxxxx")
207 );
208 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit3, ":", sizeof (":"));
209 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.InterfaceName, "XXXX", sizeof ("XXXX"));
210 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit4, ":", sizeof (":"));
211 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMajor, "yyy", sizeof ("yyy"));
212 CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMinor, "xxx", sizeof ("xxx"));
213 DHCPOpStart.End[0] = OP_END;
214 };
215
216 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
217
218 //
219 // DHCPDECLINE option structure
220 //
221 struct opdeclinestr {
222 UINT8 DhcpCookie[4];
223 DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
224 struct requestopendstr OpDeclineEnd;
225 };
226
227 #define DHCPDECLINEoptions (*(struct opdeclinestr *) DHCPV4_TRANSMIT_BUFFER.options)
228
229 //
230 // DHCPRELEASE option structure
231 //
232 struct opreleasestr {
233 UINT8 DhcpCookie[4];
234 DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
235 DHCPV4_OP_SERVER_IP DhcServerIpPtr;
236 UINT8 End[1];
237 };
238
239 #define DHCPRELEASEoptions (*(struct opreleasestr *) DHCPV4_TRANSMIT_BUFFER.options)
240
241 //
242 // array of PXE vendor options in which we are interested
243 // value 0 -> not of interest, else value is index into PXE OPTION array
244 // option values from 1 to MAX_OUR_PXE_OPT
245 //
246 STATIC UINT8 ourPXEopts[MAX_OUR_PXE_OPT] = {
247 VEND_PXE_MTFTP_IP_IX, // multicast IP address of bootfile for MTFTP listen
248 VEND_PXE_MTFTP_CPORT_IX, // UDP Port to monitor for MTFTP responses - Intel order
249 VEND_PXE_MTFTP_SPORT_IX, // Server UDP Port for MTFTP open - Intel order
250 VEND_PXE_MTFTP_TMOUT_IX, // Listen timeout - secs
251 VEND_PXE_MTFTP_DELAY_IX, // Transmission timeout - secs
252 VEND_PXE_DISCOVERY_CONTROL_IX, // bit field
253 VEND_PXE_DISCOVERY_MCAST_ADDR_IX, // boot server discovery multicast address
254 VEND_PXE_BOOT_SERVERS_IX, // list of boot servers of form tp(2) cnt(1) ips[cnt]
255 VEND_PXE_BOOT_MENU_IX,
256 VEND_PXE_BOOT_PROMPT_IX,
257 VEND_PXE_MCAST_ADDRS_ALLOC_IX, // not used by client
258 VEND_PXE_CREDENTIAL_TYPES_IX,
259 VEND_13_IX, // not used by client
260 VEND_14_IX, // not used by client
261 VEND_15_IX, // not used by client
262 VEND_16_IX, // not used by client
263 VEND_17_IX, // not used by client
264 VEND_18_IX, // not used by client
265 VEND_19_IX, // not used by client
266 VEND_20_IX, // not used by client
267 VEND_21_IX, // not used by client
268 VEND_22_IX, // not used by client
269 VEND_23_IX, // not used by client
270 VEND_24_IX, // not used by client
271 VEND_25_IX, // not used by client
272 VEND_26_IX, // not used by client
273 VEND_27_IX, // not used by client
274 VEND_28_IX, // not used by client
275 VEND_29_IX, // not used by client
276 VEND_30_IX, // not used by client
277 VEND_31_IX, // not used by client
278 VEND_32_IX, // not used by client
279 VEND_33_IX, // not used by client
280 VEND_34_IX, // not used by client
281 VEND_35_IX, // not used by client
282 VEND_36_IX, // not used by client
283 VEND_37_IX, // not used by client
284 VEND_38_IX, // not used by client
285 VEND_39_IX, // not used by client
286 VEND_40_IX, // not used by client
287 VEND_41_IX, // not used by client
288 VEND_42_IX, // not used by client
289 VEND_43_IX, // not used by client
290 VEND_44_IX, // not used by client
291 VEND_45_IX, // not used by client
292 VEND_46_IX, // not used by client
293 VEND_47_IX, // not used by client
294 VEND_48_IX, // not used by client
295 VEND_49_IX, // not used by client
296 VEND_50_IX, // not used by client
297 VEND_51_IX, // not used by client
298 VEND_52_IX, // not used by client
299 VEND_53_IX, // not used by client
300 VEND_54_IX, // not used by client
301 VEND_55_IX, // not used by client
302 VEND_56_IX, // not used by client
303 VEND_57_IX, // not used by client
304 VEND_58_IX, // not used by client
305 VEND_59_IX, // not used by client
306 VEND_60_IX, // not used by client
307 VEND_61_IX, // not used by client
308 VEND_62_IX, // not used by client
309 VEND_63_IX, // not used by client
310 VEND_64_IX, // not used by client
311 VEND_65_IX, // not used by client
312 VEND_66_IX, // not used by client
313 VEND_67_IX, // not used by client
314 VEND_68_IX, // not used by client
315 VEND_69_IX, // not used by client
316 VEND_70_IX, // not used by client
317 VEND_PXE_BOOT_ITEM_IX
318 };
319
320 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
321
322 //
323 // array of options in which we are interested
324 // value 0 -> not of interest, else value is index into OPTION array
325 // option values from 1 to MAX_OUR_OPT
326 //
327 STATIC UINT8 OurDhcpOptions[MAX_OUR_OPT] = {
328 OP_SUBNET_MASK_IX, // OP_SUBNET_MASK 1 // data is the subnet mask
329 OP_TIME_OFFSET_IX, // OP_TIME_OFFSET 2 // data is the time offset of subnet to UTC in seconds
330 OP_ROUTER_LIST_IX, // OP_ROUTER_LIST 3 // list of routers on subnet
331 OP_TIME_SERVERS_IX, // OP_TIME_SERVERS 4 // list of time servers available
332 OP_NAME_SERVERS_IX, // OP_NAME_SERVERS 5 // list of name servers available
333 OP_DNS_SERVERS_IX, // OP_DNS_SERVERS 6 // list of DNS servers available
334 OP_LOG_SERVERS_IX, // OP_LOG_SERVERS 7
335 OP_COOKIE_SERVERS_IX, // OP_COOKIE_SERVERS 8
336 OP_LPR_SREVERS_IX, // OP_LPR_SREVERS 9
337 OP_IMPRESS_SERVERS_IX, // OP_IMPRESS_SERVERS 10
338 OP_RES_LOC_SERVERS_IX, // OP_RES_LOC_SERVERS 11
339 OP_HOST_NAME_IX, // OP_HOST_NAME 12 // client name
340 OP_BOOT_FILE_SZ_IX, // OP_BOOT_FILE_SZ 13 // number of 512 blocks of boot file
341 OP_DUMP_FILE_IX, // OP_DUMP_FILE 14 // path name of dump file if client crashes
342 OP_DOMAIN_NAME_IX, // OP_DOMAIN_NAME 15 // domain name to use
343 OP_SWAP_SERVER_IX, // OP_SWAP_SERVER 16
344 OP_ROOT_PATH_IX, // OP_ROOT_PATH 17 // path name containing root disk
345 OP_EXTENSION_PATH_IX, // OP_EXTENSION_PATH 18 // name of TFTP downloadable file of form of OP
346 OP_IP_FORWARDING_IX, // OP_IP_FORWARDING 19 // enable/disable IP packet forwarding
347 OP_NON_LOCAL_SRC_RTE_IX, // OP_NON_LOCAL_SRC_RTE 20 // enable/disable non local source routing
348 OP_POLICY_FILTER_IX, // OP_POLICY_FILTER 21 // policy filters for non local source routing
349 OP_MAX_DATAGRAM_SZ_IX, // OP_MAX_DATAGRAM_SZ 22 // maximum datagram reassembly size
350 OP_DEFAULT_TTL_IX, // OP_DEFAULT_TTL 23 // default IP time to live
351 OP_MTU_AGING_TIMEOUT_IX, // OP_MTU_AGING_TIMEOUT 24
352 OP_MTU_SIZES_IX, // OP_MTU_SIZES 25
353 OP_MTU_TO_USE_IX, // OP_MTU_TO_USE 26
354 OP_ALL_SUBNETS_LOCAL_IX, // OP_ALL_SUBNETS_LOCAL 27
355 OP_BROADCAST_ADD_IX, // OP_BROADCAST_ADD 28 // broadcast address used on subnet
356 OP_PERFORM_MASK_DISCOVERY_IX, // OP_PERFORM_MASK_DISCOVERY 29 // perform mask discovery using ICMP
357 OP_RESPOND_TO_MASK_REQ_IX, // OP_RESPOND_TO_MASK_REQ 30 // respond to subnet mask requests using ICMP
358 OP_PERFORM_ROUTER_DISCOVERY_IX, // OP_PERFORM_ROUTER_DISCOVERY 31
359 OP_ROUTER_SOLICIT_ADDRESS_IX, // OP_ROUTER_SOLICIT_ADDRESS 32
360 OP_STATIC_ROUTER_LIST_IX, // OP_STATIC_ROUTER_LIST 33 // list of dest/route pairs
361 OP_USE_ARP_TRAILERS_IX, // OP_USE_ARP_TRAILERS 34
362 OP_ARP_CACHE_TIMEOUT_IX, // OP_ARP_CACHE_TIMEOUT 35
363 OP_ETHERNET_ENCAPSULATION_IX, // OP_ETHERNET_ENCAPSULATION 36 // 0 -> RFC 894, 1 -> IEEE 802.3 (RFC 1042)
364 OP_TCP_DEFAULT_TTL_IX, // OP_TCP_DEFAULT_TTL 37 // default time to live when sending TCP segments
365 OP_TCP_KEEP_ALIVE_INT_IX, // OP_TCP_KEEP_ALIVE_INT 38 // keep alive interval in seconds
366 OP_KEEP_ALIVE_GARBAGE_IX, // OP_KEEP_ALIVE_GARBAGE 39
367 OP_NIS_DOMAIN_NAME_IX, // OP_NIS_DOMAIN_NAME 40
368 OP_NIS_SERVERS_IX, // OP_NIS_SERVERS 41
369 OP_NTP_SERVERS_IX, // OP_NTP_SERVERS 42
370 OP_VENDOR_SPECIFIC_IX, // OP_VENDOR_SPECIFIC 43
371 OP_NBNS_SERVERS_IX, // OP_NBNS_SERVERS 44
372 OP_NBDD_SERVERS_IX, // OP_NBDD_SERVERS 45
373 OP_NETBIOS_NODE_TYPE_IX, // OP_NETBIOS_NODE_TYPE 46
374 OP_NETBIOS_SCOPE_IX, // OP_NETBIOS_SCOPE 47
375 OP_XWINDOW_SYSTEM_FONT_SERVERS_IX, // OP_XWINDOW_SYSTEM_FONT_SERVERS 48
376 OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX, // OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49
377 OP_DHCP_REQ_IP_ADD_IX, // OP_DHCP_REQ_IP_ADD 50 // requested IP address - in DHCPDISCOVER
378 OP_DHCP_LEASE_TIME_IX, // OP_DHCP_LEASE_TIME 51 // lease time requested/granted
379 OP_DHCP_OPTION_OVERLOAD_IX, // OP_DHCP_OPTION_OVERLOAD 52 // file/server name/both used to hold options
380 OP_DHCP_MESSAGE_TYPE_IX, // OP_DHCP_MESSAGE_TYPE 53 // message type
381 OP_DHCP_SERVER_IP_IX, // OP_DHCP_SERVER_IP 54 // IP of server
382 OP_DHCP_PARM_REQ_LIST_IX, // OP_DHCP_PARM_REQ_LIST 55 // list of requested parameters
383 OP_DHCP_ERROR_MESSAGE_IX, // OP_DHCP_ERROR_MESSAGE 56 // in DHCPNAK or DECLINE messages
384 OP_DHCP_MAX_MESSAGE_SZ_IX, // OP_DHCP_MAX_MESSAGE_SZ 57 // maximum DHCP message size client will accept
385 OP_DHCP_RENEWAL_TIME_IX, // OP_DHCP_RENEWAL_TIME 58 // time in seconds before transitioning to RENEWING state
386 OP_DHCP_REBINDING_TIME_IX, // OP_DHCP_REBINDING_TIME 59 // time in seconds before transitioning to REBINDING state
387 OP_DHCP_CLASS_IDENTIFIER_IX, // OP_DHCP_CLASS_IDENTIFIER 60
388 OP_DHCP_CLIENT_IDENTIFIER_IX, // OP_DHCP_CLIENT_IDENTIFIER 61
389 OP_RESERVED62_IX, // OP_RESERVED62
390 OP_RESERVED63_IX, // OP_RESERVED63
391 OP_NISPLUS_DOMAIN_NAME_IX, // OP_NISPLUS_DOMAIN_NAME 64
392 OP_NISPLUS_SERVERS_IX, // OP_NISPLUS_SERVERS 65
393 OP_DHCP_TFTP_SERVER_NAME_IX, // OP_DHCP_TFTP_SERVER_NAME 66
394 OP_DHCP_BOOTFILE_IX // OP_DHCP_BOOTFILE 67
395 };
396
397 #define RxBuf ((DHCP_RECEIVE_BUFFER *) (Private->ReceiveBuffers))
398
399 #pragma pack()
400
401 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
402 CHAR8 *
403 PxeBcLibGetSmbiosString (
404 IN SMBIOS_STRUCTURE_POINTER *Smbios,
405 IN UINT16 StringNumber
406 )
407 /*++
408 Routine description:
409 Return SMBIOS string given the string number.
410
411 Arguments:
412 Smbios - Pointer to SMBIOS structure
413 StringNumber - String number to return. 0 is used to skip all strings and
414 point to the next SMBIOS structure.
415
416 Returns:
417 Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0
418 --*/
419 {
420 UINT16 Index;
421 CHAR8 *String;
422
423 //
424 // Skip over formatted section
425 //
426 String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);
427
428 //
429 // Look through unformated section
430 //
431 for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {
432 if (StringNumber == Index) {
433 return String;
434 }
435 //
436 // Skip string
437 //
438 for (; *String != 0; String++)
439 ;
440 String++;
441
442 if (*String == 0) {
443 //
444 // If double NULL then we are done.
445 // Return pointer to next structure in Smbios.
446 // if you pass in a 0 you will always get here
447 //
448 Smbios->Raw = (UINT8 *)++String;
449 return NULL;
450 }
451 }
452
453 return NULL;
454 }
455
456 EFI_STATUS
457 PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
458 IN EFI_GUID *SystemGuid,
459 OUT CHAR8 **SystemSerialNumber
460 )
461 /*++
462
463 Routine Description:
464 This function gets system guid and serial number from the smbios table
465
466 Arguments:
467 SystemGuid - The pointer of returned system guid
468 SystemSerialNumber - The pointer of returned system serial number
469
470 Returns:
471 EFI_SUCCESS - Successfully get the system guid and system serial number
472 EFI_NOT_FOUND - Not find the SMBIOS table
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 EFI_EVENT_TIMER,
590 EFI_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 Ip4AddRouter (Private, &RxBufPtr->u.Dhcpv4.giaddr);
624
625 Ip4AddRouterList (
626 Private,
627 (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1]
628 );
629 }
630
631 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
632 STATIC
633 EFI_STATUS
634 DoUdpWrite (
635 PXE_BASECODE_DEVICE *Private,
636 EFI_IP_ADDRESS *ServerIpPtr,
637 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
638 EFI_IP_ADDRESS *ClientIpPtr,
639 EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr
640 )
641 {
642 UINTN Len;
643
644 Len = sizeof DHCPV4_TRANSMIT_BUFFER;
645
646 return UdpWrite (
647 Private,
648 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
649 ServerIpPtr,
650 ServerPortPtr,
651 0,
652 ClientIpPtr,
653 ClientPortPtr,
654 0,
655 0,
656 &Len,
657 Private->TransmitBuffer
658 );
659 }
660
661 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
662
663 //
664 // initialize the DHCP structure
665 //
666 typedef struct {
667 UINT8 x[4];
668 } C4Str;
669
670 STATIC
671 VOID
672 InitDhcpv4TxBuf (
673 PXE_BASECODE_DEVICE *Private
674 )
675 {
676 UINTN HwAddrLen;
677 UINT8 *String;
678 CHAR8 *SystemSerialNumber;
679 EFI_PXE_BASE_CODE_MODE *PxebcMode;
680
681 PxebcMode = Private->EfiBc.Mode;
682
683 ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT));
684 DHCPV4_TRANSMIT_BUFFER.op = BOOTP_REQUEST;
685 DHCPV4_TRANSMIT_BUFFER.htype = Private->SimpleNetwork->Mode->IfType;
686 DHCPV4_TRANSMIT_BUFFER.flags = HTONS (DHCP_BROADCAST_FLAG);
687 CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart));
688
689 //
690 // default to hardware address
691 //
692 HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize;
693
694 if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) {
695 HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr;
696 }
697
698 String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress;
699
700 if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
701 (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid,
702 &SystemSerialNumber
703 ) == EFI_SUCCESS) {
704 if (PxebcMode->SendGUID) {
705 HwAddrLen = sizeof (EFI_GUID);
706 String = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid;
707 }
708 } else {
709 //
710 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
711 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
712 // GUID not yet set - send all 0's to show not programable
713 //
714 ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID));
715 }
716
717 DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen;
718 CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen);
719
720 CvtNum (
721 SYS_ARCH,
722 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType,
723 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType
724 );
725
726 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type = Private->NiiPtr->Type;
727 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion = Private->NiiPtr->MajorVer;
728 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion = Private->NiiPtr->MinorVer;
729
730 *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId;
731
732 CvtNum (
733 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion,
734 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor,
735 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor
736 );
737
738 CvtNum (
739 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion,
740 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor,
741 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor
742 );
743 }
744
745 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
746 STATIC
747 UINT32
748 DecodePxeOptions (
749 DHCP_RECEIVE_BUFFER *RxBufPtr,
750 UINT8 *ptr,
751 INTN Len
752 )
753 {
754 UINT8 Op;
755 UINT8 *EndPtr;
756 INTN Index;
757 UNION_PTR LocalPtr;
758 UINT32 status;
759
760 status = 0;
761
762 for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
763 Op = ptr[0];
764 Len = ptr[1];
765
766 switch (Op) {
767 case OP_PAD:
768 Len = -1;
769 break;
770
771 case OP_END:
772 return status;
773
774 default:
775 LocalPtr.BytePtr = ptr;
776 if (Op <= MAX_OUR_PXE_OPT) {
777 Index = ourPXEopts[Op - 1];
778 if (Index) {
779 RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr;
780 status |= 1 << Index;
781 if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) {
782 RxBufPtr->OpAdds.Status |= USE_THREE_BYTE;
783 }
784 }
785 }
786 break;
787 }
788 }
789
790 return status;
791 }
792
793 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
794 STATIC
795 VOID
796 DecodeOptions (
797 DHCP_RECEIVE_BUFFER *RxBufPtr,
798 UINT8 *ptr,
799 INTN Len
800 )
801 {
802 UINT8 Op;
803 UINT8 *EndPtr;
804 INTN Index;
805 UNION_PTR LocalPtr;
806
807 for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
808 Op = ptr[0];
809 Len = ptr[1];
810
811 switch (Op) {
812 case OP_PAD:
813 Len = -1;
814 break;
815
816 case OP_END:
817 return ;
818
819 default:
820 LocalPtr.BytePtr = ptr;
821 if (Op <= MAX_OUR_OPT) {
822 Index = OurDhcpOptions[Op - 1];
823 if (Index) {
824 RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr;
825 if (Index == OP_VENDOR_SPECIFIC_IX) {
826 UINT32 status;
827 status = DecodePxeOptions (
828 RxBufPtr,
829 (UINT8 *) LocalPtr.VendorOptions->VendorOptions,
830 LocalPtr.VendorOptions->Header.Length
831 );
832 if (status) {
833 RxBufPtr->OpAdds.Status |= PXE_TYPE;
834 //
835 // check for all the MTFTP info options present - any missing is a nogo
836 //
837 if ((status & WfM11a_OPTS) == WfM11a_OPTS) {
838 RxBufPtr->OpAdds.Status |= WfM11a_TYPE;
839 }
840
841 if (status & DISCOVER_OPTS) {
842 RxBufPtr->OpAdds.Status |= DISCOVER_TYPE;
843 }
844
845 if (status & CREDENTIALS_OPT) {
846 RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE;
847 }
848 }
849 }
850 }
851 }
852 break;
853 }
854 }
855 }
856
857 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
858 VOID
859 Parse (
860 DHCP_RECEIVE_BUFFER *RxBufPtr,
861 INTN Len
862 )
863 {
864 UNION_PTR LocalPtr;
865
866 //
867 // initialize
868 //
869 SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0);
870
871 DecodeOptions (
872 RxBufPtr,
873 RxBufPtr->u.Dhcpv4.options + 4,
874 Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4)
875 );
876
877 LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1];
878
879 if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) {
880 DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname);
881 }
882
883 if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) {
884 DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file);
885 } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) {
886 RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER));
887
888 RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen ((CHAR8 *)RxBufPtr->u.Dhcpv4.file);
889 }
890
891 LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1];
892
893 if ((LocalPtr.OpPtr) &&
894 LocalPtr.PxeClassStr->Header.Length >= 9 &&
895 !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9)
896 ) {
897 RxBufPtr->OpAdds.Status |= PXE_TYPE;
898 }
899 }
900
901 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
902 STATIC
903 VOID
904 CopyParseRxBuf (
905 PXE_BASECODE_DEVICE *Private,
906 INTN RxBufIndex,
907 INTN PacketIndex
908 )
909 {
910 DHCP_RECEIVE_BUFFER *RxBufPtr;
911
912 RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex];
913
914 CopyMem (
915 &RxBufPtr->u.Dhcpv4,
916 &RxBuf[RxBufIndex].u.Dhcpv4,
917 sizeof (RxBuf[RxBufIndex].u.Dhcpv4)
918 );
919
920 Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer);
921 }
922
923 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
924 STATIC
925 VOID
926 CopyProxyRxBuf (
927 PXE_BASECODE_DEVICE *Private,
928 INTN RxBufIndex
929 )
930 {
931 Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
932 CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX);
933 }
934
935 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
936 STATIC
937 VOID
938 CopyParse (
939 PXE_BASECODE_DEVICE *Private,
940 EFI_PXE_BASE_CODE_PACKET *PacketPtr,
941 EFI_PXE_BASE_CODE_PACKET *NewPacketPtr,
942 INTN Index
943 )
944 {
945 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
946
947 DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index];
948
949 CopyMem (
950 (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4,
951 NewPacketPtr,
952 sizeof (*NewPacketPtr)
953 );
954
955 CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr));
956
957 Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer);
958 }
959
960 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
961 BOOLEAN
962 AckEdit (
963 DHCP_RECEIVE_BUFFER *DhcpRxBuf
964 )
965 {
966 UNION_PTR LocalPtr;
967
968 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
969
970 //
971 // check that an ACK
972 // if a DHCP type, must be DHCPOFFER and must have server id
973 //
974 return (BOOLEAN)
975 (
976 (LocalPtr.OpPtr) &&
977 (LocalPtr.MessageType->Type == DHCPACK) &&
978 DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]
979 );
980 }
981
982 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
983
984 //
985 // if a discover type packet, make sure all required fields are present
986 //
987 BOOLEAN
988 DHCPOfferAckEdit (
989 DHCP_RECEIVE_BUFFER *DhcpRxBuf
990 )
991 {
992 PXE_OP_SERVER_LIST *BootServerOpPtr;
993 UNION_PTR LocalPtr;
994
995 if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) {
996 return TRUE;
997 }
998
999 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
1000
1001 if (LocalPtr.OpPtr == NULL) {
1002 LocalPtr.OpPtr = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
1003 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
1004 }
1005 //
1006 // make sure all required fields are here
1007 // if mucticast enabled, need multicast address
1008 //
1009 if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) &&
1010 (!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))
1011 ) {
1012 return FALSE;
1013 //
1014 // missing required field
1015 //
1016 }
1017 //
1018 // if a list, it better be good
1019 //
1020 BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1];
1021
1022 if (BootServerOpPtr != NULL) {
1023 PXE_SERVER_LIST *BootServerListPtr;
1024 INTN ServerListLen;
1025 INTN ServerEntryLen;
1026
1027 BootServerListPtr = BootServerOpPtr->ServerList;
1028 ServerListLen = BootServerOpPtr->Header.Length;
1029
1030 do {
1031 EFI_IPv4_ADDRESS *IpListPtr;
1032 INTN IpCnt;
1033
1034 IpCnt = BootServerListPtr->u.Ipv4List.IpCount;
1035
1036 ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS);
1037
1038 if (ServerListLen < ServerEntryLen) {
1039 //
1040 // missing required field
1041 //
1042 return FALSE;
1043 }
1044
1045 IpListPtr = BootServerListPtr->u.Ipv4List.IpList;
1046
1047 while (IpCnt--) {
1048 if (IS_MULTICAST (IpListPtr)) {
1049 //
1050 // missing required field
1051 //
1052 return FALSE;
1053 } else {
1054 ++IpListPtr;
1055 }
1056 }
1057
1058 BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr;
1059 } while (ServerListLen -= ServerEntryLen);
1060 }
1061 //
1062 // else there must be a list if use list enabled or multicast and
1063 // broadcast disabled
1064 //
1065 else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) ||
1066 ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
1067 ) {
1068 //
1069 // missing required field
1070 //
1071 return FALSE;
1072 }
1073 //
1074 // if not USE_BOOTFILE or no bootfile given, must have menu stuff
1075 //
1076 if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) ||
1077 !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
1078 ) {
1079 INTN MenuLth;
1080
1081 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
1082
1083 if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) {
1084 //
1085 // missing required field
1086 //
1087 return FALSE;
1088 }
1089 //
1090 // make sure menu valid
1091 //
1092 MenuLth = LocalPtr.BootMenu->Header.Length;
1093 LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem;
1094
1095 do {
1096 INTN MenuItemLen;
1097
1098 MenuItemLen = LocalPtr.BootMenuItem->DataLen;
1099
1100 if (MenuItemLen == 0) {
1101 //
1102 // missing required field
1103 //
1104 return FALSE;
1105 }
1106
1107 MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data);
1108
1109 MenuLth -= MenuItemLen;
1110 LocalPtr.BytePtr += MenuItemLen;
1111 } while (MenuLth > 0);
1112
1113 if (MenuLth != 0) {
1114 //
1115 // missing required field
1116 //
1117 return FALSE;
1118 }
1119 }
1120
1121 if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
1122 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem;
1123 }
1124
1125 return TRUE;
1126 }
1127
1128 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1129 BOOLEAN
1130 DHCPAckEdit (
1131 DHCP_RECEIVE_BUFFER *RxBufPtr
1132 )
1133 {
1134 return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE);
1135 }
1136
1137 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1138
1139 //
1140 // get an offer/ack
1141 //
1142 EFI_STATUS
1143 GetOfferAck (
1144 PXE_BASECODE_DEVICE *Private,
1145 BOOLEAN (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf),
1146 UINT16 OpFlags, // for Udp read
1147 EFI_IP_ADDRESS *ServerIpPtr,
1148 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
1149 EFI_IP_ADDRESS *ClientIpPtr,
1150 EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr,
1151 DHCP_RECEIVE_BUFFER *DhcpRxBuf,
1152 EFI_EVENT TimeoutEvent
1153 )
1154 /*++
1155 Routine description:
1156 Wait for an OFFER/ACK packet.
1157
1158 Parameters:
1159 Private := Pointer to PxeBc interface
1160 ExtraEdit := Pointer to extra option checking function
1161 OpFlags := UdpRead() option flags
1162 ServerIpPtr :=
1163 ServerPortPtr :=
1164 ClientIpPtr :=
1165 ClientPortPtr :=
1166 DhcpRxBuf :=
1167 TimeoutEvent :=
1168
1169 Returns:
1170 --*/
1171 {
1172 EFI_IP_ADDRESS ServerIp;
1173 EFI_STATUS StatCode;
1174 INTN RxBufLen;
1175
1176 for (;;) {
1177 //
1178 // Wait until we get a UDP packet.
1179 //
1180 ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
1181 RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer;
1182
1183 if ((StatCode = UdpRead (
1184 Private,
1185 OpFlags,
1186 ClientIpPtr,
1187 ClientPortPtr,
1188 ServerIpPtr,
1189 ServerPortPtr,
1190 0,
1191 0,
1192 (UINTN *) &RxBufLen,
1193 &DhcpRxBuf->u.Dhcpv4,
1194 TimeoutEvent
1195 )) != EFI_SUCCESS) {
1196 if (StatCode == EFI_TIMEOUT) {
1197 StatCode = EFI_NO_RESPONSE;
1198 }
1199
1200 break;
1201 }
1202 //
1203 // got a packet - see if a good offer
1204 //
1205 if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) {
1206 continue;
1207 }
1208
1209 if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) {
1210 continue;
1211 }
1212
1213 if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) {
1214 continue;
1215 }
1216
1217 if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) {
1218 continue;
1219 }
1220
1221 if (CompareMem (
1222 DhcpRxBuf->u.Dhcpv4.chaddr,
1223 DHCPV4_TRANSMIT_BUFFER.chaddr,
1224 sizeof DhcpRxBuf->u.Dhcpv4.chaddr
1225 )) {
1226 //
1227 // no good
1228 //
1229 continue;
1230 }
1231
1232 Parse (DhcpRxBuf, RxBufLen);
1233
1234 if (!(*ExtraEdit) (DhcpRxBuf)) {
1235 continue;
1236 }
1237 //
1238 // Good DHCP packet.
1239 //
1240 StatCode = EFI_SUCCESS;
1241 break;
1242 }
1243
1244 return StatCode;
1245 }
1246
1247 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1248
1249 //
1250 // get DHCPOFFER's
1251 //
1252 EFI_STATUS
1253 GetOffers (
1254 PXE_BASECODE_DEVICE *Private
1255 )
1256 {
1257 EFI_IP_ADDRESS ClientIp;
1258 EFI_IP_ADDRESS ServerIp;
1259 EFI_STATUS StatCode;
1260 EFI_EVENT TimeoutEvent;
1261 INTN NumOffers;
1262 INTN Index;
1263
1264 //
1265 //
1266 //
1267 ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
1268 NumOffers = 0;
1269
1270 for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) {
1271 Private->ServerCount[Index] = 0;
1272 Private->GotProxy[Index] = 0;
1273 }
1274
1275 Private->GotBootp = 0;
1276 //
1277 // these we throw away
1278 //
1279 Private->GotProxy[DHCP_ONLY_IX] = 1;
1280 StatCode = gBS->CreateEvent (
1281 EFI_EVENT_TIMER,
1282 EFI_TPL_CALLBACK,
1283 NULL,
1284 NULL,
1285 &TimeoutEvent
1286 );
1287
1288 if (EFI_ERROR (StatCode)) {
1289 return StatCode;
1290 }
1291
1292 StatCode = gBS->SetTimer (
1293 TimeoutEvent,
1294 TimerRelative,
1295 Private->Timeout * 10000000 + 1000000
1296 );
1297
1298 if (EFI_ERROR (StatCode)) {
1299 gBS->CloseEvent (TimeoutEvent);
1300 return StatCode;
1301 }
1302 //
1303 // get offers
1304 //
1305 for (;;) {
1306 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1307 UNION_PTR LocalPtr;
1308
1309 DhcpRxBuf = &RxBuf[NumOffers];
1310
1311 if ((
1312 StatCode = GetOfferAck (
1313 Private,
1314 DHCPOfferAckEdit,
1315 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
1316 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP |
1317 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
1318 &ServerIp,
1319 &DhcpServerPort,
1320 &ClientIp,
1321 &DHCPClientPort,
1322 DhcpRxBuf,
1323 TimeoutEvent
1324 )
1325 ) != EFI_SUCCESS
1326 ) {
1327 break;
1328 }
1329
1330 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
1331
1332 //
1333 // check type of offer
1334 //
1335 if (LocalPtr.OpPtr == NULL) {
1336 //
1337 // bootp - we only need one and make sure has bootfile
1338 //
1339 if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1340 continue;
1341 }
1342
1343 Private->GotBootp = (UINT8) (NumOffers + 1);
1344 }
1345 //
1346 // if a DHCP type, must be DHCPOFFER and must have server id
1347 //
1348 else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) {
1349 continue;
1350 } else {
1351 INTN TypeIx;
1352
1353 //
1354 // get type - PXE10, WfM11a, or BINL
1355 //
1356 if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) {
1357 TypeIx = PXE10_IX;
1358 } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) {
1359 //
1360 // WfM - make sure it has a bootfile
1361 //
1362 if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1363 continue;
1364 }
1365
1366 TypeIx = WfM11a_IX;
1367 } else {
1368 TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX;
1369 }
1370 //
1371 // check DHCP or proxy
1372 //
1373 if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) {
1374 //
1375 // proxy - only need one of each type if not BINL
1376 // and must have at least PXE_TYPE
1377 //
1378 if (TypeIx == BINL_IX) {
1379 Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers;
1380 } else if (Private->GotProxy[TypeIx]) {
1381 continue;
1382 } else {
1383 Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1);
1384 }
1385 } else {
1386 Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers;
1387 }
1388 }
1389
1390 if (++NumOffers == MAX_OFFERS) {
1391 break;
1392 }
1393 }
1394
1395 gBS->CloseEvent (TimeoutEvent);
1396 Private->NumOffersReceived = NumOffers;
1397
1398 return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE;
1399 }
1400
1401 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1402
1403 //
1404 // send DHCPDECLINE
1405 //
1406 STATIC
1407 VOID
1408 DeclineOffer (
1409 PXE_BASECODE_DEVICE *Private
1410 )
1411 {
1412 EFI_PXE_BASE_CODE_MODE *PxebcMode;
1413 UINT16 SaveSecs;
1414
1415 PxebcMode = Private->EfiBc.Mode;
1416 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1417
1418 DHCPV4_TRANSMIT_BUFFER.secs = 0;
1419 DHCPV4_TRANSMIT_BUFFER.flags = 0;
1420 SetMem (
1421 DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr),
1422 sizeof (DHCPOpStart) - sizeof (struct opdeclinestr),
1423 OP_PAD
1424 );
1425 DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE;
1426 CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (struct requestopendstr));
1427 // DHCPDECLINEoptions.OpDeclineEnd = DHCP_REQ_OPTIONS;
1428
1429 {
1430 EFI_IP_ADDRESS TmpIp;
1431
1432 CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp);
1433
1434 DoUdpWrite (
1435 Private,
1436 &TmpIp,
1437 &DhcpServerPort,
1438 &PxebcMode->StationIp,
1439 &DHCPClientPort
1440 );
1441 }
1442
1443 InitDhcpv4TxBuf (Private);
1444 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1445 Private->GoodStationIp = FALSE;
1446 }
1447
1448 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1449
1450 //
1451 // send DHCPRELEASE
1452 //
1453 STATIC
1454 BOOLEAN
1455 Release (
1456 PXE_BASECODE_DEVICE *Private
1457 )
1458 {
1459 EFI_PXE_BASE_CODE_MODE *PxebcMode;
1460 UINT16 SaveSecs;
1461 DHCPV4_OP_SERVER_IP *Point;
1462
1463 PxebcMode = Private->EfiBc.Mode;
1464 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1465 DHCPV4_TRANSMIT_BUFFER.secs = 0;
1466
1467 SetMem (
1468 DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr),
1469 sizeof (DHCPOpStart) - sizeof (struct opreleasestr),
1470 OP_PAD
1471 );
1472
1473 DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE;
1474 Point = (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1];
1475 CopyMem (
1476 &DHCPRELEASEoptions.DhcServerIpPtr,
1477 &Point,
1478 sizeof DHCPRELEASEoptions.DhcServerIpPtr
1479 );
1480
1481 DHCPRELEASEoptions.End[0] = OP_END;
1482
1483 {
1484 EFI_IP_ADDRESS TmpIp;
1485
1486 CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp);
1487
1488 DoUdpWrite (
1489 Private,
1490 &TmpIp,
1491 &DhcpServerPort,
1492 &PxebcMode->StationIp,
1493 &DHCPClientPort
1494 );
1495 }
1496
1497 InitDhcpv4TxBuf (Private);
1498
1499 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1500 Private->GoodStationIp = FALSE;
1501 return FALSE;
1502 }
1503
1504 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1505 STATIC
1506 BOOLEAN
1507 GetBINLAck (
1508 PXE_BASECODE_DEVICE *Private,
1509 EFI_IP_ADDRESS *ServerIpPtr
1510 )
1511 {
1512 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1513 EFI_STATUS StatCode;
1514 EFI_EVENT TimeoutEvent;
1515
1516 //
1517 //
1518 //
1519 StatCode = gBS->CreateEvent (
1520 EFI_EVENT_TIMER,
1521 EFI_TPL_CALLBACK,
1522 NULL,
1523 NULL,
1524 &TimeoutEvent
1525 );
1526
1527 if (EFI_ERROR (StatCode)) {
1528 return FALSE;
1529 }
1530
1531 StatCode = gBS->SetTimer (
1532 TimeoutEvent,
1533 TimerRelative,
1534 Private->Timeout * 10000000 + 1000000
1535 );
1536
1537 if (EFI_ERROR (StatCode)) {
1538 gBS->CloseEvent (TimeoutEvent);
1539 return FALSE;
1540 }
1541 //
1542 //
1543 //
1544 DhcpRxBuf = &PXE_BINL_BUFFER;
1545
1546 for (;;) {
1547 EFI_PXE_BASE_CODE_UDP_PORT BINLSrvPort;
1548
1549 BINLSrvPort = 0;
1550
1551 if (GetOfferAck (
1552 Private,
1553 AckEdit,
1554 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
1555 ServerIpPtr,
1556 &BINLSrvPort,
1557 &Private->EfiBc.Mode->StationIp,
1558 &PSEUDO_DHCP_CLIENT_PORT,
1559 DhcpRxBuf,
1560 TimeoutEvent
1561 ) != EFI_SUCCESS) {
1562 break;
1563 }
1564 //
1565 // make sure from whom we wanted
1566 //
1567 if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem (
1568 &ServerIpPtr->v4,
1569 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1570 sizeof (ServerIpPtr->v4)
1571 )) {
1572 gBS->CloseEvent (TimeoutEvent);
1573 //
1574 // got an ACK from server
1575 //
1576 return TRUE;
1577 }
1578 }
1579
1580 gBS->CloseEvent (TimeoutEvent);
1581 return FALSE;
1582 }
1583
1584 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1585
1586 //
1587 // make sure we can get BINL
1588 // send DHCPREQUEST to PXE server
1589 //
1590 STATIC
1591 BOOLEAN
1592 TryBINL (
1593 PXE_BASECODE_DEVICE *Private,
1594 INTN OfferIx
1595 )
1596 {
1597 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1598 EFI_IP_ADDRESS ServerIp;
1599 UINT16 SaveSecs;
1600 INTN Index;
1601
1602 DhcpRxBuf = &RxBuf[OfferIx];
1603
1604 //
1605 // send DHCP request
1606 // if fail return false
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 // client IP address - filled in by client if it knows it
1616 //
1617 CopyMem (
1618 ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr),
1619 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
1620 sizeof (EFI_IPv4_ADDRESS)
1621 );
1622
1623 SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD);
1624 DHCPV4_TRANSMIT_BUFFER.flags = 0;
1625 DHCPV4_OPTIONS_BUFFER.End[0] = OP_END;
1626 AddRouters (Private, DhcpRxBuf);
1627 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1628
1629 for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) {
1630 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
1631
1632 //
1633 // unicast DHCPREQUEST to PXE server
1634 //
1635 if (DoUdpWrite (
1636 Private,
1637 &ServerIp,
1638 &PseudoDhcpServerPort,
1639 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
1640 &PSEUDO_DHCP_CLIENT_PORT
1641 ) != EFI_SUCCESS) {
1642 break;
1643 }
1644
1645 if (!GetBINLAck (Private, &ServerIp)) {
1646 continue;
1647 }
1648 //
1649 // early exit failures
1650 // make sure a good ACK
1651 //
1652 if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || (
1653 !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
1654 )
1655 ) {
1656 break;
1657 }
1658
1659 Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
1660 return TRUE;
1661 }
1662 //
1663 // failed - reset seconds field, etc.
1664 //
1665 Private->EfiBc.Mode->RouteTableEntries = 0;
1666 //
1667 // reset
1668 //
1669 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1670 return FALSE;
1671 }
1672
1673 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1674 STATIC
1675 BOOLEAN
1676 TryFinishBINL (
1677 PXE_BASECODE_DEVICE *Private,
1678 INTN OfferIx
1679 )
1680 {
1681 if (TryBINL (Private, OfferIx)) {
1682 return TRUE;
1683 }
1684
1685 return Release (Private);
1686 }
1687
1688 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1689 STATIC
1690 BOOLEAN
1691 TryFinishProxyBINL (
1692 PXE_BASECODE_DEVICE *Private
1693 )
1694 {
1695 INTN Index;
1696
1697 for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) {
1698 if (TryBINL (Private, Private->BinlProxies[Index])) {
1699 return TRUE;
1700 }
1701 }
1702
1703 return Release (Private);
1704 }
1705
1706 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1707
1708 //
1709 // try to finish DORA - send DHCP request, wait for ACK, check with ARP
1710 //
1711 STATIC
1712 BOOLEAN
1713 TryFinishDORA (
1714 PXE_BASECODE_DEVICE *Private,
1715 INTN OfferIx
1716 )
1717 {
1718 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1719 EFI_IP_ADDRESS ClientIp;
1720 EFI_IP_ADDRESS ServerIp;
1721 EFI_STATUS StatCode;
1722 UNION_PTR LocalPtr;
1723 EFI_EVENT TimeoutEvent;
1724
1725 //
1726 // send DHCP request
1727 // if fail return false
1728 //
1729 DhcpRxBuf = &DHCPV4_ACK_BUFFER;
1730 DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
1731 CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (RequestOpEndStr));
1732 // DHCP_REQ_OPTIONS = RequestOpEndStr;
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 EFI_EVENT_TIMER,
1764 EFI_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 ((EFI_D_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 UINT8 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 ((EFI_D_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 EFI_STATUS
2285 EFIAPI
2286 BcDhcp (
2287 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
2288 IN BOOLEAN SortOffers
2289 )
2290 /*++
2291 Routine description:
2292 standard DHCP Discover/Offer/Request/Ack session
2293 broadcast DHCPDISCOVER
2294 receive DHCPOFFER's
2295 broadcast DHCPREQUEST
2296 receive DHCPACK
2297 check (ARP) good IP
2298
2299 Parameters:
2300 This := Pointer to PxeBc interface
2301 SortOffers :=
2302
2303 Returns:
2304 --*/
2305 {
2306 EFI_PXE_BASE_CODE_IP_FILTER Filter;
2307 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2308 PXE_BASECODE_DEVICE *Private;
2309 EFI_STATUS StatCode;
2310
2311 //
2312 // Lock the instance data and make sure started
2313 //
2314 StatCode = EFI_SUCCESS;
2315
2316 if (This == NULL) {
2317 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
2318 return EFI_INVALID_PARAMETER;
2319 }
2320
2321 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2322
2323 if (Private == NULL) {
2324 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));
2325 return EFI_INVALID_PARAMETER;
2326 }
2327
2328 EfiAcquireLock (&Private->Lock);
2329
2330 if (This->Mode == NULL || !This->Mode->Started) {
2331 DEBUG ((EFI_D_ERROR, "BC was not started."));
2332 EfiReleaseLock (&Private->Lock);
2333 return EFI_NOT_STARTED;
2334 }
2335
2336 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
2337 Filter.IpCnt = 0;
2338 Filter.reserved = 0;
2339
2340 DEBUG ((EFI_D_INFO, "\nBcDhcp() Enter. "));
2341
2342 PxebcMode = Private->EfiBc.Mode;
2343
2344 if (!GetMem (Private)) {
2345 DEBUG ((EFI_D_ERROR, "\nBcDhcp() GetMem() failed.\n"));
2346 EfiReleaseLock (&Private->Lock);
2347 return EFI_OUT_OF_RESOURCES;
2348 }
2349
2350 PxebcMode->DhcpDiscoverValid = FALSE;
2351 PxebcMode->DhcpAckReceived = FALSE;
2352 PxebcMode->ProxyOfferReceived = FALSE;
2353
2354 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
2355
2356 //
2357 // Issue BC command
2358 //
2359 if (Private->TotalSeconds == 0) {
2360 //
2361 // put in seconds field of DHCP send packets
2362 //
2363 Private->TotalSeconds = 4;
2364 }
2365
2366 if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) {
2367 //
2368 // success - copy packets
2369 //
2370 PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE;
2371
2372 CopyMem (
2373 &PxebcMode->DhcpAck,
2374 (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET,
2375 sizeof (EFI_PXE_BASE_CODE_PACKET)
2376 );
2377
2378 if (PxebcMode->ProxyOfferReceived) {
2379 CopyMem (
2380 &PxebcMode->ProxyOffer,
2381 (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET,
2382 sizeof (EFI_PXE_BASE_CODE_PACKET)
2383 );
2384 }
2385 }
2386 //
2387 // set filter back to unicast
2388 //
2389 IpFilter (Private, &Filter);
2390
2391 FreeMem (Private);
2392
2393 //
2394 // Unlock the instance data
2395 //
2396 DEBUG ((EFI_D_WARN, "\nBcDhcp() Exit = %xh ", StatCode));
2397
2398 EfiReleaseLock (&Private->Lock);
2399 return StatCode;
2400 }
2401
2402 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2403 STATIC
2404 BOOLEAN
2405 VerifyCredentialOption (
2406 UINT8 *tx,
2407 UINT8 *rx
2408 )
2409 {
2410 UINTN n;
2411
2412 //
2413 // Fail verification if either pointer is NULL.
2414 //
2415 if (tx == NULL || rx == NULL) {
2416 return FALSE;
2417 }
2418 //
2419 // Fail verification if tx[0] is not a credential type option
2420 // or if the length is zero or not a multiple of four.
2421 //
2422 if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) {
2423 return FALSE;
2424 }
2425 //
2426 // Fail verification if rx[0] is not a credential type option
2427 // or if the length is not equal to four.
2428 //
2429 if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) {
2430 return FALSE;
2431 }
2432 //
2433 // Look through transmitted credential types for a copy
2434 // of the received credential type.
2435 //
2436 for (n = 0; n < tx[1]; n += 4) {
2437 if (!CompareMem (&tx[n + 2], &rx[2], 4)) {
2438 return TRUE;
2439 }
2440 }
2441
2442 return FALSE;
2443 }
2444
2445 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2446 EFI_STATUS
2447 DoDiscover (
2448 PXE_BASECODE_DEVICE *Private,
2449 UINT16 OpFlags,
2450 IN UINT16 Type,
2451 IN UINT16 *LayerPtr,
2452 IN BOOLEAN UseBis,
2453 EFI_IP_ADDRESS *DestPtr,
2454 PXE_SERVER_LISTS *ServerListPtr
2455 )
2456 /*++
2457 Routine description:
2458 This function tries to complete the PXE Bootserver and/or boot image
2459 discovery sequence. When this command completes successfully, the
2460 PXEdiscover and PXEreply fields in the BC instance data structure are
2461 updated. If the Info pointer is set to NULL, the discovery information
2462 in the DHCPack and ProxyOffer packets must be valid and will be used.
2463 If Info is not set to NULL, the discovery methods in the Info field
2464 must be set and will be used. When discovering any layer number other
2465 than zero (the credential flag does not count), only unicast discovery
2466 is used.
2467
2468 Parameters:
2469 Private := Pointer to PxeBc interface
2470 OpFlags :=
2471 Type :=
2472 LayerPtr :=
2473 UseBis :=
2474 DestPtr :=
2475 ServerListPtr :=
2476
2477 Returns:
2478 --*/
2479 {
2480 EFI_PXE_BASE_CODE_UDP_PORT ClientPort;
2481 EFI_PXE_BASE_CODE_UDP_PORT ServerPort;
2482 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2483 EFI_STATUS StatCode;
2484 EFI_EVENT TimeoutEvent;
2485 UINT8 OpLen;
2486
2487 PxebcMode = Private->EfiBc.Mode;
2488
2489 if (DestPtr->Addr[0] == 0) {
2490 DEBUG ((EFI_D_WARN, "\nDoDiscover() !DestPtr->Addr[0]"));
2491 return EFI_INVALID_PARAMETER;
2492 }
2493 //
2494 // seed random number with hardware address
2495 //
2496 SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
2497
2498 if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) {
2499 ClientPort = DHCPClientPort;
2500 ServerPort = DhcpServerPort;
2501 } else {
2502 ClientPort = PSEUDO_DHCP_CLIENT_PORT;
2503 ServerPort = PseudoDhcpServerPort;
2504 }
2505
2506 if (UseBis) {
2507 *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG;
2508 } else {
2509 *LayerPtr &= PXE_BOOT_LAYER_MASK;
2510 }
2511
2512 for (Private->Timeout = 1;
2513 Private->Timeout < 5;
2514 Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout
2515 ) {
2516 InitDhcpv4TxBuf (Private);
2517 //
2518 // initialize DHCP message structure
2519 //
2520 DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
2521 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
2522 CopyMem (
2523 &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2524 &PxebcMode->StationIp,
2525 sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr
2526 );
2527
2528 DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
2529 DISCOVERoptions.Header.OpCode = OP_VENDOR_SPECIFIC;
2530 DISCOVERoptions.BootItem.Header.OpCode = VEND_PXE_BOOT_ITEM;
2531 DISCOVERoptions.BootItem.Header.Length = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM);
2532 DISCOVERoptions.BootItem.Type = HTONS (Type);
2533 DISCOVERoptions.BootItem.Layer = HTONS (*LayerPtr);
2534
2535 if (UseBis) {
2536 EFI_BIS_PROTOCOL *BisPtr;
2537 BIS_APPLICATION_HANDLE BisAppHandle;
2538 EFI_BIS_DATA *BisDataSigInfo;
2539 EFI_BIS_SIGNATURE_INFO *BisSigInfo;
2540 UINTN Index;
2541 UINTN Index2;
2542
2543 BisPtr = PxebcBisStart (
2544 Private,
2545 &BisAppHandle,
2546 &BisDataSigInfo
2547 );
2548
2549 if (BisPtr == NULL) {
2550 //
2551 // %%TBD - In order to get here, BIS must have
2552 // been present when PXEBC.Start() was called.
2553 // BIS had to be shutdown/removed/damaged
2554 // before PXEBC.Discover() was called.
2555 // Do we need to document a specific error
2556 // for this case?
2557 //
2558 return EFI_OUT_OF_RESOURCES;
2559 }
2560 //
2561 // Compute number of credential types.
2562 //
2563 Index2 = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO);
2564
2565 DISCREDoptions.Header.OpCode = VEND_PXE_CREDENTIAL_TYPES;
2566
2567 DISCREDoptions.Header.Length = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL));
2568
2569 OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length);
2570
2571 BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data;
2572
2573 for (Index = 0; Index < Index2; ++Index) {
2574 UINT32 x;
2575
2576 CopyMem (&x, &BisSigInfo[Index], sizeof x);
2577 x = HTONL (x);
2578 CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x);
2579 }
2580
2581 PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
2582 } else {
2583 OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS);
2584 }
2585
2586 DISCOVERoptions.Header.Length = OpLen;
2587
2588 ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END;
2589 ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen] = OP_END;
2590
2591 StatCode = DoUdpWrite (
2592 Private,
2593 DestPtr,
2594 &ServerPort,
2595 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2596 &ClientPort
2597 );
2598
2599 if (StatCode != EFI_SUCCESS) {
2600 return StatCode;
2601 }
2602 //
2603 //
2604 //
2605 StatCode = gBS->CreateEvent (
2606 EFI_EVENT_TIMER,
2607 EFI_TPL_CALLBACK,
2608 NULL,
2609 NULL,
2610 &TimeoutEvent
2611 );
2612
2613 if (EFI_ERROR (StatCode)) {
2614 return StatCode;
2615 }
2616
2617 StatCode = gBS->SetTimer (
2618 TimeoutEvent,
2619 TimerRelative,
2620 Private->Timeout * 10000000 + 1000000
2621 );
2622
2623 if (EFI_ERROR (StatCode)) {
2624 gBS->CloseEvent (TimeoutEvent);
2625 return StatCode;
2626 }
2627 //
2628 // wait for ACK
2629 //
2630 for (;;) {
2631 DHCP_RECEIVE_BUFFER *RxBufPtr;
2632 UINT16 TmpType;
2633 UINT16 TmpLayer;
2634
2635 RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER;
2636 ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
2637
2638 if (GetOfferAck (
2639 Private,
2640 AckEdit,
2641 OpFlags,
2642 (EFI_IP_ADDRESS *) &Private->ServerIp,
2643 0,
2644 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2645 &ClientPort,
2646 RxBufPtr,
2647 TimeoutEvent
2648 ) != EFI_SUCCESS) {
2649 break;
2650 }
2651 //
2652 // check type of response - need PXEClient DHCPACK of proper type with bootfile
2653 //
2654 if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) ||
2655 (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) ||
2656 !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] ||
2657 !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] ||
2658 !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) {
2659
2660 continue;
2661 }
2662
2663 TmpType = TmpLayer = 0;
2664
2665 if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
2666 TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type);
2667
2668 if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) {
2669 TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8);
2670 } else {
2671 TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer);
2672 }
2673 }
2674
2675 if (TmpType != Type) {
2676 continue;
2677 }
2678
2679 if (UseBis) {
2680 if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) {
2681 continue;
2682 }
2683
2684 if (!VerifyCredentialOption (
2685 (UINT8 *) &DISCREDoptions.Header,
2686 (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]
2687 )) {
2688 continue;
2689 }
2690 }
2691
2692 *LayerPtr = TmpLayer;
2693
2694 if (UseBis) {
2695 CopyMem (
2696 &PxebcMode->PxeBisReply,
2697 &RxBufPtr->u.Dhcpv4,
2698 sizeof (EFI_PXE_BASE_CODE_PACKET)
2699 );
2700
2701 PxebcMode->PxeBisReplyReceived = TRUE;
2702
2703 StatCode = DoDiscover (
2704 Private,
2705 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2706 Type,
2707 LayerPtr,
2708 FALSE,
2709 &Private->ServerIp,
2710 0
2711 );
2712
2713 gBS->CloseEvent (TimeoutEvent);
2714 return StatCode;
2715 }
2716
2717 PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE;
2718
2719 CopyMem (
2720 &PxebcMode->PxeDiscover,
2721 &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
2722 sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER)
2723 );
2724
2725 CopyMem (
2726 &PxebcMode->PxeReply,
2727 &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4,
2728 sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4)
2729 );
2730
2731 AddRouters (Private, RxBufPtr);
2732
2733 gBS->CloseEvent (TimeoutEvent);
2734 return EFI_SUCCESS;
2735 }
2736
2737 gBS->CloseEvent (TimeoutEvent);
2738 }
2739 //
2740 // end for loop
2741 //
2742 return EFI_TIMEOUT;
2743 }
2744
2745 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2746 STATIC
2747 EFI_STATUS
2748 Discover (
2749 PXE_BASECODE_DEVICE *Private,
2750 IN UINT16 Type,
2751 IN UINT16 *LayerPtr,
2752 IN BOOLEAN UseBis,
2753 IN EFI_PXE_BASE_CODE_DISCOVER_INFO *DiscoverInfoPtr,
2754 PXE_SERVER_LISTS *McastServerListPtr,
2755 PXE_SERVER_LISTS *ServerListPtr
2756 )
2757 /*++
2758 Routine Description:
2759
2760 Parameters:
2761 Private := Pointer to PxeBc interface
2762 Type :=
2763 LayerPtr :=
2764 UseBis :=
2765 DiscoverInfoPtr :=
2766 McastServerListPtr :=
2767 ServerListPtr :=
2768
2769 Returns:
2770 --*/
2771 {
2772 EFI_IP_ADDRESS DestIp;
2773 EFI_STATUS StatCode;
2774
2775 DEBUG ((EFI_D_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr));
2776
2777 if (UseBis) {
2778 DEBUG ((EFI_D_INFO, "BIS "));
2779 }
2780 //
2781 // get dest IP addr - mcast, bcast, or unicast
2782 //
2783 if (DiscoverInfoPtr->UseMCast) {
2784 DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4;
2785
2786 DEBUG (
2787 (EFI_D_INFO,
2788 "\nDiscover() MCast %d.%d.%d.%d ",
2789 DestIp.v4.Addr[0],
2790 DestIp.v4.Addr[1],
2791 DestIp.v4.Addr[2],
2792 DestIp.v4.Addr[3])
2793 );
2794
2795 if ((StatCode = DoDiscover (
2796 Private,
2797 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2798 Type,
2799 LayerPtr,
2800 UseBis,
2801 &DestIp,
2802 McastServerListPtr
2803 )) != EFI_TIMEOUT) {
2804 DEBUG (
2805 (EFI_D_WARN,
2806 "\nDiscover() status == %r (%Xh)",
2807 StatCode,
2808 StatCode)
2809 );
2810
2811 return StatCode;
2812 }
2813 }
2814
2815 if (DiscoverInfoPtr->UseBCast) {
2816 DEBUG ((EFI_D_INFO, "\nDiscver() BCast "));
2817
2818 if ((StatCode = DoDiscover (
2819 Private,
2820 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2821 Type,
2822 LayerPtr,
2823 UseBis,
2824 &BroadcastIP,
2825 McastServerListPtr
2826 )) != EFI_TIMEOUT) {
2827
2828 DEBUG ((EFI_D_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode));
2829
2830 return StatCode;
2831 }
2832 }
2833
2834 if (DiscoverInfoPtr->UseUCast) {
2835 UINTN Index;
2836
2837 DEBUG (
2838 (EFI_D_INFO,
2839 "\nDiscover() UCast IP#=%d ",
2840 ServerListPtr->Ipv4List.IpCount)
2841 );
2842
2843 for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
2844 CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4);
2845
2846 DEBUG (
2847 (EFI_D_INFO,
2848 "\nDiscover() UCast %d.%d.%d.%d ",
2849 DestIp.v4.Addr[0],
2850 DestIp.v4.Addr[1],
2851 DestIp.v4.Addr[2],
2852 DestIp.v4.Addr[3])
2853 );
2854
2855 if ((StatCode = DoDiscover (
2856 Private,
2857 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2858 Type,
2859 LayerPtr,
2860 UseBis,
2861 &DestIp,
2862 0
2863 )) != EFI_TIMEOUT) {
2864 DEBUG (
2865 (EFI_D_WARN,
2866 "\nDiscover() status == %r (%Xh)",
2867 StatCode,
2868 StatCode)
2869 );
2870
2871 return StatCode;
2872 }
2873 }
2874 }
2875
2876 DEBUG ((EFI_D_WARN, "\nDiscover() TIMEOUT"));
2877
2878 return EFI_TIMEOUT;
2879 }
2880
2881 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2882
2883 /* BcDiscover()
2884 */
2885 EFI_STATUS
2886 EFIAPI
2887 BcDiscover (
2888 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
2889 IN UINT16 Type,
2890 IN UINT16 *LayerPtr,
2891 IN BOOLEAN UseBis,
2892 IN EFI_PXE_BASE_CODE_DISCOVER_INFO * DiscoverInfoPtr OPTIONAL
2893 )
2894 /*++
2895 Routine description:
2896
2897 Parameters:
2898 This :=
2899 Type :=
2900 LayerPtr :=
2901 UseBis :=
2902 DiscoverInfoPtr :=
2903
2904 Returns:
2905 --*/
2906 {
2907 EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
2908 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2909 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
2910 PXE_SERVER_LISTS DefaultSrvList;
2911 PXE_SERVER_LISTS *ServerListPtr;
2912 PXE_SERVER_LISTS *McastServerListPtr;
2913 EFI_STATUS Status;
2914 UNION_PTR LocalPtr;
2915 UINTN Index;
2916 UINTN Index2;
2917 BOOLEAN AcquiredSrvList;
2918 EFI_STATUS StatCode;
2919 PXE_BASECODE_DEVICE *Private;
2920
2921 //
2922 // Lock the instance data and make sure started
2923 //
2924 StatCode = EFI_SUCCESS;
2925
2926 if (This == NULL) {
2927 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
2928 return EFI_INVALID_PARAMETER;
2929 }
2930
2931 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2932
2933 if (Private == NULL) {
2934 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
2935 return EFI_INVALID_PARAMETER;
2936 }
2937
2938 EfiAcquireLock (&Private->Lock);
2939
2940 if (This->Mode == NULL || !This->Mode->Started) {
2941 DEBUG ((EFI_D_ERROR, "BC was not started."));
2942 EfiReleaseLock (&Private->Lock);
2943 return EFI_NOT_STARTED;
2944 }
2945
2946 ServerListPtr = NULL;
2947 McastServerListPtr = NULL;
2948 AcquiredSrvList = FALSE;
2949
2950 PxebcMode = Private->EfiBc.Mode;
2951
2952 if (!GetMem (Private)) {
2953 EfiReleaseLock (&Private->Lock);
2954 return EFI_OUT_OF_RESOURCES;
2955 }
2956
2957 if (UseBis) {
2958 if (!PxebcMode->BisSupported) {
2959 EfiReleaseLock (&Private->Lock);
2960 return EFI_INVALID_PARAMETER;
2961 }
2962 }
2963
2964 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
2965
2966 if (Private->TotalSeconds == 0) {
2967 //
2968 // put in seconds field of DHCP send packets
2969 //
2970 Private->TotalSeconds = 4;
2971 }
2972
2973 ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
2974
2975 //
2976 // if layer number not zero, use previous discover
2977 //
2978 if (*LayerPtr != 0) {
2979 DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0"));
2980
2981 if (DiscoverInfoPtr != NULL) {
2982 DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n"));
2983
2984 EfiReleaseLock (&Private->Lock);
2985 return EFI_INVALID_PARAMETER;
2986 }
2987
2988 if (!PxebcMode->PxeDiscoverValid) {
2989 DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n"));
2990
2991 EfiReleaseLock (&Private->Lock);
2992 return EFI_INVALID_PARAMETER;
2993 }
2994
2995 if (!PxebcMode->PxeReplyReceived) {
2996 DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n"));
2997
2998 EfiReleaseLock (&Private->Lock);
2999 return EFI_INVALID_PARAMETER;
3000 }
3001
3002 if (UseBis && !PxebcMode->PxeBisReplyReceived) {
3003 DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeBisReplyReceived == 0\n"));
3004
3005 EfiReleaseLock (&Private->Lock);
3006 return EFI_INVALID_PARAMETER;
3007 }
3008
3009 DefaultInfo.UseUCast = TRUE;
3010 DiscoverInfoPtr = &DefaultInfo;
3011
3012 DefaultSrvList.Ipv4List.IpCount = 1;
3013 CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4);
3014
3015 ServerListPtr = &DefaultSrvList;
3016 }
3017 //
3018 // layer is zero - see if info is supplied or if we need to use info from a cached offer
3019 //
3020 else if (!DiscoverInfoPtr) {
3021 //
3022 // not supplied - generate it
3023 // make sure that there is cached, appropriate information
3024 // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail
3025 //
3026 DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
3027
3028 if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) {
3029 DEBUG ((EFI_D_WARN, "\nBcDiscover() !ack && !proxy"));
3030 EfiReleaseLock (&Private->Lock);
3031 return EFI_INVALID_PARAMETER;
3032 }
3033
3034 DiscoverInfoPtr = &DefaultInfo;
3035
3036 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
3037
3038 //
3039 // if multicast enabled, need multicast address
3040 //
3041 if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) {
3042 DefaultInfo.UseMCast = TRUE;
3043
3044 CopyMem (
3045 ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp),
3046 &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip,
3047 sizeof (EFI_IPv4_ADDRESS)
3048 );
3049 }
3050
3051 DefaultInfo.UseBCast = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0);
3052
3053 DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0);
3054
3055 DefaultInfo.UseUCast = (BOOLEAN)
3056 (
3057 (DefaultInfo.MustUseList) ||
3058 ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
3059 );
3060
3061 if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList (
3062 Type,
3063 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1],
3064 &ServerListPtr
3065 )) {
3066 DEBUG ((EFI_D_WARN, "\nBcDiscover() type not in list"));
3067 EfiReleaseLock (&Private->Lock);
3068 return EFI_INVALID_PARAMETER;
3069 }
3070 }
3071 //
3072 // Info supplied - make SrvList if required
3073 // if we use ucast discovery or must use list, there better be one
3074 //
3075 else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) {
3076 //
3077 // there better be a list
3078 //
3079 if (DiscoverInfoPtr->IpCnt == 0) {
3080 DEBUG ((EFI_D_WARN, "\nBcDiscover() no bootserver list"));
3081 EfiReleaseLock (&Private->Lock);
3082 return EFI_INVALID_PARAMETER;
3083 }
3084 //
3085 // get its size
3086 //
3087 for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
3088 if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
3089 if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) {
3090 if (Index2 != 0) {
3091 DEBUG ((EFI_D_WARN, "\nBcDiscover() accept any?"));
3092 EfiReleaseLock (&Private->Lock);
3093 return EFI_INVALID_PARAMETER;
3094 } else {
3095 Index2 = 1;
3096 DefaultSrvList.Ipv4List.IpCount = 0;
3097 ServerListPtr = &DefaultSrvList;
3098 break;
3099 }
3100 } else {
3101 ++Index2;
3102 }
3103 }
3104 }
3105
3106 if (Index2 == 0) {
3107 DEBUG ((EFI_D_WARN, "\nBcDiscover() !Index2?"));
3108 EfiReleaseLock (&Private->Lock);
3109 return EFI_INVALID_PARAMETER;
3110 }
3111
3112 if (ServerListPtr == NULL) {
3113 Status = gBS->AllocatePool (
3114 EfiBootServicesData,
3115 sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS),
3116 (VOID **) &ServerListPtr
3117 );
3118
3119 if (EFI_ERROR (Status) || ServerListPtr == NULL) {
3120 ServerListPtr = NULL;
3121 EfiReleaseLock (&Private->Lock);
3122 return EFI_OUT_OF_RESOURCES;
3123 }
3124 //
3125 // build an array of IP addresses from the server list
3126 //
3127 AcquiredSrvList = TRUE;
3128 ServerListPtr->Ipv4List.IpCount = (UINT8) Index2;
3129
3130 for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
3131 if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
3132 CopyMem (
3133 &ServerListPtr->Ipv4List.IpList[Index2++],
3134 &DiscoverInfoPtr->SrvList[Index].IpAddr.v4,
3135 sizeof ServerListPtr->Ipv4List.IpList[0]
3136 );
3137 }
3138 }
3139 }
3140 }
3141
3142 if (DiscoverInfoPtr->MustUseList) {
3143 McastServerListPtr = ServerListPtr;
3144 }
3145
3146 if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) {
3147 DEBUG ((EFI_D_WARN, "\nBcDiscover() Nothing to use!\n"));
3148
3149 EfiReleaseLock (&Private->Lock);
3150 return EFI_INVALID_PARAMETER;
3151 }
3152
3153 PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE;
3154
3155 StatCode = Discover (
3156 Private,
3157 Type,
3158 LayerPtr,
3159 UseBis,
3160 DiscoverInfoPtr,
3161 McastServerListPtr,
3162 ServerListPtr
3163 );
3164
3165 if (AcquiredSrvList) {
3166 gBS->FreePool (ServerListPtr);
3167 }
3168
3169 FreeMem (Private);
3170
3171 //
3172 // Unlock the instance data
3173 //
3174 DEBUG (
3175 (EFI_D_INFO,
3176 "\nBcDiscover() status == %r (%Xh)\n",
3177 StatCode,
3178 StatCode)
3179 );
3180
3181 EfiReleaseLock (&Private->Lock);
3182 return StatCode;
3183 }
3184
3185 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3186 EFI_STATUS
3187 EFIAPI
3188 BcSetPackets (
3189 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
3190 BOOLEAN *NewDhcpDiscoverValid, OPTIONAL
3191 BOOLEAN *NewDhcpAckReceived, OPTIONAL
3192 BOOLEAN *NewProxyOfferReceived, OPTIONAL
3193 BOOLEAN *NewPxeDiscoverValid, OPTIONAL
3194 BOOLEAN *NewPxeReplyReceived, OPTIONAL
3195 BOOLEAN *NewPxeBisReplyReceived, OPTIONAL
3196 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
3197 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
3198 IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
3199 IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
3200 IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
3201 IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
3202 )
3203 /*++
3204 Routine description:
3205
3206 Parameters:
3207
3208 Returns:
3209 --*/
3210 {
3211 EFI_PXE_BASE_CODE_MODE *PxebcMode;
3212 EFI_STATUS Status;
3213 EFI_STATUS StatCode;
3214 PXE_BASECODE_DEVICE *Private;
3215
3216 //
3217 // Lock the instance data and make sure started
3218 //
3219 StatCode = EFI_SUCCESS;
3220
3221 if (This == NULL) {
3222 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
3223 return EFI_INVALID_PARAMETER;
3224 }
3225
3226 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
3227
3228 if (Private == NULL) {
3229 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
3230 return EFI_INVALID_PARAMETER;
3231 }
3232
3233 EfiAcquireLock (&Private->Lock);
3234
3235 if (This->Mode == NULL || !This->Mode->Started) {
3236 DEBUG ((EFI_D_ERROR, "BC was not started."));
3237 EfiReleaseLock (&Private->Lock);
3238 return EFI_NOT_STARTED;
3239 }
3240
3241 PxebcMode = Private->EfiBc.Mode;
3242
3243 if (Private->DhcpPacketBuffer == NULL) {
3244 Status = gBS->AllocatePool (
3245 EfiBootServicesData,
3246 sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
3247 &Private->DhcpPacketBuffer
3248 );
3249
3250 if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
3251 Private->DhcpPacketBuffer = NULL;
3252 EfiReleaseLock (&Private->Lock);
3253 return EFI_OUT_OF_RESOURCES;
3254 }
3255 }
3256 //
3257 // Issue BC command
3258 //
3259 //
3260 // reset
3261 //
3262 Private->FileSize = 0;
3263 if (NewDhcpDiscoverValid != NULL) {
3264 PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
3265 }
3266
3267 if (NewDhcpAckReceived != NULL) {
3268 PxebcMode->DhcpAckReceived = *NewDhcpAckReceived;
3269 }
3270
3271 if (NewProxyOfferReceived != NULL) {
3272 PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived;
3273 }
3274
3275 if (NewPxeDiscoverValid != NULL) {
3276 PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid;
3277 }
3278
3279 if (NewPxeReplyReceived != NULL) {
3280 PxebcMode->PxeReplyReceived = *NewPxeReplyReceived;
3281 }
3282
3283 if (NewPxeBisReplyReceived != NULL) {
3284 PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
3285 }
3286
3287 if (NewDhcpDiscover != NULL) {
3288 CopyMem (
3289 &PxebcMode->DhcpDiscover,
3290 NewDhcpDiscover,
3291 sizeof *NewDhcpDiscover
3292 );
3293 }
3294
3295 if (NewDhcpAck != NULL) {
3296 CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX);
3297 }
3298
3299 if (NewProxyOffer != NULL) {
3300 CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX);
3301 }
3302
3303 if (NewPxeDiscover != NULL) {
3304 CopyMem (
3305 &PxebcMode->PxeDiscover,
3306 NewPxeDiscover,
3307 sizeof *NewPxeDiscover
3308 );
3309 }
3310
3311 if (NewPxeReply != NULL) {
3312 CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX);
3313 }
3314
3315 if (NewPxeBisReply != NULL) {
3316 CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX);
3317 }
3318 //
3319 // Unlock the instance data
3320 //
3321 EfiReleaseLock (&Private->Lock);
3322 return EFI_SUCCESS;
3323 }
3324
3325 /* eof - pxe_bc_dhcp.c */