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