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