]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_dhcp.c
sync comments, fix function header, rename variable name to follow coding style.
[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 EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort = DHCP_SERVER_PORT;
26 EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort = DHCP_CLIENT_PORT;
27 EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort = PXE_DISCOVERY_PORT;
28 #define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort
29 EFI_IP_ADDRESS BroadcastIP = {{0xffffffff}};
30 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 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 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 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 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 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_TABLE_ENTRY_POINT *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_STRUCTURE *) (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 VOID
531 Ip4AddRouterList (
532 PXE_BASECODE_DEVICE *Private,
533 DHCPV4_OP_IP_LIST *IpListPtr
534 )
535 {
536 EFI_IP_ADDRESS TmpIp;
537 INTN Index;
538 INTN num;
539
540 if (IpListPtr == NULL) {
541 return ;
542 }
543
544 for (Index = 0, num = IpListPtr->Header.Length >> 2; Index < num; ++Index) {
545 CopyMem (&TmpIp, &IpListPtr->IpList[Index], 4);
546 Ip4AddRouter (Private, &TmpIp);
547 }
548 }
549
550 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
551
552 //
553 // send ARP for our IP - fail if someone has it
554 //
555 BOOLEAN
556 SetStationIP (
557 PXE_BASECODE_DEVICE *Private
558 )
559 {
560 EFI_MAC_ADDRESS DestMac;
561 EFI_STATUS EfiStatus;
562
563 ZeroMem (&DestMac, sizeof DestMac);
564
565 if (GetHwAddr(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac)
566 || DoArp(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) == EFI_SUCCESS) {
567 return FALSE; // somebody else has this IP
568 }
569
570 CopyMem (
571 (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->StationIp,
572 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
573 sizeof (EFI_IPv4_ADDRESS)
574 );
575
576 Private->GoodStationIp = TRUE;
577
578 if (!Private->UseIgmpv1Reporting) {
579 return TRUE;
580 }
581
582 if (Private->Igmpv1TimeoutEvent != NULL) {
583 return TRUE;
584 }
585
586 EfiStatus = gBS->CreateEvent (
587 EVT_TIMER,
588 TPL_CALLBACK,
589 NULL,
590 NULL,
591 &Private->Igmpv1TimeoutEvent
592 );
593
594 if (EFI_ERROR (EfiStatus)) {
595 Private->Igmpv1TimeoutEvent = NULL;
596 return TRUE;
597 }
598
599 EfiStatus = gBS->SetTimer (
600 Private->Igmpv1TimeoutEvent,
601 TimerRelative,
602 (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
603 ); /* 400 seconds */
604
605 if (EFI_ERROR (EfiStatus)) {
606 gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
607 Private->Igmpv1TimeoutEvent = NULL;
608 }
609
610 return TRUE;
611 }
612
613 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
614 VOID
615 AddRouters (
616 PXE_BASECODE_DEVICE *Private,
617 DHCP_RECEIVE_BUFFER *RxBufPtr
618 )
619 {
620 Ip4AddRouterList (
621 Private,
622 (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1]
623 );
624 }
625
626 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
627 EFI_STATUS
628 DoUdpWrite (
629 PXE_BASECODE_DEVICE *Private,
630 EFI_IP_ADDRESS *ServerIpPtr,
631 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
632 EFI_IP_ADDRESS *ClientIpPtr,
633 EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr
634 )
635 {
636 UINTN Len;
637
638 Len = sizeof DHCPV4_TRANSMIT_BUFFER;
639
640 return UdpWrite (
641 Private,
642 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
643 ServerIpPtr,
644 ServerPortPtr,
645 0,
646 ClientIpPtr,
647 ClientPortPtr,
648 0,
649 0,
650 &Len,
651 Private->TransmitBuffer
652 );
653 }
654
655 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
656
657 //
658 // initialize the DHCP structure
659 //
660 typedef struct {
661 UINT8 x[4];
662 } C4Str;
663
664 VOID
665 InitDhcpv4TxBuf (
666 PXE_BASECODE_DEVICE *Private
667 )
668 {
669 UINTN HwAddrLen;
670 UINT8 *String;
671 CHAR8 *SystemSerialNumber;
672 EFI_PXE_BASE_CODE_MODE *PxebcMode;
673
674 PxebcMode = Private->EfiBc.Mode;
675
676 ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT));
677 DHCPV4_TRANSMIT_BUFFER.op = BOOTP_REQUEST;
678 DHCPV4_TRANSMIT_BUFFER.htype = Private->SimpleNetwork->Mode->IfType;
679 DHCPV4_TRANSMIT_BUFFER.flags = HTONS (DHCP_BROADCAST_FLAG);
680 CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart));
681
682 //
683 // default to hardware address
684 //
685 HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize;
686
687 if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) {
688 HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr;
689 }
690
691 String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress;
692
693 if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
694 (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid,
695 &SystemSerialNumber
696 ) == EFI_SUCCESS) {
697 if (PxebcMode->SendGUID) {
698 HwAddrLen = sizeof (EFI_GUID);
699 String = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid;
700 }
701 } else {
702 //
703 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
704 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
705 // GUID not yet set - send all 0's to show not programable
706 //
707 ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID));
708 }
709
710 DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen;
711 CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen);
712
713 CvtNum (
714 SYS_ARCH,
715 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType,
716 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType
717 );
718
719 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type = Private->NiiPtr->Type;
720 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion = Private->NiiPtr->MajorVer;
721 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion = Private->NiiPtr->MinorVer;
722
723 *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId;
724
725 CvtNum (
726 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion,
727 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor,
728 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor
729 );
730
731 CvtNum (
732 DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion,
733 (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor,
734 sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor
735 );
736 }
737
738 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
739 UINT32
740 DecodePxeOptions (
741 DHCP_RECEIVE_BUFFER *RxBufPtr,
742 UINT8 *ptr,
743 INTN Len
744 )
745 {
746 UINT8 Op;
747 UINT8 *EndPtr;
748 INTN Index;
749 UNION_PTR LocalPtr;
750 UINT32 status;
751
752 status = 0;
753
754 for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
755 Op = ptr[0];
756 Len = ptr[1];
757
758 switch (Op) {
759 case OP_PAD:
760 Len = -1;
761 break;
762
763 case OP_END:
764 return status;
765
766 default:
767 LocalPtr.BytePtr = ptr;
768 if (Op <= MAX_OUR_PXE_OPT) {
769 Index = ourPXEopts[Op - 1];
770 if (Index) {
771 RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr;
772 status |= 1 << Index;
773 if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) {
774 RxBufPtr->OpAdds.Status |= USE_THREE_BYTE;
775 }
776 }
777 }
778 break;
779 }
780 }
781
782 return status;
783 }
784
785 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
786 VOID
787 DecodeOptions (
788 DHCP_RECEIVE_BUFFER *RxBufPtr,
789 UINT8 *ptr,
790 INTN Len
791 )
792 {
793 UINT8 Op;
794 UINT8 *EndPtr;
795 INTN Index;
796 UNION_PTR LocalPtr;
797
798 for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
799 Op = ptr[0];
800 Len = ptr[1];
801
802 switch (Op) {
803 case OP_PAD:
804 Len = -1;
805 break;
806
807 case OP_END:
808 return ;
809
810 default:
811 LocalPtr.BytePtr = ptr;
812 if (Op <= MAX_OUR_OPT) {
813 Index = OurDhcpOptions[Op - 1];
814 if (Index) {
815 RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr;
816 if (Index == OP_VENDOR_SPECIFIC_IX) {
817 UINT32 status;
818 status = DecodePxeOptions (
819 RxBufPtr,
820 (UINT8 *) LocalPtr.VendorOptions->VendorOptions,
821 LocalPtr.VendorOptions->Header.Length
822 );
823 if (status) {
824 RxBufPtr->OpAdds.Status |= PXE_TYPE;
825 //
826 // check for all the MTFTP info options present - any missing is a nogo
827 //
828 if ((status & WfM11a_OPTS) == WfM11a_OPTS) {
829 RxBufPtr->OpAdds.Status |= WfM11a_TYPE;
830 }
831
832 if (status & DISCOVER_OPTS) {
833 RxBufPtr->OpAdds.Status |= DISCOVER_TYPE;
834 }
835
836 if (status & CREDENTIALS_OPT) {
837 RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE;
838 }
839 }
840 }
841 }
842 }
843 break;
844 }
845 }
846 }
847
848 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
849 VOID
850 Parse (
851 DHCP_RECEIVE_BUFFER *RxBufPtr,
852 INTN Len
853 )
854 {
855 UNION_PTR LocalPtr;
856
857 //
858 // initialize
859 //
860 SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0);
861
862 DecodeOptions (
863 RxBufPtr,
864 RxBufPtr->u.Dhcpv4.options + 4,
865 Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4)
866 );
867
868 LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1];
869
870 if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) {
871 DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname);
872 }
873
874 if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) {
875 DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file);
876 } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) {
877 RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER));
878
879 RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen ((CHAR8 *) RxBufPtr->u.Dhcpv4.file);
880 }
881
882 LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1];
883
884 if ((LocalPtr.OpPtr) &&
885 LocalPtr.PxeClassStr->Header.Length >= 9 &&
886 !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9)
887 ) {
888 RxBufPtr->OpAdds.Status |= PXE_TYPE;
889 }
890 }
891
892 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
893 VOID
894 CopyParseRxBuf (
895 PXE_BASECODE_DEVICE *Private,
896 INTN RxBufIndex,
897 INTN PacketIndex
898 )
899 {
900 DHCP_RECEIVE_BUFFER *RxBufPtr;
901
902 RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex];
903
904 CopyMem (
905 &RxBufPtr->u.Dhcpv4,
906 &RxBuf[RxBufIndex].u.Dhcpv4,
907 sizeof (RxBuf[RxBufIndex].u.Dhcpv4)
908 );
909
910 Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer);
911 }
912
913 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
914 VOID
915 CopyProxyRxBuf (
916 PXE_BASECODE_DEVICE *Private,
917 INTN RxBufIndex
918 )
919 {
920 Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
921 CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX);
922 }
923
924 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
925 VOID
926 CopyParse (
927 PXE_BASECODE_DEVICE *Private,
928 EFI_PXE_BASE_CODE_PACKET *PacketPtr,
929 EFI_PXE_BASE_CODE_PACKET *NewPacketPtr,
930 INTN Index
931 )
932 {
933 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
934
935 DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index];
936
937 CopyMem (
938 (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4,
939 NewPacketPtr,
940 sizeof (*NewPacketPtr)
941 );
942
943 CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr));
944
945 Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer);
946 }
947
948 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
949 BOOLEAN
950 AckEdit (
951 DHCP_RECEIVE_BUFFER *DhcpRxBuf
952 )
953 {
954 UNION_PTR LocalPtr;
955
956 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
957
958 //
959 // check that an ACK
960 // if a DHCP type, must be DHCPOFFER and must have server id
961 //
962 return (BOOLEAN)
963 (
964 (LocalPtr.OpPtr) &&
965 (LocalPtr.MessageType->Type == DHCPACK) &&
966 DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]
967 );
968 }
969
970 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
971
972 //
973 // if a discover type packet, make sure all required fields are present
974 //
975 BOOLEAN
976 DHCPOfferAckEdit (
977 DHCP_RECEIVE_BUFFER *DhcpRxBuf
978 )
979 {
980 PXE_OP_SERVER_LIST *BootServerOpPtr;
981 UNION_PTR LocalPtr;
982
983 if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) {
984 return TRUE;
985 }
986
987 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
988
989 if (LocalPtr.OpPtr == NULL) {
990 LocalPtr.OpPtr = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
991 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
992 }
993 //
994 // make sure all required fields are here
995 // if mucticast enabled, need multicast address
996 //
997 if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) &&
998 (!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))
999 ) {
1000 return FALSE;
1001 //
1002 // missing required field
1003 //
1004 }
1005 //
1006 // if a list, it better be good
1007 //
1008 BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1];
1009
1010 if (BootServerOpPtr != NULL) {
1011 PXE_SERVER_LIST *BootServerListPtr;
1012 INTN ServerListLen;
1013 INTN ServerEntryLen;
1014
1015 BootServerListPtr = BootServerOpPtr->ServerList;
1016 ServerListLen = BootServerOpPtr->Header.Length;
1017
1018 do {
1019 EFI_IPv4_ADDRESS *IpListPtr;
1020 INTN IpCnt;
1021
1022 IpCnt = BootServerListPtr->u.Ipv4List.IpCount;
1023
1024 ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS);
1025
1026 if (ServerListLen < ServerEntryLen) {
1027 //
1028 // missing required field
1029 //
1030 return FALSE;
1031 }
1032
1033 IpListPtr = BootServerListPtr->u.Ipv4List.IpList;
1034
1035 while (IpCnt--) {
1036 if (IS_MULTICAST (IpListPtr)) {
1037 //
1038 // missing required field
1039 //
1040 return FALSE;
1041 } else {
1042 ++IpListPtr;
1043 }
1044 }
1045
1046 BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr;
1047 } while (ServerListLen -= ServerEntryLen);
1048 }
1049 //
1050 // else there must be a list if use list enabled or multicast and
1051 // broadcast disabled
1052 //
1053 else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) ||
1054 ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
1055 ) {
1056 //
1057 // missing required field
1058 //
1059 return FALSE;
1060 }
1061 //
1062 // if not USE_BOOTFILE or no bootfile given, must have menu stuff
1063 //
1064 if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) ||
1065 !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
1066 ) {
1067 INTN MenuLth;
1068
1069 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
1070
1071 if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) {
1072 //
1073 // missing required field
1074 //
1075 return FALSE;
1076 }
1077 //
1078 // make sure menu valid
1079 //
1080 MenuLth = LocalPtr.BootMenu->Header.Length;
1081 LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem;
1082
1083 do {
1084 INTN MenuItemLen;
1085
1086 MenuItemLen = LocalPtr.BootMenuItem->DataLen;
1087
1088 if (MenuItemLen == 0) {
1089 //
1090 // missing required field
1091 //
1092 return FALSE;
1093 }
1094
1095 MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data);
1096
1097 MenuLth -= MenuItemLen;
1098 LocalPtr.BytePtr += MenuItemLen;
1099 } while (MenuLth > 0);
1100
1101 if (MenuLth != 0) {
1102 //
1103 // missing required field
1104 //
1105 return FALSE;
1106 }
1107 }
1108
1109 if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
1110 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem;
1111 }
1112
1113 return TRUE;
1114 }
1115
1116 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1117 BOOLEAN
1118 DHCPAckEdit (
1119 DHCP_RECEIVE_BUFFER *RxBufPtr
1120 )
1121 {
1122 return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE);
1123 }
1124
1125 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1126
1127 //
1128 // get an offer/ack
1129 //
1130 EFI_STATUS
1131 GetOfferAck (
1132 PXE_BASECODE_DEVICE *Private,
1133 BOOLEAN (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf),
1134 UINT16 OpFlags, // for Udp read
1135 EFI_IP_ADDRESS *ServerIpPtr,
1136 EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
1137 EFI_IP_ADDRESS *ClientIpPtr,
1138 EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr,
1139 DHCP_RECEIVE_BUFFER *DhcpRxBuf,
1140 EFI_EVENT TimeoutEvent
1141 )
1142 /*++
1143 Routine description:
1144 Wait for an OFFER/ACK packet.
1145
1146 Parameters:
1147 Private := Pointer to PxeBc interface
1148 ExtraEdit := Pointer to extra option checking function
1149 OpFlags := UdpRead() option flags
1150 ServerIpPtr :=
1151 ServerPortPtr :=
1152 ClientIpPtr :=
1153 ClientPortPtr :=
1154 DhcpRxBuf :=
1155 TimeoutEvent :=
1156
1157 Returns:
1158 --*/
1159 {
1160 EFI_IP_ADDRESS ServerIp;
1161 EFI_STATUS StatCode;
1162 INTN RxBufLen;
1163
1164 for (;;) {
1165 //
1166 // Wait until we get a UDP packet.
1167 //
1168 ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
1169 RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer;
1170
1171 if ((StatCode = UdpRead (
1172 Private,
1173 OpFlags,
1174 ClientIpPtr,
1175 ClientPortPtr,
1176 ServerIpPtr,
1177 ServerPortPtr,
1178 0,
1179 0,
1180 (UINTN *) &RxBufLen,
1181 &DhcpRxBuf->u.Dhcpv4,
1182 TimeoutEvent
1183 )) != EFI_SUCCESS) {
1184 if (StatCode == EFI_TIMEOUT) {
1185 StatCode = EFI_NO_RESPONSE;
1186 }
1187
1188 break;
1189 }
1190 //
1191 // got a packet - see if a good offer
1192 //
1193 if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) {
1194 continue;
1195 }
1196
1197 if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) {
1198 continue;
1199 }
1200
1201 if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) {
1202 continue;
1203 }
1204
1205 if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) {
1206 continue;
1207 }
1208
1209 if (CompareMem (
1210 DhcpRxBuf->u.Dhcpv4.chaddr,
1211 DHCPV4_TRANSMIT_BUFFER.chaddr,
1212 sizeof DhcpRxBuf->u.Dhcpv4.chaddr
1213 )) {
1214 //
1215 // no good
1216 //
1217 continue;
1218 }
1219
1220 Parse (DhcpRxBuf, RxBufLen);
1221
1222 if (!(*ExtraEdit) (DhcpRxBuf)) {
1223 continue;
1224 }
1225 //
1226 // Good DHCP packet.
1227 //
1228 StatCode = EFI_SUCCESS;
1229 break;
1230 }
1231
1232 return StatCode;
1233 }
1234
1235 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1236
1237 //
1238 // get DHCPOFFER's
1239 //
1240 EFI_STATUS
1241 GetOffers (
1242 PXE_BASECODE_DEVICE *Private
1243 )
1244 {
1245 EFI_IP_ADDRESS ClientIp;
1246 EFI_IP_ADDRESS ServerIp;
1247 EFI_STATUS StatCode;
1248 EFI_EVENT TimeoutEvent;
1249 INTN NumOffers;
1250 INTN Index;
1251
1252 //
1253 //
1254 //
1255 ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
1256 NumOffers = 0;
1257
1258 for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) {
1259 Private->ServerCount[Index] = 0;
1260 Private->GotProxy[Index] = 0;
1261 }
1262
1263 Private->GotBootp = 0;
1264 //
1265 // these we throw away
1266 //
1267 Private->GotProxy[DHCP_ONLY_IX] = 1;
1268 StatCode = gBS->CreateEvent (
1269 EVT_TIMER,
1270 TPL_CALLBACK,
1271 NULL,
1272 NULL,
1273 &TimeoutEvent
1274 );
1275
1276 if (EFI_ERROR (StatCode)) {
1277 return StatCode;
1278 }
1279
1280 StatCode = gBS->SetTimer (
1281 TimeoutEvent,
1282 TimerRelative,
1283 Private->Timeout * 10000000 + 1000000
1284 );
1285
1286 if (EFI_ERROR (StatCode)) {
1287 gBS->CloseEvent (TimeoutEvent);
1288 return StatCode;
1289 }
1290 //
1291 // get offers
1292 //
1293 for (;;) {
1294 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1295 UNION_PTR LocalPtr;
1296
1297 DhcpRxBuf = &RxBuf[NumOffers];
1298
1299 if ((
1300 StatCode = GetOfferAck (
1301 Private,
1302 DHCPOfferAckEdit,
1303 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
1304 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP |
1305 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
1306 &ServerIp,
1307 &DhcpServerPort,
1308 &ClientIp,
1309 &DHCPClientPort,
1310 DhcpRxBuf,
1311 TimeoutEvent
1312 )
1313 ) != EFI_SUCCESS
1314 ) {
1315 break;
1316 }
1317
1318 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
1319
1320 //
1321 // check type of offer
1322 //
1323 if (LocalPtr.OpPtr == NULL) {
1324 //
1325 // bootp - we only need one and make sure has bootfile
1326 //
1327 if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1328 continue;
1329 }
1330
1331 Private->GotBootp = (UINT8) (NumOffers + 1);
1332 }
1333 //
1334 // if a DHCP type, must be DHCPOFFER and must have server id
1335 //
1336 else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) {
1337 continue;
1338 } else {
1339 INTN TypeIx;
1340
1341 //
1342 // get type - PXE10, WfM11a, or BINL
1343 //
1344 if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) {
1345 TypeIx = PXE10_IX;
1346 } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) {
1347 //
1348 // WfM - make sure it has a bootfile
1349 //
1350 if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1351 continue;
1352 }
1353
1354 TypeIx = WfM11a_IX;
1355 } else {
1356 TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX;
1357 }
1358 //
1359 // check DHCP or proxy
1360 //
1361 if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) {
1362 //
1363 // proxy - only need one of each type if not BINL
1364 // and must have at least PXE_TYPE
1365 //
1366 if (TypeIx == BINL_IX) {
1367 Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers;
1368 } else if (Private->GotProxy[TypeIx]) {
1369 continue;
1370 } else {
1371 Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1);
1372 }
1373 } else {
1374 Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers;
1375 }
1376 }
1377
1378 if (++NumOffers == MAX_OFFERS) {
1379 break;
1380 }
1381 }
1382
1383 gBS->CloseEvent (TimeoutEvent);
1384 Private->NumOffersReceived = NumOffers;
1385
1386 return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE;
1387 }
1388
1389 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1390
1391 //
1392 // send DHCPDECLINE
1393 //
1394 VOID
1395 DeclineOffer (
1396 PXE_BASECODE_DEVICE *Private
1397 )
1398 {
1399 EFI_PXE_BASE_CODE_MODE *PxebcMode;
1400 UINT16 SaveSecs;
1401
1402 PxebcMode = Private->EfiBc.Mode;
1403 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1404
1405 DHCPV4_TRANSMIT_BUFFER.secs = 0;
1406 DHCPV4_TRANSMIT_BUFFER.flags = 0;
1407 SetMem (
1408 DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr),
1409 sizeof (DHCPOpStart) - sizeof (struct opdeclinestr),
1410 OP_PAD
1411 );
1412 DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE;
1413 CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (DHCPDECLINEoptions.OpDeclineEnd));
1414
1415 {
1416 EFI_IP_ADDRESS TmpIp;
1417
1418 CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp);
1419
1420 DoUdpWrite (
1421 Private,
1422 &TmpIp,
1423 &DhcpServerPort,
1424 &PxebcMode->StationIp,
1425 &DHCPClientPort
1426 );
1427 }
1428
1429 InitDhcpv4TxBuf (Private);
1430 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1431 Private->GoodStationIp = FALSE;
1432 }
1433
1434 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1435
1436 //
1437 // send DHCPRELEASE
1438 //
1439 BOOLEAN
1440 Release (
1441 PXE_BASECODE_DEVICE *Private
1442 )
1443 {
1444 EFI_PXE_BASE_CODE_MODE *PxebcMode;
1445 UINT16 SaveSecs;
1446
1447 PxebcMode = Private->EfiBc.Mode;
1448 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1449 DHCPV4_TRANSMIT_BUFFER.secs = 0;
1450
1451 SetMem (
1452 DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr),
1453 sizeof (DHCPOpStart) - sizeof (struct opreleasestr),
1454 OP_PAD
1455 );
1456
1457 DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE;
1458
1459 CopyMem (
1460 &DHCPRELEASEoptions.DhcServerIpPtr,
1461 (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1],
1462 sizeof DHCPRELEASEoptions.DhcServerIpPtr
1463 );
1464
1465 DHCPRELEASEoptions.End[0] = OP_END;
1466
1467 {
1468 EFI_IP_ADDRESS TmpIp;
1469
1470 CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp);
1471
1472 DoUdpWrite (
1473 Private,
1474 &TmpIp,
1475 &DhcpServerPort,
1476 &PxebcMode->StationIp,
1477 &DHCPClientPort
1478 );
1479 }
1480
1481 InitDhcpv4TxBuf (Private);
1482
1483 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1484 Private->GoodStationIp = FALSE;
1485 return FALSE;
1486 }
1487
1488 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1489 BOOLEAN
1490 GetBINLAck (
1491 PXE_BASECODE_DEVICE *Private,
1492 EFI_IP_ADDRESS *ServerIpPtr
1493 )
1494 {
1495 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1496 EFI_STATUS StatCode;
1497 EFI_EVENT TimeoutEvent;
1498
1499 //
1500 //
1501 //
1502 StatCode = gBS->CreateEvent (
1503 EVT_TIMER,
1504 TPL_CALLBACK,
1505 NULL,
1506 NULL,
1507 &TimeoutEvent
1508 );
1509
1510 if (EFI_ERROR (StatCode)) {
1511 return FALSE;
1512 }
1513
1514 StatCode = gBS->SetTimer (
1515 TimeoutEvent,
1516 TimerRelative,
1517 Private->Timeout * 10000000 + 1000000
1518 );
1519
1520 if (EFI_ERROR (StatCode)) {
1521 gBS->CloseEvent (TimeoutEvent);
1522 return FALSE;
1523 }
1524 //
1525 //
1526 //
1527 DhcpRxBuf = &PXE_BINL_BUFFER;
1528
1529 for (;;) {
1530 EFI_PXE_BASE_CODE_UDP_PORT BINLSrvPort;
1531
1532 BINLSrvPort = 0;
1533
1534 if (GetOfferAck (
1535 Private,
1536 AckEdit,
1537 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
1538 ServerIpPtr,
1539 &BINLSrvPort,
1540 &Private->EfiBc.Mode->StationIp,
1541 &PSEUDO_DHCP_CLIENT_PORT,
1542 DhcpRxBuf,
1543 TimeoutEvent
1544 ) != EFI_SUCCESS) {
1545 break;
1546 }
1547 //
1548 // make sure from whom we wanted
1549 //
1550 if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem (
1551 &ServerIpPtr->v4,
1552 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1553 sizeof (ServerIpPtr->v4)
1554 )) {
1555 gBS->CloseEvent (TimeoutEvent);
1556 //
1557 // got an ACK from server
1558 //
1559 return TRUE;
1560 }
1561 }
1562
1563 gBS->CloseEvent (TimeoutEvent);
1564 return FALSE;
1565 }
1566
1567 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1568
1569 //
1570 // make sure we can get BINL
1571 // send DHCPREQUEST to PXE server
1572 //
1573 BOOLEAN
1574 TryBINL (
1575 PXE_BASECODE_DEVICE *Private,
1576 INTN OfferIx
1577 )
1578 {
1579 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1580 EFI_IP_ADDRESS ServerIp;
1581 UINT16 SaveSecs;
1582 INTN Index;
1583
1584 DhcpRxBuf = &RxBuf[OfferIx];
1585
1586 //
1587 // use next server address first.
1588 //
1589 ServerIp.Addr[0] = DhcpRxBuf->u.Dhcpv4.siaddr;
1590 if (ServerIp.Addr[0] == 0) {
1591 //
1592 // next server address is NULL, use option 54.
1593 //
1594 CopyMem (
1595 ((EFI_IPv4_ADDRESS *) &ServerIp),
1596 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1597 sizeof (EFI_IPv4_ADDRESS)
1598 );
1599 }
1600
1601 //
1602 // client IP address - filled in by client if it knows it
1603 //
1604 CopyMem (
1605 ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr),
1606 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
1607 sizeof (EFI_IPv4_ADDRESS)
1608 );
1609
1610 SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD);
1611 DHCPV4_TRANSMIT_BUFFER.flags = 0;
1612 DHCPV4_OPTIONS_BUFFER.End[0] = OP_END;
1613 AddRouters (Private, DhcpRxBuf);
1614 SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
1615
1616 for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) {
1617 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
1618
1619 //
1620 // unicast DHCPREQUEST to PXE server
1621 //
1622 if (DoUdpWrite (
1623 Private,
1624 &ServerIp,
1625 &PseudoDhcpServerPort,
1626 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
1627 &PSEUDO_DHCP_CLIENT_PORT
1628 ) != EFI_SUCCESS) {
1629 break;
1630 }
1631
1632 if (!GetBINLAck (Private, &ServerIp)) {
1633 continue;
1634 }
1635 //
1636 // early exit failures
1637 // make sure a good ACK
1638 //
1639 if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || (
1640 !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
1641 )
1642 ) {
1643 break;
1644 }
1645
1646 Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
1647 return TRUE;
1648 }
1649 //
1650 // failed - reset seconds field, etc.
1651 //
1652 Private->EfiBc.Mode->RouteTableEntries = 0;
1653 //
1654 // reset
1655 //
1656 DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
1657 return FALSE;
1658 }
1659
1660 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1661 BOOLEAN
1662 TryFinishBINL (
1663 PXE_BASECODE_DEVICE *Private,
1664 INTN OfferIx
1665 )
1666 {
1667 if (TryBINL (Private, OfferIx)) {
1668 return TRUE;
1669 }
1670
1671 return Release (Private);
1672 }
1673
1674 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1675 BOOLEAN
1676 TryFinishProxyBINL (
1677 PXE_BASECODE_DEVICE *Private
1678 )
1679 {
1680 INTN Index;
1681
1682 for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) {
1683 if (TryBINL (Private, Private->BinlProxies[Index])) {
1684 return TRUE;
1685 }
1686 }
1687
1688 return Release (Private);
1689 }
1690
1691 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1692
1693 //
1694 // try to finish DORA - send DHCP request, wait for ACK, check with ARP
1695 //
1696 BOOLEAN
1697 TryFinishDORA (
1698 PXE_BASECODE_DEVICE *Private,
1699 INTN OfferIx
1700 )
1701 {
1702 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
1703 EFI_IP_ADDRESS ClientIp;
1704 EFI_IP_ADDRESS ServerIp;
1705 EFI_STATUS StatCode;
1706 UNION_PTR LocalPtr;
1707 EFI_EVENT TimeoutEvent;
1708
1709 //
1710 // send DHCP request
1711 // if fail return false
1712 //
1713 DhcpRxBuf = &DHCPV4_ACK_BUFFER;
1714 DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
1715 CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (DHCP_REQ_OPTIONS));
1716 DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[OfferIx].u.Dhcpv4.yiaddr;
1717
1718 CopyMem (
1719 &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
1720 &((DHCPV4_OP_SERVER_IP *) RxBuf[OfferIx].OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1721 sizeof DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip
1722 );
1723
1724 CopyMem (
1725 Private->EfiBc.Mode->SubnetMask.Addr,
1726 &DefaultSubnetMask,
1727 4
1728 );
1729
1730 //
1731 // broadcast DHCPREQUEST
1732 //
1733 if (DoUdpWrite (
1734 Private,
1735 &BroadcastIP,
1736 &DhcpServerPort,
1737 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
1738 &DHCPClientPort
1739 ) != EFI_SUCCESS) {
1740 return FALSE;
1741 }
1742 //
1743 //
1744 //
1745 StatCode = gBS->CreateEvent (
1746 EVT_TIMER,
1747 TPL_CALLBACK,
1748 NULL,
1749 NULL,
1750 &TimeoutEvent
1751 );
1752
1753 if (EFI_ERROR (StatCode)) {
1754 return FALSE;
1755 }
1756
1757 StatCode = gBS->SetTimer (
1758 TimeoutEvent,
1759 TimerPeriodic,
1760 Private->Timeout * 10000000 + 1000000
1761 );
1762
1763 if (EFI_ERROR (StatCode)) {
1764 gBS->CloseEvent (TimeoutEvent);
1765 return FALSE;
1766 }
1767 //
1768 // wait for ACK
1769 //
1770 for (;;) {
1771 if (GetOfferAck (
1772 Private,
1773 DHCPAckEdit,
1774 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,
1775 &ServerIp,
1776 &DhcpServerPort,
1777 &ClientIp,
1778 &DHCPClientPort,
1779 DhcpRxBuf,
1780 TimeoutEvent
1781 ) != EFI_SUCCESS) {
1782 break;
1783 }
1784 //
1785 // check type of response - need DHCPACK
1786 //
1787 if (CompareMem (
1788 &DHCP_REQ_OPTIONS.OpReqIP.Ip,
1789 &DhcpRxBuf->u.Dhcpv4.yiaddr,
1790 sizeof (EFI_IPv4_ADDRESS)
1791 ) || CompareMem (
1792 &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
1793 &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
1794 sizeof (EFI_IPv4_ADDRESS)
1795 )) {
1796 continue;
1797 }
1798 //
1799 // got ACK
1800 // check with ARP that IP unused - good return true
1801 //
1802 if (!SetStationIP (Private)) {
1803 //
1804 // fail - send DHCPDECLINE and return false
1805 //
1806 DeclineOffer (Private);
1807 break;
1808 }
1809
1810 LocalPtr.OpPtr = DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
1811
1812 if (LocalPtr.OpPtr != NULL) {
1813 CopyMem (
1814 (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask,
1815 &LocalPtr.SubnetMaskStr->Ip,
1816 sizeof (EFI_IPv4_ADDRESS)
1817 );
1818 }
1819
1820 AddRouters (Private, DhcpRxBuf);
1821 gBS->CloseEvent (TimeoutEvent);
1822 return TRUE;
1823 }
1824
1825 gBS->CloseEvent (TimeoutEvent);
1826 return FALSE;
1827 }
1828
1829 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1830
1831 //
1832 // try a DHCP server of appropriate type
1833 //
1834 BOOLEAN
1835 TryDHCPFinishDORA (
1836 PXE_BASECODE_DEVICE *Private,
1837 INTN TypeIx
1838 )
1839 {
1840 INTN Index;
1841
1842 //
1843 // go through the DHCP servers of the requested type
1844 //
1845 for (Index = 0; Index < Private->ServerCount[TypeIx]; ++Index) {
1846 if (TryFinishDORA (Private, Index = Private->OfferCount[TypeIx][Index])) {
1847 if (TypeIx == BINL_IX && !TryFinishBINL (Private, Index)) {
1848 continue;
1849 }
1850
1851 return TRUE;
1852 }
1853 }
1854
1855 return FALSE;
1856 }
1857
1858 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1859
1860 //
1861 // try a DHCP only server and a proxy of appropriate type
1862 //
1863 BOOLEAN
1864 TryProxyFinishDORA (
1865 PXE_BASECODE_DEVICE *Private,
1866 INTN TypeIx
1867 )
1868 {
1869 INTN Index;
1870
1871 if (!Private->GotProxy[TypeIx]) {
1872 //
1873 // no proxies of the type wanted
1874 //
1875 return FALSE;
1876 }
1877 //
1878 // go through the DHCP only servers
1879 //
1880 for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
1881 if (TryFinishDORA (Private, Private->OfferCount[DHCP_ONLY_IX][Index])) {
1882 if (TypeIx != BINL_IX) {
1883 CopyProxyRxBuf (Private, Private->GotProxy[TypeIx] - 1);
1884 } else if (!TryFinishProxyBINL (Private)) {
1885 //
1886 // if didn't work with this DHCP, won't work with any
1887 //
1888 return FALSE;
1889 }
1890
1891 return TRUE;
1892 }
1893 }
1894
1895 return FALSE;
1896 }
1897
1898 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1899
1900 //
1901 // getting to the bottom of the barrel
1902 //
1903 BOOLEAN
1904 TryAnyWithBootfileFinishDORA (
1905 PXE_BASECODE_DEVICE *Private
1906 )
1907 {
1908 //
1909 // try a DHCP only server who has a bootfile
1910 //
1911 UNION_PTR LocalPtr;
1912 INTN Index;
1913
1914 for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
1915 INTN offer;
1916
1917 offer = Private->OfferCount[DHCP_ONLY_IX][Index];
1918
1919 if (RxBuf[offer].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && TryFinishDORA (Private, offer)) {
1920 return TRUE;
1921 }
1922 }
1923 //
1924 // really at bottom - see if be have any bootps
1925 //
1926 if (!Private->GotBootp) {
1927 return FALSE;
1928 }
1929
1930 DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[Private->GotBootp - 1].u.Dhcpv4.yiaddr;
1931
1932 if (!SetStationIP (Private)) {
1933 return FALSE;
1934 }
1935 //
1936 // treat BOOTP response as DHCP ACK packet
1937 //
1938 CopyParseRxBuf (Private, Private->GotBootp - 1, DHCPV4_ACK_INDEX);
1939
1940 LocalPtr.OpPtr = RxBuf[Private->GotBootp - 1].OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
1941
1942 if (LocalPtr.OpPtr != NULL) {
1943 *(EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask = LocalPtr.SubnetMaskStr->Ip;
1944 }
1945
1946 return TRUE;
1947 }
1948
1949 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1950
1951 /* DoDhcpDora()
1952 */
1953 EFI_STATUS
1954 DoDhcpDora (
1955 PXE_BASECODE_DEVICE *Private,
1956 BOOLEAN SortOffers
1957 )
1958 {
1959 EFI_PXE_BASE_CODE_IP_FILTER Filter;
1960 EFI_STATUS StatCode;
1961 INTN NumOffers;
1962
1963 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
1964
1965 Filter.IpCnt = 0;
1966 Filter.reserved = 0;
1967
1968 //
1969 // set filter unicast or broadcast
1970 //
1971 if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
1972 return StatCode;
1973 }
1974 //
1975 // seed random number with hardware address
1976 //
1977 SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
1978
1979 for (Private->Timeout = 1;
1980 Private->Timeout < 17;
1981 Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), Private->Timeout <<= 1
1982 ) {
1983 INTN Index;
1984
1985 InitDhcpv4TxBuf (Private);
1986 DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
1987 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
1988
1989 //
1990 // broadcast DHCPDISCOVER
1991 //
1992 StatCode = DoUdpWrite (
1993 Private,
1994 &BroadcastIP,
1995 &DhcpServerPort,
1996 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
1997 &DHCPClientPort
1998 );
1999
2000 if (StatCode != EFI_SUCCESS) {
2001 return StatCode;
2002 }
2003
2004 CopyMem (
2005 &Private->EfiBc.Mode->DhcpDiscover,
2006 (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
2007 sizeof (EFI_PXE_BASE_CODE_PACKET)
2008 );
2009
2010 //
2011 // get DHCPOFFER's
2012 //
2013 if ((StatCode = GetOffers (Private)) != EFI_SUCCESS) {
2014 if (StatCode != EFI_NO_RESPONSE) {
2015 return StatCode;
2016 }
2017
2018 continue;
2019 }
2020 //
2021 // select offer and reply DHCPREQUEST
2022 //
2023 if (SortOffers) {
2024 if (TryDHCPFinishDORA(Private, PXE10_IX) || // try DHCP with PXE10
2025 TryDHCPFinishDORA(Private, WfM11a_IX) || // no - try with WfM
2026 TryProxyFinishDORA(Private, PXE10_IX) || // no - try DHCP only and proxy with PXE10
2027 TryProxyFinishDORA(Private, WfM11a_IX) || // no - try DHCP only and proxy with WfM
2028 TryDHCPFinishDORA(Private, BINL_IX) || // no - try with WfM
2029 TryProxyFinishDORA(Private, BINL_IX) || // no - try DHCP only and proxy with PXE10
2030 TryAnyWithBootfileFinishDORA(Private))
2031 {
2032 return EFI_SUCCESS;
2033 }
2034
2035 continue;
2036 }
2037 //
2038 // FIFO order
2039 //
2040 NumOffers = Private->NumOffersReceived;
2041
2042 for (Index = 0; Index < NumOffers; ++Index) {
2043 //
2044 // ignore proxies
2045 //
2046 if (!RxBuf[Index].u.Dhcpv4.yiaddr) {
2047 continue;
2048 }
2049 //
2050 // check if a bootp server
2051 //
2052 if (!RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]) {
2053 //
2054 // it is - just check ARP
2055 //
2056 if (!SetStationIP (Private)) {
2057 continue;
2058 }
2059 }
2060 //
2061 // else check if a DHCP only server
2062 //
2063 else if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE))) {
2064 //
2065 // it is a normal DHCP offer (without any PXE options), just finish the D.O.R.A by sending DHCP request.
2066 //
2067 if (!TryFinishDORA (Private, Index)) {
2068 continue;
2069 }
2070 } else if (TryFinishDORA (Private, Index)) {
2071 if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) && !TryFinishBINL (Private, Index)) {
2072 continue;
2073 }
2074 }
2075
2076 DEBUG ((DEBUG_WARN, "\nDoDhcpDora() Got packets. "));
2077 return EFI_SUCCESS;
2078 }
2079 //
2080 // now look for DHCP onlys and a Proxy
2081 //
2082 for (Index = 0; Index < NumOffers; ++Index) {
2083 INTN Index2;
2084
2085 //
2086 // ignore proxies, bootps, non DHCP onlys, and bootable DHCPS
2087 //
2088 if (!RxBuf[Index].u.Dhcpv4.yiaddr ||
2089 !RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1] ||
2090 RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE) ||
2091 RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
2092 ) {
2093 continue;
2094 }
2095 //
2096 // found non bootable DHCP only - try to find a proxy
2097 //
2098 for (Index2 = 0; Index2 < NumOffers; ++Index2) {
2099 if (!RxBuf[Index2].u.Dhcpv4.yiaddr) {
2100 if (!TryFinishDORA (Private, Index)) {
2101 //
2102 // DHCP no ACK
2103 //
2104 break;
2105 }
2106
2107 if (RxBuf[Index2].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) {
2108 CopyProxyRxBuf (Private, Index2);
2109 } else if (!TryFinishBINL (Private, Index2)) {
2110 continue;
2111 }
2112
2113 DEBUG ((DEBUG_WARN, "\nDoDhcpDora() Got packets. "));
2114 return EFI_SUCCESS;
2115 }
2116 }
2117 }
2118 }
2119
2120 return EFI_NO_RESPONSE;
2121 }
2122
2123 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2124
2125 //
2126 // determine if the server ip is in the ip list
2127 //
2128 BOOLEAN
2129 InServerList (
2130 EFI_IP_ADDRESS *ServerIpPtr,
2131 PXE_SERVER_LISTS *ServerListPtr
2132 )
2133 {
2134 UINTN Index;
2135
2136 if (!ServerListPtr || !ServerListPtr->Ipv4List.IpCount) {
2137 return TRUE;
2138 }
2139
2140 for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
2141 if (!CompareMem (
2142 ServerIpPtr,
2143 &ServerListPtr->Ipv4List.IpList[Index],
2144 sizeof (EFI_IPv4_ADDRESS)
2145 )) {
2146 return TRUE;
2147 }
2148 }
2149
2150 return FALSE;
2151 }
2152
2153 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2154 BOOLEAN
2155 ExtractBootServerList (
2156 UINT16 Type,
2157 DHCPV4_OP_STRUCT *ptr,
2158 PXE_SERVER_LISTS **ServerListPtr
2159 )
2160 {
2161 UNION_PTR LocalPtr;
2162 INTN ServerListLen;
2163
2164 LocalPtr.OpPtr = ptr;
2165 ServerListLen = LocalPtr.BootServersStr->Header.Length;
2166
2167 //
2168 // find type
2169 //
2170 LocalPtr.BootServerList = LocalPtr.BootServersStr->ServerList;
2171
2172 while (ServerListLen) {
2173 INTN ServerEntryLen;
2174
2175 ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (LocalPtr.BootServerList->u.Ipv4List.IpCount - 1) *
2176 sizeof (EFI_IPv4_ADDRESS);
2177
2178 if (NTOHS (LocalPtr.BootServerList->Type) == Type) {
2179 *ServerListPtr = &LocalPtr.BootServerList->u;
2180 return TRUE;
2181 }
2182
2183 (LocalPtr.BytePtr) += ServerEntryLen;
2184 ServerListLen -= ServerEntryLen;
2185 }
2186
2187 return FALSE;
2188 }
2189
2190 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2191 VOID
2192 FreeMem (
2193 PXE_BASECODE_DEVICE *Private
2194 )
2195 {
2196 if (Private->TransmitBuffer != NULL) {
2197 gBS->FreePool (Private->TransmitBuffer);
2198 Private->TransmitBuffer = NULL;
2199 }
2200
2201 if (Private->ReceiveBuffers != NULL) {
2202 gBS->FreePool (Private->ReceiveBuffers);
2203 Private->ReceiveBuffers = NULL;
2204 }
2205 }
2206
2207 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2208 BOOLEAN
2209 GetMem (
2210 PXE_BASECODE_DEVICE *Private
2211 )
2212 {
2213 EFI_STATUS Status;
2214
2215 if (Private->DhcpPacketBuffer == NULL) {
2216 Status = gBS->AllocatePool (
2217 EfiBootServicesData,
2218 sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
2219 &Private->DhcpPacketBuffer
2220 );
2221
2222 if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
2223 Private->DhcpPacketBuffer = NULL;
2224 FreeMem (Private);
2225 return FALSE;
2226 }
2227 }
2228
2229 Status = gBS->AllocatePool (
2230 EfiBootServicesData,
2231 sizeof (EFI_PXE_BASE_CODE_PACKET),
2232 &Private->TransmitBuffer
2233 );
2234
2235 if (EFI_ERROR (Status) || Private->TransmitBuffer == NULL) {
2236 gBS->FreePool (Private->DhcpPacketBuffer);
2237 Private->DhcpPacketBuffer = NULL;
2238 Private->TransmitBuffer = NULL;
2239 FreeMem (Private);
2240 return FALSE;
2241 }
2242
2243 Status = gBS->AllocatePool (
2244 EfiBootServicesData,
2245 sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS),
2246 &Private->ReceiveBuffers
2247 );
2248
2249 if (EFI_ERROR (Status) || Private->ReceiveBuffers == NULL) {
2250 gBS->FreePool (Private->TransmitBuffer);
2251 gBS->FreePool (Private->DhcpPacketBuffer);
2252 Private->DhcpPacketBuffer = NULL;
2253 Private->TransmitBuffer = NULL;
2254 Private->ReceiveBuffers = NULL;
2255 FreeMem (Private);
2256 return FALSE;
2257 }
2258
2259 return TRUE;
2260 }
2261
2262 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2263
2264 /**
2265
2266
2267 **/
2268 EFI_STATUS
2269 EFIAPI
2270 BcDhcp (
2271 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
2272 IN BOOLEAN SortOffers
2273 )
2274 {
2275 EFI_PXE_BASE_CODE_IP_FILTER Filter;
2276 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2277 PXE_BASECODE_DEVICE *Private;
2278 EFI_STATUS StatCode;
2279
2280 //
2281 // Lock the instance data and make sure started
2282 //
2283 StatCode = EFI_SUCCESS;
2284
2285 if (This == NULL) {
2286 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
2287 return EFI_INVALID_PARAMETER;
2288 }
2289
2290 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2291
2292 if (Private == NULL) {
2293 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));
2294 return EFI_INVALID_PARAMETER;
2295 }
2296
2297 EfiAcquireLock (&Private->Lock);
2298
2299 if (This->Mode == NULL || !This->Mode->Started) {
2300 DEBUG ((DEBUG_ERROR, "BC was not started."));
2301 EfiReleaseLock (&Private->Lock);
2302 return EFI_NOT_STARTED;
2303 }
2304
2305 Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
2306 Filter.IpCnt = 0;
2307 Filter.reserved = 0;
2308
2309 DEBUG ((DEBUG_INFO, "\nBcDhcp() Enter. "));
2310
2311 PxebcMode = Private->EfiBc.Mode;
2312
2313 if (!GetMem (Private)) {
2314 DEBUG ((DEBUG_ERROR, "\nBcDhcp() GetMem() failed.\n"));
2315 EfiReleaseLock (&Private->Lock);
2316 return EFI_OUT_OF_RESOURCES;
2317 }
2318
2319 PxebcMode->DhcpDiscoverValid = FALSE;
2320 PxebcMode->DhcpAckReceived = FALSE;
2321 PxebcMode->ProxyOfferReceived = FALSE;
2322
2323 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
2324
2325 //
2326 // Issue BC command
2327 //
2328 if (Private->TotalSeconds == 0) {
2329 //
2330 // put in seconds field of DHCP send packets
2331 //
2332 Private->TotalSeconds = 4;
2333 }
2334
2335 if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) {
2336 //
2337 // success - copy packets
2338 //
2339 PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE;
2340
2341 CopyMem (
2342 &PxebcMode->DhcpAck,
2343 (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET,
2344 sizeof (EFI_PXE_BASE_CODE_PACKET)
2345 );
2346
2347 if (PxebcMode->ProxyOfferReceived) {
2348 CopyMem (
2349 &PxebcMode->ProxyOffer,
2350 (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET,
2351 sizeof (EFI_PXE_BASE_CODE_PACKET)
2352 );
2353 }
2354 }
2355 //
2356 // set filter back to unicast
2357 //
2358 IpFilter (Private, &Filter);
2359
2360 FreeMem (Private);
2361
2362 //
2363 // Unlock the instance data
2364 //
2365 DEBUG ((DEBUG_WARN, "\nBcDhcp() Exit = %xh ", StatCode));
2366
2367 EfiReleaseLock (&Private->Lock);
2368 return StatCode;
2369 }
2370
2371 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2372 BOOLEAN
2373 VerifyCredentialOption (
2374 UINT8 *tx,
2375 UINT8 *rx
2376 )
2377 {
2378 UINTN n;
2379
2380 //
2381 // Fail verification if either pointer is NULL.
2382 //
2383 if (tx == NULL || rx == NULL) {
2384 return FALSE;
2385 }
2386 //
2387 // Fail verification if tx[0] is not a credential type option
2388 // or if the length is zero or not a multiple of four.
2389 //
2390 if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) {
2391 return FALSE;
2392 }
2393 //
2394 // Fail verification if rx[0] is not a credential type option
2395 // or if the length is not equal to four.
2396 //
2397 if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) {
2398 return FALSE;
2399 }
2400 //
2401 // Look through transmitted credential types for a copy
2402 // of the received credential type.
2403 //
2404 for (n = 0; n < tx[1]; n += 4) {
2405 if (!CompareMem (&tx[n + 2], &rx[2], 4)) {
2406 return TRUE;
2407 }
2408 }
2409
2410 return FALSE;
2411 }
2412
2413 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2414
2415 /**
2416
2417
2418 **/
2419 EFI_STATUS
2420 DoDiscover (
2421 PXE_BASECODE_DEVICE *Private,
2422 UINT16 OpFlags,
2423 IN UINT16 Type,
2424 IN UINT16 *LayerPtr,
2425 IN BOOLEAN UseBis,
2426 EFI_IP_ADDRESS *DestPtr,
2427 PXE_SERVER_LISTS *ServerListPtr
2428 )
2429 {
2430 EFI_PXE_BASE_CODE_UDP_PORT ClientPort;
2431 EFI_PXE_BASE_CODE_UDP_PORT ServerPort;
2432 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2433 EFI_STATUS StatCode;
2434 EFI_EVENT TimeoutEvent;
2435 UINT8 OpLen;
2436
2437 PxebcMode = Private->EfiBc.Mode;
2438
2439 if (DestPtr->Addr[0] == 0) {
2440 DEBUG ((DEBUG_WARN, "\nDoDiscover() !DestPtr->Addr[0]"));
2441 return EFI_INVALID_PARAMETER;
2442 }
2443 //
2444 // seed random number with hardware address
2445 //
2446 SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
2447
2448 if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) {
2449 ClientPort = DHCPClientPort;
2450 ServerPort = DhcpServerPort;
2451 } else {
2452 ClientPort = PSEUDO_DHCP_CLIENT_PORT;
2453 ServerPort = PseudoDhcpServerPort;
2454 }
2455
2456 if (UseBis) {
2457 *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG;
2458 } else {
2459 *LayerPtr &= PXE_BOOT_LAYER_MASK;
2460 }
2461
2462 for (Private->Timeout = 1;
2463 Private->Timeout < 5;
2464 Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout
2465 ) {
2466 InitDhcpv4TxBuf (Private);
2467 //
2468 // initialize DHCP message structure
2469 //
2470 DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
2471 DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
2472 CopyMem (
2473 &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2474 &PxebcMode->StationIp,
2475 sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr
2476 );
2477
2478 DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
2479 DISCOVERoptions.Header.OpCode = OP_VENDOR_SPECIFIC;
2480 DISCOVERoptions.BootItem.Header.OpCode = VEND_PXE_BOOT_ITEM;
2481 DISCOVERoptions.BootItem.Header.Length = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM);
2482 DISCOVERoptions.BootItem.Type = HTONS (Type);
2483 DISCOVERoptions.BootItem.Layer = HTONS (*LayerPtr);
2484
2485 if (UseBis) {
2486 EFI_BIS_PROTOCOL *BisPtr;
2487 BIS_APPLICATION_HANDLE BisAppHandle;
2488 EFI_BIS_DATA *BisDataSigInfo;
2489 EFI_BIS_SIGNATURE_INFO *BisSigInfo;
2490 UINTN Index;
2491 UINTN Index2;
2492
2493 BisPtr = PxebcBisStart (
2494 Private,
2495 &BisAppHandle,
2496 &BisDataSigInfo
2497 );
2498
2499 if (BisPtr == NULL) {
2500 //
2501 // %%TBD - In order to get here, BIS must have
2502 // been present when PXEBC.Start() was called.
2503 // BIS had to be shutdown/removed/damaged
2504 // before PXEBC.Discover() was called.
2505 // Do we need to document a specific error
2506 // for this case?
2507 //
2508 return EFI_OUT_OF_RESOURCES;
2509 }
2510 //
2511 // Compute number of credential types.
2512 //
2513 Index2 = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO);
2514
2515 DISCREDoptions.Header.OpCode = VEND_PXE_CREDENTIAL_TYPES;
2516
2517 DISCREDoptions.Header.Length = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL));
2518
2519 OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length);
2520
2521 BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data;
2522
2523 for (Index = 0; Index < Index2; ++Index) {
2524 UINT32 x;
2525
2526 CopyMem (&x, &BisSigInfo[Index], sizeof x);
2527 x = HTONL (x);
2528 CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x);
2529 }
2530
2531 PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
2532 } else {
2533 OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS);
2534 }
2535
2536 DISCOVERoptions.Header.Length = OpLen;
2537
2538 ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END;
2539 ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen] = OP_END;
2540
2541 StatCode = DoUdpWrite (
2542 Private,
2543 DestPtr,
2544 &ServerPort,
2545 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2546 &ClientPort
2547 );
2548
2549 if (StatCode != EFI_SUCCESS) {
2550 return StatCode;
2551 }
2552 //
2553 //
2554 //
2555 StatCode = gBS->CreateEvent (
2556 EVT_TIMER,
2557 TPL_CALLBACK,
2558 NULL,
2559 NULL,
2560 &TimeoutEvent
2561 );
2562
2563 if (EFI_ERROR (StatCode)) {
2564 return StatCode;
2565 }
2566
2567 StatCode = gBS->SetTimer (
2568 TimeoutEvent,
2569 TimerRelative,
2570 Private->Timeout * 10000000 + 1000000
2571 );
2572
2573 if (EFI_ERROR (StatCode)) {
2574 gBS->CloseEvent (TimeoutEvent);
2575 return StatCode;
2576 }
2577 //
2578 // wait for ACK
2579 //
2580 for (;;) {
2581 DHCP_RECEIVE_BUFFER *RxBufPtr;
2582 UINT16 TmpType;
2583 UINT16 TmpLayer;
2584
2585 RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER;
2586 ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
2587
2588 if (GetOfferAck (
2589 Private,
2590 AckEdit,
2591 OpFlags,
2592 (EFI_IP_ADDRESS *) &Private->ServerIp,
2593 0,
2594 (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
2595 &ClientPort,
2596 RxBufPtr,
2597 TimeoutEvent
2598 ) != EFI_SUCCESS) {
2599 break;
2600 }
2601 //
2602 // check type of response - need PXEClient DHCPACK of proper type with bootfile
2603 //
2604 if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) ||
2605 (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) ||
2606 !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] ||
2607 !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] ||
2608 !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) {
2609
2610 continue;
2611 }
2612
2613 TmpType = TmpLayer = 0;
2614
2615 if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
2616 TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type);
2617
2618 if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) {
2619 TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8);
2620 } else {
2621 TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer);
2622 }
2623 }
2624
2625 if (TmpType != Type) {
2626 continue;
2627 }
2628
2629 if (UseBis) {
2630 if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) {
2631 continue;
2632 }
2633
2634 if (!VerifyCredentialOption (
2635 (UINT8 *) &DISCREDoptions.Header,
2636 (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]
2637 )) {
2638 continue;
2639 }
2640 }
2641
2642 *LayerPtr = TmpLayer;
2643
2644 if (UseBis) {
2645 CopyMem (
2646 &PxebcMode->PxeBisReply,
2647 &RxBufPtr->u.Dhcpv4,
2648 sizeof (EFI_PXE_BASE_CODE_PACKET)
2649 );
2650
2651 PxebcMode->PxeBisReplyReceived = TRUE;
2652
2653 StatCode = DoDiscover (
2654 Private,
2655 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2656 Type,
2657 LayerPtr,
2658 FALSE,
2659 &Private->ServerIp,
2660 0
2661 );
2662
2663 gBS->CloseEvent (TimeoutEvent);
2664 return StatCode;
2665 }
2666
2667 PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE;
2668
2669 CopyMem (
2670 &PxebcMode->PxeDiscover,
2671 &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
2672 sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER)
2673 );
2674
2675 CopyMem (
2676 &PxebcMode->PxeReply,
2677 &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4,
2678 sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4)
2679 );
2680
2681 AddRouters (Private, RxBufPtr);
2682
2683 gBS->CloseEvent (TimeoutEvent);
2684 return EFI_SUCCESS;
2685 }
2686
2687 gBS->CloseEvent (TimeoutEvent);
2688 }
2689 //
2690 // end for loop
2691 //
2692 return EFI_TIMEOUT;
2693 }
2694
2695 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2696
2697 /**
2698 Parameters:
2699 Private := Pointer to PxeBc interface
2700 Type :=
2701 LayerPtr :=
2702 UseBis :=
2703 DiscoverInfoPtr :=
2704 McastServerListPtr :=
2705 ServerListPtr :=
2706
2707
2708 **/
2709 EFI_STATUS
2710 Discover (
2711 PXE_BASECODE_DEVICE *Private,
2712 IN UINT16 Type,
2713 IN UINT16 *LayerPtr,
2714 IN BOOLEAN UseBis,
2715 IN EFI_PXE_BASE_CODE_DISCOVER_INFO *DiscoverInfoPtr,
2716 PXE_SERVER_LISTS *McastServerListPtr,
2717 PXE_SERVER_LISTS *ServerListPtr
2718 )
2719 {
2720 EFI_IP_ADDRESS DestIp;
2721 EFI_STATUS StatCode;
2722
2723 DEBUG ((DEBUG_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr));
2724
2725 if (UseBis) {
2726 DEBUG ((DEBUG_INFO, "BIS "));
2727 }
2728 //
2729 // get dest IP addr - mcast, bcast, or unicast
2730 //
2731 if (DiscoverInfoPtr->UseMCast) {
2732 DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4;
2733
2734 DEBUG (
2735 (DEBUG_INFO,
2736 "\nDiscover() MCast %d.%d.%d.%d ",
2737 DestIp.v4.Addr[0],
2738 DestIp.v4.Addr[1],
2739 DestIp.v4.Addr[2],
2740 DestIp.v4.Addr[3])
2741 );
2742
2743 if ((StatCode = DoDiscover (
2744 Private,
2745 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2746 Type,
2747 LayerPtr,
2748 UseBis,
2749 &DestIp,
2750 McastServerListPtr
2751 )) != EFI_TIMEOUT) {
2752 DEBUG (
2753 (DEBUG_WARN,
2754 "\nDiscover() status == %r (%Xh)",
2755 StatCode,
2756 StatCode)
2757 );
2758
2759 return StatCode;
2760 }
2761 }
2762
2763 if (DiscoverInfoPtr->UseBCast) {
2764 DEBUG ((DEBUG_INFO, "\nDiscver() BCast "));
2765
2766 if ((StatCode = DoDiscover (
2767 Private,
2768 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2769 Type,
2770 LayerPtr,
2771 UseBis,
2772 &BroadcastIP,
2773 McastServerListPtr
2774 )) != EFI_TIMEOUT) {
2775
2776 DEBUG ((DEBUG_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode));
2777
2778 return StatCode;
2779 }
2780 }
2781
2782 if (DiscoverInfoPtr->UseUCast) {
2783 UINTN Index;
2784
2785 DEBUG (
2786 (DEBUG_INFO,
2787 "\nDiscover() UCast IP#=%d ",
2788 ServerListPtr->Ipv4List.IpCount)
2789 );
2790
2791 for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
2792 CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4);
2793
2794 DEBUG (
2795 (DEBUG_INFO,
2796 "\nDiscover() UCast %d.%d.%d.%d ",
2797 DestIp.v4.Addr[0],
2798 DestIp.v4.Addr[1],
2799 DestIp.v4.Addr[2],
2800 DestIp.v4.Addr[3])
2801 );
2802
2803 if ((StatCode = DoDiscover (
2804 Private,
2805 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
2806 Type,
2807 LayerPtr,
2808 UseBis,
2809 &DestIp,
2810 0
2811 )) != EFI_TIMEOUT) {
2812 DEBUG (
2813 (DEBUG_WARN,
2814 "\nDiscover() status == %r (%Xh)",
2815 StatCode,
2816 StatCode)
2817 );
2818
2819 return StatCode;
2820 }
2821 }
2822 }
2823
2824 DEBUG ((DEBUG_WARN, "\nDiscover() TIMEOUT"));
2825
2826 return EFI_TIMEOUT;
2827 }
2828
2829 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2830
2831 /* BcDiscover()
2832 */
2833
2834 /**
2835
2836
2837 **/
2838 EFI_STATUS
2839 EFIAPI
2840 BcDiscover (
2841 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
2842 IN UINT16 Type,
2843 IN UINT16 *LayerPtr,
2844 IN BOOLEAN UseBis,
2845 IN EFI_PXE_BASE_CODE_DISCOVER_INFO * DiscoverInfoPtr OPTIONAL
2846 )
2847 {
2848 EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
2849 EFI_PXE_BASE_CODE_MODE *PxebcMode;
2850 DHCP_RECEIVE_BUFFER *DhcpRxBuf;
2851 PXE_SERVER_LISTS DefaultSrvList;
2852 PXE_SERVER_LISTS *ServerListPtr;
2853 PXE_SERVER_LISTS *McastServerListPtr;
2854 UNION_PTR LocalPtr;
2855 UINTN Index;
2856 UINTN Index2;
2857 BOOLEAN AcquiredSrvList;
2858 EFI_STATUS StatCode;
2859 PXE_BASECODE_DEVICE *Private;
2860
2861 //
2862 // Lock the instance data and make sure started
2863 //
2864 StatCode = EFI_SUCCESS;
2865
2866 if (This == NULL) {
2867 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
2868 return EFI_INVALID_PARAMETER;
2869 }
2870
2871 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
2872
2873 if (Private == NULL) {
2874 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
2875 return EFI_INVALID_PARAMETER;
2876 }
2877
2878 EfiAcquireLock (&Private->Lock);
2879
2880 if (This->Mode == NULL || !This->Mode->Started) {
2881 DEBUG ((DEBUG_ERROR, "BC was not started."));
2882 EfiReleaseLock (&Private->Lock);
2883 return EFI_NOT_STARTED;
2884 }
2885
2886 ServerListPtr = NULL;
2887 McastServerListPtr = NULL;
2888 AcquiredSrvList = FALSE;
2889
2890 PxebcMode = Private->EfiBc.Mode;
2891
2892 if (!GetMem (Private)) {
2893 EfiReleaseLock (&Private->Lock);
2894 return EFI_OUT_OF_RESOURCES;
2895 }
2896
2897 if (UseBis) {
2898 if (!PxebcMode->BisSupported) {
2899 EfiReleaseLock (&Private->Lock);
2900 return EFI_INVALID_PARAMETER;
2901 }
2902 }
2903
2904 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
2905
2906 if (Private->TotalSeconds == 0) {
2907 //
2908 // put in seconds field of DHCP send packets
2909 //
2910 Private->TotalSeconds = 4;
2911 }
2912
2913 ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
2914
2915 //
2916 // if layer number not zero, use previous discover
2917 //
2918 if (*LayerPtr != 0) {
2919 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0"));
2920
2921 if (DiscoverInfoPtr != NULL) {
2922 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n"));
2923
2924 EfiReleaseLock (&Private->Lock);
2925 return EFI_INVALID_PARAMETER;
2926 }
2927
2928 if (!PxebcMode->PxeDiscoverValid) {
2929 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n"));
2930
2931 EfiReleaseLock (&Private->Lock);
2932 return EFI_INVALID_PARAMETER;
2933 }
2934
2935 if (!PxebcMode->PxeReplyReceived) {
2936 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n"));
2937
2938 EfiReleaseLock (&Private->Lock);
2939 return EFI_INVALID_PARAMETER;
2940 }
2941
2942 if (UseBis && !PxebcMode->PxeBisReplyReceived) {
2943 DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeBisReplyReceived == 0\n"));
2944
2945 EfiReleaseLock (&Private->Lock);
2946 return EFI_INVALID_PARAMETER;
2947 }
2948
2949 DefaultInfo.UseUCast = TRUE;
2950 DiscoverInfoPtr = &DefaultInfo;
2951
2952 DefaultSrvList.Ipv4List.IpCount = 1;
2953 CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4);
2954
2955 ServerListPtr = &DefaultSrvList;
2956 }
2957 //
2958 // layer is zero - see if info is supplied or if we need to use info from a cached offer
2959 //
2960 else if (!DiscoverInfoPtr) {
2961 //
2962 // not supplied - generate it
2963 // make sure that there is cached, appropriate information
2964 // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail
2965 //
2966 DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
2967
2968 if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) {
2969 DEBUG ((DEBUG_WARN, "\nBcDiscover() !ack && !proxy"));
2970 EfiReleaseLock (&Private->Lock);
2971 return EFI_INVALID_PARAMETER;
2972 }
2973
2974 DiscoverInfoPtr = &DefaultInfo;
2975
2976 LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
2977
2978 //
2979 // if multicast enabled, need multicast address
2980 //
2981 if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) {
2982 DefaultInfo.UseMCast = TRUE;
2983
2984 CopyMem (
2985 ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp),
2986 &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip,
2987 sizeof (EFI_IPv4_ADDRESS)
2988 );
2989 }
2990
2991 DefaultInfo.UseBCast = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0);
2992
2993 DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0);
2994
2995 DefaultInfo.UseUCast = (BOOLEAN)
2996 (
2997 (DefaultInfo.MustUseList) ||
2998 ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
2999 );
3000
3001 if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList (
3002 Type,
3003 DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1],
3004 &ServerListPtr
3005 )) {
3006 DEBUG ((DEBUG_WARN, "\nBcDiscover() type not in list"));
3007 EfiReleaseLock (&Private->Lock);
3008 return EFI_INVALID_PARAMETER;
3009 }
3010 }
3011 //
3012 // Info supplied - make SrvList if required
3013 // if we use ucast discovery or must use list, there better be one
3014 //
3015 else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) {
3016 //
3017 // there better be a list
3018 //
3019 if (DiscoverInfoPtr->IpCnt == 0) {
3020 DEBUG ((DEBUG_WARN, "\nBcDiscover() no bootserver list"));
3021 EfiReleaseLock (&Private->Lock);
3022 return EFI_INVALID_PARAMETER;
3023 }
3024 //
3025 // get its size
3026 //
3027 for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
3028 if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
3029 if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) {
3030 if (Index2 != 0) {
3031 DEBUG ((DEBUG_WARN, "\nBcDiscover() accept any?"));
3032 EfiReleaseLock (&Private->Lock);
3033 return EFI_INVALID_PARAMETER;
3034 } else {
3035 Index2 = 1;
3036 DefaultSrvList.Ipv4List.IpCount = 0;
3037 ServerListPtr = &DefaultSrvList;
3038 break;
3039 }
3040 } else {
3041 ++Index2;
3042 }
3043 }
3044 }
3045
3046 if (Index2 == 0) {
3047 DEBUG ((DEBUG_WARN, "\nBcDiscover() !Index2?"));
3048 EfiReleaseLock (&Private->Lock);
3049 return EFI_INVALID_PARAMETER;
3050 }
3051
3052 if (ServerListPtr == NULL) {
3053 ServerListPtr = AllocatePool (
3054 sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS)
3055 );
3056
3057 if (ServerListPtr == NULL) {
3058 EfiReleaseLock (&Private->Lock);
3059 return EFI_OUT_OF_RESOURCES;
3060 }
3061 //
3062 // build an array of IP addresses from the server list
3063 //
3064 AcquiredSrvList = TRUE;
3065 ServerListPtr->Ipv4List.IpCount = (UINT8) Index2;
3066
3067 for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
3068 if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
3069 CopyMem (
3070 &ServerListPtr->Ipv4List.IpList[Index2++],
3071 &DiscoverInfoPtr->SrvList[Index].IpAddr.v4,
3072 sizeof ServerListPtr->Ipv4List.IpList[0]
3073 );
3074 }
3075 }
3076 }
3077 }
3078
3079 if (DiscoverInfoPtr->MustUseList) {
3080 McastServerListPtr = ServerListPtr;
3081 }
3082
3083 if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) {
3084 DEBUG ((DEBUG_WARN, "\nBcDiscover() Nothing to use!\n"));
3085
3086 EfiReleaseLock (&Private->Lock);
3087 return EFI_INVALID_PARAMETER;
3088 }
3089
3090 PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE;
3091
3092 StatCode = Discover (
3093 Private,
3094 Type,
3095 LayerPtr,
3096 UseBis,
3097 DiscoverInfoPtr,
3098 McastServerListPtr,
3099 ServerListPtr
3100 );
3101
3102 if (AcquiredSrvList) {
3103 gBS->FreePool (ServerListPtr);
3104 }
3105
3106 FreeMem (Private);
3107
3108 //
3109 // Unlock the instance data
3110 //
3111 DEBUG (
3112 (DEBUG_INFO,
3113 "\nBcDiscover() status == %r (%Xh)\n",
3114 StatCode,
3115 StatCode)
3116 );
3117
3118 EfiReleaseLock (&Private->Lock);
3119 return StatCode;
3120 }
3121
3122 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3123
3124 /**
3125
3126
3127 **/
3128 EFI_STATUS
3129 EFIAPI
3130 BcSetPackets (
3131 IN EFI_PXE_BASE_CODE_PROTOCOL * This,
3132 BOOLEAN *NewDhcpDiscoverValid, OPTIONAL
3133 BOOLEAN *NewDhcpAckReceived, OPTIONAL
3134 BOOLEAN *NewProxyOfferReceived, OPTIONAL
3135 BOOLEAN *NewPxeDiscoverValid, OPTIONAL
3136 BOOLEAN *NewPxeReplyReceived, OPTIONAL
3137 BOOLEAN *NewPxeBisReplyReceived, OPTIONAL
3138 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
3139 IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
3140 IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
3141 IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
3142 IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
3143 IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
3144 )
3145 {
3146 EFI_PXE_BASE_CODE_MODE *PxebcMode;
3147 EFI_STATUS Status;
3148 PXE_BASECODE_DEVICE *Private;
3149
3150 //
3151 // Lock the instance data and make sure started
3152 //
3153
3154 if (This == NULL) {
3155 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
3156 return EFI_INVALID_PARAMETER;
3157 }
3158
3159 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
3160
3161 if (Private == NULL) {
3162 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
3163 return EFI_INVALID_PARAMETER;
3164 }
3165
3166 EfiAcquireLock (&Private->Lock);
3167
3168 if (This->Mode == NULL || !This->Mode->Started) {
3169 DEBUG ((DEBUG_ERROR, "BC was not started."));
3170 EfiReleaseLock (&Private->Lock);
3171 return EFI_NOT_STARTED;
3172 }
3173
3174 PxebcMode = Private->EfiBc.Mode;
3175
3176 if (Private->DhcpPacketBuffer == NULL) {
3177 Status = gBS->AllocatePool (
3178 EfiBootServicesData,
3179 sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
3180 &Private->DhcpPacketBuffer
3181 );
3182
3183 if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
3184 Private->DhcpPacketBuffer = NULL;
3185 EfiReleaseLock (&Private->Lock);
3186 return EFI_OUT_OF_RESOURCES;
3187 }
3188 }
3189 //
3190 // Issue BC command
3191 //
3192 //
3193 // reset
3194 //
3195 Private->FileSize = 0;
3196 if (NewDhcpDiscoverValid != NULL) {
3197 PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
3198 }
3199
3200 if (NewDhcpAckReceived != NULL) {
3201 PxebcMode->DhcpAckReceived = *NewDhcpAckReceived;
3202 }
3203
3204 if (NewProxyOfferReceived != NULL) {
3205 PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived;
3206 }
3207
3208 if (NewPxeDiscoverValid != NULL) {
3209 PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid;
3210 }
3211
3212 if (NewPxeReplyReceived != NULL) {
3213 PxebcMode->PxeReplyReceived = *NewPxeReplyReceived;
3214 }
3215
3216 if (NewPxeBisReplyReceived != NULL) {
3217 PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
3218 }
3219
3220 if (NewDhcpDiscover != NULL) {
3221 CopyMem (
3222 &PxebcMode->DhcpDiscover,
3223 NewDhcpDiscover,
3224 sizeof *NewDhcpDiscover
3225 );
3226 }
3227
3228 if (NewDhcpAck != NULL) {
3229 CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX);
3230 }
3231
3232 if (NewProxyOffer != NULL) {
3233 CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX);
3234 }
3235
3236 if (NewPxeDiscover != NULL) {
3237 CopyMem (
3238 &PxebcMode->PxeDiscover,
3239 NewPxeDiscover,
3240 sizeof *NewPxeDiscover
3241 );
3242 }
3243
3244 if (NewPxeReply != NULL) {
3245 CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX);
3246 }
3247
3248 if (NewPxeBisReply != NULL) {
3249 CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX);
3250 }
3251 //
3252 // Unlock the instance data
3253 //
3254 EfiReleaseLock (&Private->Lock);
3255 return EFI_SUCCESS;
3256 }
3257
3258 /* eof - pxe_bc_dhcp.c */