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