]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
ArmVirtPkg: implement DT-based ArmGicArchLib
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp4.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Functions implementation related with DHCPv4 for UefiPxeBc Driver.\r
3\r
61047329 4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
a3bcde70
HT
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "PxeBcImpl.h"\r
17\r
18//\r
19// This is a map from the interested DHCP4 option tags' index to the tag value.\r
20//\r
21UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {\r
22 PXEBC_DHCP4_TAG_BOOTFILE_LEN,\r
23 PXEBC_DHCP4_TAG_VENDOR,\r
24 PXEBC_DHCP4_TAG_OVERLOAD,\r
25 PXEBC_DHCP4_TAG_MSG_TYPE,\r
26 PXEBC_DHCP4_TAG_SERVER_ID,\r
27 PXEBC_DHCP4_TAG_CLASS_ID,\r
28 PXEBC_DHCP4_TAG_BOOTFILE\r
29};\r
30\r
31//\r
32// There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.\r
33//\r
34UINT32 mPxeDhcpTimeout[4] = {4, 8, 16, 32};\r
35\r
36\r
37/**\r
38 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.\r
39\r
40 @param[in] Buffer Pointer to the option buffer.\r
41 @param[in] Length Length of the option buffer.\r
42 @param[in] OptTag Tag of the required option.\r
43\r
44 @retval NULL Failed to find the required option.\r
45 @retval Others The position of the required option.\r
46\r
47**/\r
48EFI_DHCP4_PACKET_OPTION *\r
49PxeBcParseDhcp4Options (\r
50 IN UINT8 *Buffer,\r
51 IN UINT32 Length,\r
52 IN UINT8 OptTag\r
53 )\r
54{\r
55 EFI_DHCP4_PACKET_OPTION *Option;\r
56 UINT32 Offset;\r
57\r
58 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
59 Offset = 0;\r
60\r
61 while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {\r
62\r
63 if (Option->OpCode == OptTag) {\r
64 //\r
65 // Found the required option.\r
66 //\r
67 return Option;\r
68 }\r
69\r
70 //\r
71 // Skip the current option to the next.\r
72 //\r
73 if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
74 Offset++;\r
75 } else {\r
76 Offset += Option->Length + 2;\r
77 }\r
78\r
79 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
80 }\r
81\r
82 return NULL;\r
83}\r
84\r
85\r
86/**\r
87 Parse the PXE vender options and extract the information from them.\r
88\r
89 @param[in] Dhcp4Option Pointer to vendor options in buffer.\r
90 @param[in] VendorOption Pointer to structure to store information in vendor options.\r
91\r
92**/\r
93VOID\r
94PxeBcParseVendorOptions (\r
95 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,\r
96 IN PXEBC_VENDOR_OPTION *VendorOption\r
97 )\r
98{\r
99 UINT32 *BitMap;\r
100 UINT8 VendorOptionLen;\r
101 EFI_DHCP4_PACKET_OPTION *PxeOption;\r
102 UINT8 Offset;\r
103\r
104 BitMap = VendorOption->BitMap;\r
105 VendorOptionLen = Dhcp4Option->Length;\r
106 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];\r
107 Offset = 0;\r
108\r
109 ASSERT (PxeOption != NULL);\r
110\r
111 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {\r
112 //\r
113 // Parse all the interesting PXE vendor options one by one.\r
114 //\r
115 switch (PxeOption->OpCode) {\r
116\r
117 case PXEBC_VENDOR_TAG_MTFTP_IP:\r
118\r
119 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
120 break;\r
121\r
122 case PXEBC_VENDOR_TAG_MTFTP_CPORT:\r
123\r
124 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));\r
125 break;\r
126\r
127 case PXEBC_VENDOR_TAG_MTFTP_SPORT:\r
128\r
129 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));\r
130 break;\r
131\r
132 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:\r
133\r
134 VendorOption->MtftpTimeout = *PxeOption->Data;\r
135 break;\r
136\r
137 case PXEBC_VENDOR_TAG_MTFTP_DELAY:\r
138\r
139 VendorOption->MtftpDelay = *PxeOption->Data;\r
140 break;\r
141\r
142 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:\r
143\r
144 VendorOption->DiscoverCtrl = *PxeOption->Data;\r
145 break;\r
146\r
147 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:\r
148\r
149 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
150 break;\r
151\r
152 case PXEBC_VENDOR_TAG_BOOT_SERVERS:\r
153\r
154 VendorOption->BootSvrLen = PxeOption->Length;\r
155 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;\r
156 break;\r
157\r
158 case PXEBC_VENDOR_TAG_BOOT_MENU:\r
159\r
160 VendorOption->BootMenuLen = PxeOption->Length;\r
161 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;\r
162 break;\r
163\r
164 case PXEBC_VENDOR_TAG_MENU_PROMPT:\r
165\r
166 VendorOption->MenuPromptLen = PxeOption->Length;\r
167 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data;\r
168 break;\r
169\r
170 case PXEBC_VENDOR_TAG_MCAST_ALLOC:\r
171\r
172 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
173 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));\r
174 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));\r
175 break;\r
176\r
177 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:\r
178\r
179 VendorOption->CredTypeLen = PxeOption->Length;\r
180 VendorOption->CredType = (UINT32 *) PxeOption->Data;\r
181 break;\r
182\r
183 case PXEBC_VENDOR_TAG_BOOT_ITEM:\r
184\r
185 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));\r
186 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));\r
187 break;\r
188\r
189 default:\r
190 //\r
191 // Not interesting PXE vendor options.\r
192 //\r
193 break;\r
194 }\r
195\r
196 //\r
197 // Set the bit map for the special PXE options.\r
198 //\r
199 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);\r
200\r
201 //\r
202 // Continue to the next option.\r
203 //\r
204 if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
205 Offset++;\r
206 } else {\r
207 Offset = (UINT8) (Offset + PxeOption->Length + 2);\r
208 }\r
209\r
210 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);\r
211 }\r
212}\r
213\r
214\r
215/**\r
216 Build the options buffer for the DHCPv4 request packet.\r
217\r
218 @param[in] Private Pointer to PxeBc private data.\r
219 @param[out] OptList Pointer to the option pointer array.\r
220 @param[in] Buffer Pointer to the buffer to contain the option list.\r
221 @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.\r
222 Otherwise, it is not necessary.\r
223\r
224 @return Index The count of the built-in options.\r
225\r
226**/\r
227UINT32\r
228PxeBcBuildDhcp4Options (\r
229 IN PXEBC_PRIVATE_DATA *Private,\r
230 OUT EFI_DHCP4_PACKET_OPTION **OptList,\r
231 IN UINT8 *Buffer,\r
232 IN BOOLEAN NeedMsgType\r
233 )\r
234{\r
235 UINT32 Index;\r
236 PXEBC_DHCP4_OPTION_ENTRY OptEnt;\r
237 UINT16 Value;\r
238\r
239 Index = 0;\r
240 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
241\r
242 if (NeedMsgType) {\r
243 //\r
244 // Append message type.\r
245 //\r
246 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MSG_TYPE;\r
247 OptList[Index]->Length = 1;\r
248 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;\r
249 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;\r
250 Index++;\r
251 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
252\r
253 //\r
254 // Append max message size.\r
255 //\r
256 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MAXMSG;\r
257 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);\r
258 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;\r
259 Value = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);\r
260 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));\r
261 Index++;\r
262 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
263 }\r
264\r
265 //\r
266 // Append parameter request list option.\r
267 //\r
268 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_PARA_LIST;\r
269 OptList[Index]->Length = 35;\r
270 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
271 OptEnt.Para->ParaList[0] = PXEBC_DHCP4_TAG_NETMASK;\r
272 OptEnt.Para->ParaList[1] = PXEBC_DHCP4_TAG_TIME_OFFSET;\r
273 OptEnt.Para->ParaList[2] = PXEBC_DHCP4_TAG_ROUTER;\r
274 OptEnt.Para->ParaList[3] = PXEBC_DHCP4_TAG_TIME_SERVER;\r
275 OptEnt.Para->ParaList[4] = PXEBC_DHCP4_TAG_NAME_SERVER;\r
276 OptEnt.Para->ParaList[5] = PXEBC_DHCP4_TAG_DNS_SERVER;\r
277 OptEnt.Para->ParaList[6] = PXEBC_DHCP4_TAG_HOSTNAME;\r
278 OptEnt.Para->ParaList[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN;\r
279 OptEnt.Para->ParaList[8] = PXEBC_DHCP4_TAG_DOMAINNAME;\r
280 OptEnt.Para->ParaList[9] = PXEBC_DHCP4_TAG_ROOTPATH;\r
281 OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;\r
282 OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;\r
283 OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;\r
284 OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;\r
285 OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;\r
286 OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;\r
287 OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;\r
288 OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;\r
289 OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;\r
290 OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;\r
291 OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;\r
292 OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;\r
293 OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;\r
294 OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;\r
295 OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;\r
296 OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;\r
297 OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;\r
298 OptEnt.Para->ParaList[27] = 0x80;\r
299 OptEnt.Para->ParaList[28] = 0x81;\r
300 OptEnt.Para->ParaList[29] = 0x82;\r
301 OptEnt.Para->ParaList[30] = 0x83;\r
302 OptEnt.Para->ParaList[31] = 0x84;\r
303 OptEnt.Para->ParaList[32] = 0x85;\r
304 OptEnt.Para->ParaList[33] = 0x86;\r
305 OptEnt.Para->ParaList[34] = 0x87;\r
306 Index++;\r
307 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
308\r
309 //\r
310 // Append UUID/Guid-based client identifier option\r
311 //\r
312 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UUID;\r
313 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID);\r
314 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
315 OptEnt.Uuid->Type = 0;\r
316 Index++;\r
317 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
318\r
19ddbb25 319 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {\r
a3bcde70
HT
320 //\r
321 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
322 //\r
323 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
324 }\r
325\r
326 //\r
327 // Append client network device interface option\r
328 //\r
329 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UNDI;\r
330 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);\r
331 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
332\r
333 if (Private->Nii != NULL) {\r
334 OptEnt.Undi->Type = Private->Nii->Type;\r
335 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
336 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
337 } else {\r
338 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
339 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
340 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
341 }\r
342\r
343 Index++;\r
344 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
345\r
346 //\r
347 // Append client system architecture option\r
348 //\r
349 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_ARCH;\r
350 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);\r
351 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
352 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);\r
353 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
354 Index++;\r
355 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
356\r
357 //\r
358 // Append vendor class identify option\r
359 //\r
360 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_CLASS_ID;\r
361 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);\r
362 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
363 CopyMem (\r
364 OptEnt.Clid,\r
365 DEFAULT_CLASS_ID_DATA,\r
366 sizeof (PXEBC_DHCP4_OPTION_CLID)\r
367 );\r
368 PxeBcUintnToAscDecWithFormat (\r
369 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,\r
370 OptEnt.Clid->ArchitectureType,\r
371 sizeof (OptEnt.Clid->ArchitectureType)\r
372 );\r
373\r
374 if (Private->Nii != NULL) {\r
375 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
376 PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
377 PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
378 }\r
379\r
380 Index++;\r
381\r
382 return Index;\r
383}\r
384\r
385\r
386/**\r
387 Create a template DHCPv4 packet as a seed.\r
388\r
389 @param[out] Seed Pointer to the seed packet.\r
390 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.\r
391\r
392**/\r
393VOID\r
394PxeBcSeedDhcp4Packet (\r
395 OUT EFI_DHCP4_PACKET *Seed,\r
396 IN EFI_UDP4_PROTOCOL *Udp4\r
397 )\r
398{\r
399 EFI_SIMPLE_NETWORK_MODE Mode;\r
400 EFI_DHCP4_HEADER *Header;\r
401\r
402 //\r
403 // Get IfType and HwAddressSize from SNP mode data.\r
404 //\r
405 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);\r
406\r
407 Seed->Size = sizeof (EFI_DHCP4_PACKET);\r
408 Seed->Length = sizeof (Seed->Dhcp4);\r
409 Header = &Seed->Dhcp4.Header;\r
410 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));\r
411 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;\r
412 Header->HwType = Mode.IfType;\r
413 Header->HwAddrLen = (UINT8) Mode.HwAddressSize;\r
414 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);\r
415\r
416 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;\r
417 Seed->Dhcp4.Option[0] = PXEBC_DHCP4_TAG_EOP;\r
418}\r
419\r
420\r
421/**\r
422 Cache the DHCPv4 packet.\r
423\r
424 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.\r
425 @param[in] Src Pointer to the DHCPv4 packet to be cached.\r
426\r
427**/\r
428VOID\r
429PxeBcCacheDhcp4Packet (\r
430 IN EFI_DHCP4_PACKET *Dst,\r
431 IN EFI_DHCP4_PACKET *Src\r
432 )\r
433{\r
434 ASSERT (Dst->Size >= Src->Length);\r
435\r
436 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
437 Dst->Length = Src->Length;\r
438}\r
439\r
440\r
441/**\r
442 Parse the cached DHCPv4 packet, including all the options.\r
443\r
444 @param[in] Cache4 Pointer to cached DHCPv4 packet.\r
445\r
446 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.\r
447 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.\r
448\r
449**/\r
450EFI_STATUS\r
451PxeBcParseDhcp4Packet (\r
452 IN PXEBC_DHCP4_PACKET_CACHE *Cache4\r
453 )\r
454{\r
455 EFI_DHCP4_PACKET *Offer;\r
456 EFI_DHCP4_PACKET_OPTION **Options;\r
457 EFI_DHCP4_PACKET_OPTION *Option;\r
458 PXEBC_OFFER_TYPE OfferType;\r
459 UINTN Index;\r
460 BOOLEAN IsProxyOffer;\r
461 BOOLEAN IsPxeOffer;\r
462 UINT8 *Ptr8;\r
463\r
464 IsProxyOffer = FALSE;\r
465 IsPxeOffer = FALSE;\r
466\r
467 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));\r
468 ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));\r
469\r
470 Offer = &Cache4->Packet.Offer;\r
471 Options = Cache4->OptList;\r
472\r
473 //\r
474 // Parse DHCPv4 options in this offer, and store the pointers.\r
8cb92971 475 // First, try to parse DHCPv4 options from the DHCP optional parameters field.\r
a3bcde70
HT
476 //\r
477 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
478 Options[Index] = PxeBcParseDhcp4Options (\r
479 Offer->Dhcp4.Option,\r
480 GET_OPTION_BUFFER_LEN (Offer),\r
481 mInterestedDhcp4Tags[Index]\r
482 );\r
483 }\r
8cb92971
FS
484 //\r
485 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132. \r
486 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
487 //\r
488 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];\r
489 if (Option != NULL) {\r
490 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {\r
491 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
492 if (Options[Index] == NULL) {\r
493 Options[Index] = PxeBcParseDhcp4Options (\r
494 (UINT8 *) Offer->Dhcp4.Header.BootFileName,\r
495 sizeof (Offer->Dhcp4.Header.BootFileName),\r
496 mInterestedDhcp4Tags[Index]\r
497 );\r
498 }\r
499 }\r
500 }\r
501 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
502 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
503 if (Options[Index] == NULL) {\r
504 Options[Index] = PxeBcParseDhcp4Options (\r
505 (UINT8 *) Offer->Dhcp4.Header.ServerName,\r
506 sizeof (Offer->Dhcp4.Header.ServerName),\r
507 mInterestedDhcp4Tags[Index]\r
508 );\r
509 }\r
510 }\r
511 }\r
512 }\r
a3bcde70
HT
513\r
514 //\r
ae97201c 515 // The offer with zero "yiaddr" is a proxy offer.\r
a3bcde70
HT
516 //\r
517 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {\r
518 IsProxyOffer = TRUE;\r
519 }\r
520\r
521 //\r
522 // The offer with "PXEClient" is a PXE offer.\r
523 //\r
524 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];\r
525 if ((Option != NULL) && (Option->Length >= 9) &&\r
526 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
527 IsPxeOffer = TRUE;\r
528 }\r
529\r
530 //\r
531 // Parse PXE vendor options in this offer, and store the contents/pointers.\r
532 //\r
533 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];\r
534 if (IsPxeOffer && Option != NULL) {\r
535 PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);\r
536 }\r
537\r
538 //\r
8cb92971
FS
539 // Parse PXE boot file name:\r
540 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
541 // Otherwise, read from boot file field in DHCP header.\r
a3bcde70 542 //\r
8cb92971 543 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
a3bcde70
HT
544 //\r
545 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
546 // terminated string. So force to append null terminated character at the end of string.\r
547 //\r
8cb92971
FS
548 Ptr8 = (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
549 Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
550 if (*(Ptr8 - 1) != '\0') {\r
551 *Ptr8 = '\0';\r
a3bcde70 552 }\r
8cb92971 553 } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
a3bcde70
HT
554 //\r
555 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.\r
75dce340 556 // Do not count dhcp option header here, or else will destroy the serverhostname.\r
a3bcde70
HT
557 //\r
558 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)\r
559 (&Offer->Dhcp4.Header.BootFileName[0] -\r
560 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
561\r
562 }\r
563\r
564 //\r
565 // Determine offer type of the DHCPv4 packet.\r
566 //\r
567 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];\r
568 if (Option == NULL || Option->Data[0] == 0) {\r
569 //\r
570 // It's a Bootp offer.\r
571 //\r
572 OfferType = PxeOfferTypeBootp;\r
573\r
574 Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];\r
575 if (Option == NULL) {\r
576 //\r
577 // If the Bootp offer without bootfilename, discard it.\r
578 //\r
579 return EFI_DEVICE_ERROR;\r
580 }\r
581 } else {\r
582\r
583 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {\r
584 //\r
585 // It's a PXE10 offer with PXEClient and discover vendor option.\r
586 //\r
587 OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;\r
588 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {\r
589 //\r
590 // It's a WFM11a offer with PXEClient and mtftp vendor option.\r
591 // But multi-cast download is not supported currently, so discard it.\r
592 //\r
593 return EFI_DEVICE_ERROR;\r
594 } else if (IsPxeOffer) {\r
595 //\r
596 // It's a BINL offer only with PXEClient.\r
597 //\r
598 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;\r
599 } else {\r
600 //\r
601 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.\r
602 //\r
603 OfferType = PxeOfferTypeDhcpOnly;\r
604 }\r
605 }\r
606\r
607 Cache4->OfferType = OfferType;\r
608\r
609 return EFI_SUCCESS;\r
610}\r
611\r
612\r
613/**\r
614 Cache the DHCPv4 ack packet, and parse it on demand.\r
615\r
616 @param[in] Private Pointer to PxeBc private data.\r
617 @param[in] Ack Pointer to the DHCPv4 ack packet.\r
618 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.\r
619\r
620**/\r
621VOID\r
622PxeBcCopyDhcp4Ack (\r
623 IN PXEBC_PRIVATE_DATA *Private,\r
624 IN EFI_DHCP4_PACKET *Ack,\r
625 IN BOOLEAN Verified\r
626 )\r
627{\r
628 EFI_PXE_BASE_CODE_MODE *Mode;\r
629\r
630 Mode = Private->PxeBc.Mode;\r
631\r
632 PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);\r
633\r
634 if (Verified) {\r
635 //\r
636 // Parse the ack packet and store it into mode data if needed.\r
637 //\r
638 PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);\r
639 CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);\r
640 Mode->DhcpAckReceived = TRUE;\r
641 }\r
642}\r
643\r
644\r
645/**\r
646 Cache the DHCPv4 proxy offer packet according to the received order.\r
647\r
648 @param[in] Private Pointer to PxeBc private data.\r
649 @param[in] OfferIndex The received order of offer packets.\r
650\r
651**/\r
652VOID\r
653PxeBcCopyProxyOffer (\r
654 IN PXEBC_PRIVATE_DATA *Private,\r
655 IN UINT32 OfferIndex\r
656 )\r
657{\r
658 EFI_PXE_BASE_CODE_MODE *Mode;\r
659 EFI_DHCP4_PACKET *Offer;\r
660\r
661 ASSERT (OfferIndex < Private->OfferNum);\r
662 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);\r
663\r
664 Mode = Private->PxeBc.Mode;\r
665 Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;\r
666\r
667 //\r
668 // Cache the proxy offer packet and parse it.\r
669 //\r
670 PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);\r
671 PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);\r
672\r
673 //\r
674 // Store this packet into mode data.\r
675 //\r
676 CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);\r
677 Mode->ProxyOfferReceived = TRUE;\r
678}\r
679\r
680\r
681/**\r
682 Retry to request bootfile name by the BINL offer.\r
683\r
684 @param[in] Private Pointer to PxeBc private data.\r
685 @param[in] Index The received order of offer packets.\r
686\r
687 @retval EFI_SUCCESS Successfully retried to request bootfile name.\r
688 @retval EFI_DEVICE_ERROR Failed to retry bootfile name.\r
689\r
690**/\r
691EFI_STATUS\r
692PxeBcRetryBinlOffer (\r
693 IN PXEBC_PRIVATE_DATA *Private,\r
694 IN UINT32 Index\r
695 )\r
696{\r
697 EFI_DHCP4_PACKET *Offer;\r
698 EFI_IP_ADDRESS ServerIp;\r
699 EFI_STATUS Status;\r
700 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
701 EFI_DHCP4_PACKET *Reply;\r
702\r
703 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
704 ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||\r
705 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl);\r
706\r
707 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;\r
708\r
709 //\r
710 // Prefer to siaddr in header as next server address. If it's zero, then use option 54.\r
711 //\r
712 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {\r
713 CopyMem (\r
714 &ServerIp.Addr[0],\r
715 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
716 sizeof (EFI_IPv4_ADDRESS)\r
717 );\r
718 } else {\r
719 CopyMem (\r
720 &ServerIp.Addr[0],\r
721 &Offer->Dhcp4.Header.ServerAddr,\r
722 sizeof (EFI_IPv4_ADDRESS)\r
723 );\r
724 }\r
725\r
726 Private->IsDoDiscover = FALSE;\r
727 Cache4 = &Private->ProxyOffer.Dhcp4;\r
728 Reply = &Cache4->Packet.Offer;\r
729\r
730 //\r
731 // Send another request packet for bootfile name.\r
732 //\r
733 Status = PxeBcDhcp4Discover (\r
734 Private,\r
735 0,\r
736 NULL,\r
737 FALSE,\r
738 &ServerIp,\r
739 0,\r
740 NULL\r
741 );\r
742 if (EFI_ERROR (Status)) {\r
743 return Status;\r
744 }\r
745\r
746 //\r
747 // Parse the reply for the last request packet.\r
748 //\r
749 Status = PxeBcParseDhcp4Packet (Cache4);\r
750 if (EFI_ERROR (Status)) {\r
751 return Status;\r
752 }\r
753\r
754 if (Cache4->OfferType != PxeOfferTypeProxyPxe10 &&\r
755 Cache4->OfferType != PxeOfferTypeProxyWfm11a &&\r
756 Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
757 //\r
758 // This BINL ack doesn't have discovery option set or multicast option set\r
759 // or bootfile name specified.\r
760 //\r
761 return EFI_DEVICE_ERROR;\r
762 }\r
763\r
764 //\r
765 // Store the reply into mode data.\r
766 //\r
767 Private->PxeBc.Mode->ProxyOfferReceived = TRUE;\r
768 CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);\r
769\r
770 return EFI_SUCCESS;\r
771}\r
772\r
773\r
774/**\r
775 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.\r
776\r
777 @param[in] Private Pointer to PxeBc private data.\r
778 @param[in] RcvdOffer Pointer to the received offer packet.\r
779\r
780**/\r
781VOID\r
782PxeBcCacheDhcp4Offer (\r
783 IN PXEBC_PRIVATE_DATA *Private,\r
784 IN EFI_DHCP4_PACKET *RcvdOffer\r
785 )\r
786{\r
787 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
788 EFI_DHCP4_PACKET *Offer;\r
789 PXEBC_OFFER_TYPE OfferType;\r
790\r
791 ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);\r
792 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;\r
793 Offer = &Cache4->Packet.Offer;\r
794\r
795 //\r
796 // Cache the content of DHCPv4 packet firstly.\r
797 //\r
798 PxeBcCacheDhcp4Packet (Offer, RcvdOffer);\r
799\r
800 //\r
801 // Validate the DHCPv4 packet, and parse the options and offer type.\r
802 //\r
803 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {\r
804 return;\r
805 }\r
806\r
807 //\r
808 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
809 //\r
810 OfferType = Cache4->OfferType;\r
811 ASSERT (OfferType < PxeOfferTypeMax);\r
812\r
813 if (OfferType == PxeOfferTypeBootp) {\r
814 //\r
815 // It's a Bootp offer, only cache the first one, and discard the others.\r
816 //\r
817 if (Private->OfferCount[OfferType] == 0) {\r
818 Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
819 Private->OfferCount[OfferType] = 1;\r
820 } else {\r
821 return;\r
822 }\r
823 } else {\r
824 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);\r
825 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
826 //\r
827 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.\r
828 //\r
829 Private->IsProxyRecved = TRUE;\r
830\r
831 if (OfferType == PxeOfferTypeProxyBinl) {\r
832 //\r
833 // Cache all proxy BINL offers.\r
834 //\r
835 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
836 Private->OfferCount[OfferType]++;\r
837 } else if (Private->OfferCount[OfferType] > 0) {\r
838 //\r
839 // Only cache the first PXE10/WFM11a offer, and discard the others.\r
840 //\r
841 Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
842 Private->OfferCount[OfferType] = 1;\r
843 } else {\r
844 return ;\r
845 }\r
846 } else {\r
847 //\r
848 // It's a DHCPv4 offer with yiaddr, and cache them all.\r
849 //\r
850 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
851 Private->OfferCount[OfferType]++;\r
852 }\r
853 }\r
854\r
855 Private->OfferNum++;\r
856}\r
857\r
858\r
859/**\r
860 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.\r
861\r
862 @param[in] Private Pointer to PxeBc private data.\r
863\r
864**/\r
865VOID\r
866PxeBcSelectDhcp4Offer (\r
867 IN PXEBC_PRIVATE_DATA *Private\r
868 )\r
869{\r
870 UINT32 Index;\r
871 UINT32 OfferIndex;\r
872 EFI_DHCP4_PACKET *Offer;\r
873\r
874 Private->SelectIndex = 0;\r
875\r
876 if (Private->IsOfferSorted) {\r
877 //\r
878 // Select offer by default policy.\r
879 //\r
880 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {\r
881 //\r
882 // 1. DhcpPxe10 offer\r
883 //\r
884 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;\r
885\r
886 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {\r
887 //\r
888 // 2. DhcpWfm11a offer\r
889 //\r
890 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;\r
891\r
892 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
893 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {\r
894 //\r
895 // 3. DhcpOnly offer and ProxyPxe10 offer.\r
896 //\r
897 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
898 Private->SelectProxyType = PxeOfferTypeProxyPxe10;\r
899\r
900 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
901 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {\r
902 //\r
903 // 4. DhcpOnly offer and ProxyWfm11a offer.\r
904 //\r
905 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
906 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;\r
907\r
908 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {\r
909 //\r
910 // 5. DhcpBinl offer.\r
911 //\r
912 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;\r
913\r
914 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
915 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {\r
916 //\r
917 // 6. DhcpOnly offer and ProxyBinl offer.\r
918 //\r
919 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
920 Private->SelectProxyType = PxeOfferTypeProxyBinl;\r
921\r
922 } else {\r
923 //\r
924 // 7. DhcpOnly offer with bootfilename.\r
925 //\r
926 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {\r
927 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];\r
928 if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
929 Private->SelectIndex = OfferIndex + 1;\r
930 break;\r
931 }\r
932 }\r
933 //\r
934 // 8. Bootp offer with bootfilename.\r
935 //\r
936 OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];\r
937 if (Private->SelectIndex == 0 &&\r
938 Private->OfferCount[PxeOfferTypeBootp] > 0 &&\r
939 Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
940 Private->SelectIndex = OfferIndex + 1;\r
941 }\r
942 }\r
943 } else {\r
944 //\r
945 // Select offer by received order.\r
946 //\r
947 for (Index = 0; Index < Private->OfferNum; Index++) {\r
948\r
949 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;\r
950\r
951 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
952 //\r
953 // Skip proxy offers\r
954 //\r
955 continue;\r
956 }\r
957\r
958 if (!Private->IsProxyRecved &&\r
959 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly &&\r
960 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
961 //\r
962 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.\r
963 //\r
964 continue;\r
965 }\r
966\r
967 //\r
968 // Record the index of the select offer.\r
969 //\r
970 Private->SelectIndex = Index + 1;\r
971 break;\r
972 }\r
973 }\r
974}\r
975\r
976\r
977/**\r
978 Handle the DHCPv4 offer packet.\r
979\r
980 @param[in] Private Pointer to PxeBc private data.\r
981\r
982 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.\r
983 @retval EFI_NO_RESPONSE No response to the following request packet.\r
4496ff75 984 @retval EFI_NOT_FOUND No boot filename received.\r
a3bcde70
HT
985\r
986**/\r
987EFI_STATUS\r
988PxeBcHandleDhcp4Offer (\r
989 IN PXEBC_PRIVATE_DATA *Private\r
990 )\r
991{\r
992 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
993 EFI_DHCP4_PACKET_OPTION **Options;\r
994 UINT32 Index;\r
995 EFI_DHCP4_PACKET *Offer;\r
996 PXEBC_OFFER_TYPE OfferType;\r
997 UINT32 ProxyIndex;\r
998 UINT32 SelectIndex;\r
999 EFI_STATUS Status;\r
1000 EFI_PXE_BASE_CODE_MODE *Mode;\r
1001 EFI_DHCP4_PACKET *Ack;\r
1002\r
1003 ASSERT (Private->SelectIndex > 0);\r
1004 SelectIndex = (UINT32) (Private->SelectIndex - 1);\r
1005 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);\r
1006 Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4;\r
1007 Options = Cache4->OptList;\r
1008 Status = EFI_SUCCESS;\r
1009\r
1010 if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {\r
1011 //\r
1012 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
1013 //\r
1014 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {\r
1015 Status = EFI_NO_RESPONSE;\r
1016 }\r
1017 } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {\r
1018\r
1019 if (Private->IsProxyRecved) {\r
1020 //\r
1021 // DhcpOnly offer is selected, so need try to request bootfile name.\r
1022 //\r
1023 ProxyIndex = 0;\r
1024 if (Private->IsOfferSorted) {\r
1025 //\r
1026 // The proxy offer should be determined if select by default policy.\r
1027 // IsOfferSorted means all offers are labeled by OfferIndex.\r
1028 //\r
1029 ASSERT (Private->SelectProxyType < PxeOfferTypeMax);\r
1030 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);\r
1031\r
1032 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {\r
1033 //\r
1034 // Try all the cached ProxyBinl offer one by one to request bootfile name.\r
1035 //\r
1036 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {\r
1037 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
1038 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];\r
1039 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {\r
1040 break;\r
1041 }\r
1042 }\r
1043 if (Index == Private->OfferCount[Private->SelectProxyType]) {\r
1044 Status = EFI_NO_RESPONSE;\r
1045 }\r
1046 } else {\r
1047 //\r
1048 // For other proxy offers, only one is buffered.\r
1049 //\r
1050 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
1051 }\r
1052 } else {\r
1053 //\r
1054 // The proxy offer should not be determined if select by received order.\r
1055 //\r
1056 Status = EFI_NO_RESPONSE;\r
1057\r
1058 for (Index = 0; Index < Private->OfferNum; Index++) {\r
1059 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
1060 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;\r
1061 OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;\r
1062 if (!IS_PROXY_DHCP_OFFER (Offer)) {\r
1063 //\r
1064 // Skip non proxy DHCPv4 offers.\r
1065 //\r
1066 continue;\r
1067 }\r
1068\r
1069 if (OfferType == PxeOfferTypeProxyBinl) {\r
1070 //\r
1071 // Try all the cached ProxyBinl offer one by one to request bootfile name.\r
1072 //\r
1073 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {\r
1074 continue;\r
1075 }\r
1076 }\r
1077\r
1078 Private->SelectProxyType = OfferType;\r
1079 ProxyIndex = Index;\r
1080 Status = EFI_SUCCESS;\r
1081 break;\r
1082 }\r
1083 }\r
1084\r
1085 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {\r
1086 //\r
1087 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.\r
1088 //\r
1089 PxeBcCopyProxyOffer (Private, ProxyIndex);\r
1090 }\r
1091 } else {\r
1092 //\r
1093 // Othewise, the bootfile name must be included in DhcpOnly offer.\r
1094 //\r
4496ff75 1095 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
1096 Status = EFI_NOT_FOUND;\r
1097 }\r
a3bcde70
HT
1098 }\r
1099 }\r
1100\r
1101 if (!EFI_ERROR (Status)) {\r
1102 //\r
1103 // All PXE boot information is ready by now.\r
1104 //\r
1105 Mode = Private->PxeBc.Mode;\r
1106 Offer = &Cache4->Packet.Offer;\r
1107 Ack = &Private->DhcpAck.Dhcp4.Packet.Ack;\r
1108 if (Cache4->OfferType == PxeOfferTypeBootp) {\r
1109 //\r
1110 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply\r
1111 // should be taken as ack.\r
1112 //\r
1113 Ack = Offer;\r
1114 }\r
1115\r
1116 PxeBcCopyDhcp4Ack (Private, Ack, TRUE);\r
1117 Mode->DhcpDiscoverValid = TRUE;\r
1118 }\r
1119\r
1120 return Status;\r
1121}\r
1122\r
1123\r
1124/**\r
1125 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
1126 to intercept events that occurred in the configuration process.\r
1127\r
1128 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
1129 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
1130 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
1131 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
1132 state transition.\r
1133 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
1134 @param[out] NewPacket The packet that is used to replace the above Packet.\r
1135\r
1136 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
1137 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
1138 driver will continue to wait for more DHCPOFFER packets until the\r
1139 retry timeout expires.\r
1140 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
1141 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
1142\r
1143**/\r
1144EFI_STATUS\r
1145EFIAPI\r
1146PxeBcDhcp4CallBack (\r
1147 IN EFI_DHCP4_PROTOCOL *This,\r
1148 IN VOID *Context,\r
1149 IN EFI_DHCP4_STATE CurrentState,\r
1150 IN EFI_DHCP4_EVENT Dhcp4Event,\r
1151 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
1152 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
1153 )\r
1154{\r
1155 PXEBC_PRIVATE_DATA *Private;\r
1156 EFI_PXE_BASE_CODE_MODE *Mode;\r
1157 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
1158 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
1159 UINT16 Value;\r
1160 EFI_STATUS Status;\r
1161 BOOLEAN Received;\r
1162\r
1163 if ((Dhcp4Event != Dhcp4RcvdOffer) &&\r
1164 (Dhcp4Event != Dhcp4SelectOffer) &&\r
1165 (Dhcp4Event != Dhcp4SendDiscover) &&\r
1166 (Dhcp4Event != Dhcp4RcvdAck)) {\r
1167 return EFI_SUCCESS;\r
1168 }\r
1169\r
1170 Private = (PXEBC_PRIVATE_DATA *) Context;\r
1171 Mode = Private->PxeBc.Mode;\r
1172 Callback = Private->PxeBcCallback;\r
1173\r
1174 //\r
1175 // Override the Maximum DHCP Message Size.\r
1176 //\r
1177 MaxMsgSize = PxeBcParseDhcp4Options (\r
1178 Packet->Dhcp4.Option,\r
1179 GET_OPTION_BUFFER_LEN (Packet),\r
1180 PXEBC_DHCP4_TAG_MAXMSG\r
1181 );\r
1182 if (MaxMsgSize != NULL) {\r
1183 Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);\r
1184 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
1185 }\r
1186\r
1187 //\r
1188 // Callback to user if any packets sent or received.\r
1189 //\r
1190 if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) {\r
1191 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);\r
1192 Status = Callback->Callback (\r
1193 Callback,\r
1194 Private->Function,\r
1195 Received,\r
1196 Packet->Length,\r
1197 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4\r
1198 );\r
1199 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
1200 return EFI_ABORTED;\r
1201 }\r
1202 }\r
1203\r
1204 Status = EFI_SUCCESS;\r
1205\r
1206 switch (Dhcp4Event) {\r
1207\r
1208 case Dhcp4SendDiscover:\r
1209 //\r
1210 // Cache the DHCPv4 discover packet to mode data directly.\r
1211 // It need to check SendGuid as well as Dhcp4SendRequest.\r
1212 //\r
1213 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);\r
1214\r
1215 case Dhcp4SendRequest:\r
1216 if (Mode->SendGUID) {\r
1217 //\r
1218 // Send the system Guid instead of the MAC address as the hardware address if required.\r
1219 //\r
19ddbb25 1220 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) {\r
a3bcde70
HT
1221 //\r
1222 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
1223 //\r
1224 ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));\r
1225 }\r
1226 Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);\r
1227 }\r
1228 break;\r
1229\r
1230 case Dhcp4RcvdOffer:\r
1231 Status = EFI_NOT_READY;\r
1232 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {\r
1233 //\r
1234 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
1235 // the OfferIndex and OfferCount.\r
1236 //\r
1237 PxeBcCacheDhcp4Offer (Private, Packet);\r
1238 }\r
1239 break;\r
1240\r
1241 case Dhcp4SelectOffer:\r
1242 //\r
1243 // Select offer by the default policy or by order, and record the SelectIndex\r
1244 // and SelectProxyType.\r
1245 //\r
1246 PxeBcSelectDhcp4Offer (Private);\r
1247\r
1248 if (Private->SelectIndex == 0) {\r
1249 Status = EFI_ABORTED;\r
1250 } else {\r
1251 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
1252 }\r
1253 break;\r
1254\r
1255 case Dhcp4RcvdAck:\r
1256 //\r
1257 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data\r
1258 // without verification.\r
1259 //\r
1260 ASSERT (Private->SelectIndex != 0);\r
1261\r
1262 PxeBcCopyDhcp4Ack (Private, Packet, FALSE);\r
1263 break;\r
1264\r
1265 default:\r
1266 break;\r
1267 }\r
1268\r
1269 return Status;\r
1270}\r
1271\r
1272\r
1273/**\r
1274 Build and send out the request packet for the bootfile, and parse the reply.\r
1275\r
1276 @param[in] Private Pointer to PxeBc private data.\r
1277 @param[in] Type PxeBc option boot item type.\r
1278 @param[in] Layer Pointer to option boot item layer.\r
1279 @param[in] UseBis Use BIS or not.\r
1280 @param[in] DestIp Pointer to the server address.\r
1281 @param[in] IpCount The total count of the server address.\r
1282 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.\r
1283\r
1284 @retval EFI_SUCCESS Successfully discovered boot file.\r
1285 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
1286 @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
1287 @retval Others Failed to discover boot file.\r
1288\r
1289**/\r
1290EFI_STATUS\r
1291PxeBcDhcp4Discover (\r
1292 IN PXEBC_PRIVATE_DATA *Private,\r
1293 IN UINT16 Type,\r
1294 IN UINT16 *Layer,\r
1295 IN BOOLEAN UseBis,\r
1296 IN EFI_IP_ADDRESS *DestIp,\r
1297 IN UINT16 IpCount,\r
1298 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList\r
1299 )\r
1300{\r
1301 EFI_PXE_BASE_CODE_UDP_PORT Sport;\r
1302 EFI_PXE_BASE_CODE_MODE *Mode;\r
1303 EFI_DHCP4_PROTOCOL *Dhcp4;\r
1304 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;\r
1305 BOOLEAN IsBCast;\r
1306 EFI_STATUS Status;\r
1307 UINT16 RepIndex;\r
1308 UINT16 SrvIndex;\r
1309 UINT16 TryIndex;\r
1310 EFI_DHCP4_LISTEN_POINT ListenPoint;\r
1311 EFI_DHCP4_PACKET *Response;\r
1312 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];\r
1313 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];\r
1314 UINT32 OptCount;\r
1315 EFI_DHCP4_PACKET_OPTION *PxeOpt;\r
1316 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;\r
1317 UINT8 VendorOptLen;\r
1318 UINT32 Xid;\r
1319\r
1320 Mode = Private->PxeBc.Mode;\r
1321 Dhcp4 = Private->Dhcp4;\r
1322 Status = EFI_SUCCESS;\r
1323\r
1324 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
1325\r
1326 //\r
1327 // Use broadcast if destination address not specified.\r
1328 //\r
1329 if (DestIp == NULL) {\r
1330 Sport = PXEBC_DHCP4_S_PORT;\r
1331 IsBCast = TRUE;\r
1332 } else {\r
1333 Sport = PXEBC_BS_DISCOVER_PORT;\r
1334 IsBCast = FALSE;\r
1335 }\r
1336\r
1337 if (!UseBis && Layer != NULL) {\r
1338 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1339 }\r
1340\r
1341 //\r
1342 // Build all the options for the request packet.\r
1343 //\r
1344 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);\r
1345\r
1346 if (Private->IsDoDiscover) {\r
1347 //\r
1348 // Add vendor option of PXE_BOOT_ITEM\r
1349 //\r
1350 VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);\r
1351 OptList[OptCount] = AllocateZeroPool (VendorOptLen);\r
1352 if (OptList[OptCount] == NULL) {\r
1353 return EFI_OUT_OF_RESOURCES;\r
1354 }\r
1355\r
1356 OptList[OptCount]->OpCode = PXEBC_DHCP4_TAG_VENDOR;\r
1357 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);\r
1358 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;\r
1359 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;\r
1360 PxeOpt->Length = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);\r
1361 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;\r
1362 PxeBootItem->Type = HTONS (Type);\r
1363 PxeOpt->Data[PxeOpt->Length] = PXEBC_DHCP4_TAG_EOP;\r
1364\r
1365 if (Layer != NULL) {\r
1366 PxeBootItem->Layer = HTONS (*Layer);\r
1367 }\r
1368\r
1369 OptCount++;\r
1370 }\r
1371\r
1372 //\r
1373 // Build the request packet with seed packet and option list.\r
1374 //\r
1375 Status = Dhcp4->Build (\r
1376 Dhcp4,\r
1377 &Private->SeedPacket,\r
1378 0,\r
1379 NULL,\r
1380 OptCount,\r
1381 OptList,\r
1382 &Token.Packet\r
1383 );\r
1384 //\r
1385 // Free the vendor option of PXE_BOOT_ITEM.\r
1386 //\r
1387 if (Private->IsDoDiscover) {\r
1388 FreePool (OptList[OptCount - 1]);\r
1389 }\r
1390\r
1391 if (EFI_ERROR (Status)) {\r
1392 return Status;\r
1393 }\r
1394\r
1395 if (Mode->SendGUID) {\r
19ddbb25 1396 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) {\r
a3bcde70
HT
1397 //\r
1398 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
1399 //\r
1400 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));\r
1401 }\r
1402 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);\r
1403 }\r
1404\r
1405 //\r
1406 // Set fields of the token for the request packet.\r
1407 //\r
1408 Xid = NET_RANDOM (NetRandomInitSeed ());\r
1409 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid);\r
1410 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0));\r
1411 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
1412\r
1413 Token.RemotePort = Sport;\r
1414\r
1415 if (IsBCast) {\r
1416 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
1417 } else {\r
1418 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
1419 }\r
1420\r
1421 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
1422\r
1423 if (!IsBCast) {\r
1424 Token.ListenPointCount = 1;\r
1425 Token.ListenPoints = &ListenPoint;\r
1426 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;\r
1427 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));\r
1428 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));\r
1429 }\r
1430\r
1431 //\r
1432 // Send out the request packet to discover the bootfile.\r
1433 //\r
1434 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {\r
1435\r
1436 Token.TimeoutValue = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);\r
1437 Token.Packet->Dhcp4.Header.Seconds = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));\r
1438\r
1439 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
1440 if (Token.Status != EFI_TIMEOUT) {\r
1441 break;\r
1442 }\r
1443 }\r
1444\r
1445 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {\r
1446 //\r
1447 // No server response our PXE request\r
1448 //\r
1449 Status = EFI_TIMEOUT;\r
1450 }\r
1451\r
1452 if (!EFI_ERROR (Status)) {\r
1453\r
1454 RepIndex = 0;\r
1455 SrvIndex = 0;\r
1456 Response = Token.ResponseList;\r
1457 //\r
1458 // Find the right PXE Reply according to server address.\r
1459 //\r
1460 while (RepIndex < Token.ResponseCount) {\r
1461\r
1462 while (SrvIndex < IpCount) {\r
1463 if (SrvList[SrvIndex].AcceptAnyResponse) {\r
1464 break;\r
1465 }\r
1466 if ((SrvList[SrvIndex].Type == Type) &&\r
9063c328 1467 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) {\r
a3bcde70
HT
1468 break;\r
1469 }\r
1470 SrvIndex++;\r
1471 }\r
1472\r
1473 if ((IpCount != SrvIndex) || (IpCount == 0)) {\r
1474 break;\r
1475 }\r
1476\r
1477 SrvIndex = 0;\r
1478 RepIndex++;\r
1479\r
1480 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1481 }\r
1482\r
1483 if (RepIndex < Token.ResponseCount) {\r
1484 //\r
1485 // Cache the right PXE reply packet here, set valid flag later.\r
1486 // Especially for PXE discover packet, store it into mode data here.\r
1487 //\r
1488 if (Private->IsDoDiscover) {\r
1489 PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);\r
1490 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);\r
1491 } else {\r
1492 PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);\r
1493 }\r
1494 } else {\r
1495 //\r
1496 // Not found the right PXE reply packet.\r
1497 //\r
1498 Status = EFI_NOT_FOUND;\r
1499 }\r
1500 if (Token.ResponseList != NULL) {\r
1501 FreePool (Token.ResponseList);\r
1502 }\r
1503 }\r
1504\r
1505 FreePool (Token.Packet);\r
1506 return Status;\r
1507}\r
1508\r
1509\r
1510/**\r
1511 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.\r
1512\r
1513 @param[in] Private Pointer to PxeBc private data.\r
1514 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL\r
1515\r
1516 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
1517 @retval Others Failed to finish the D.O.R.A process.\r
1518\r
1519**/\r
1520EFI_STATUS\r
1521PxeBcDhcp4Dora (\r
1522 IN PXEBC_PRIVATE_DATA *Private,\r
1523 IN EFI_DHCP4_PROTOCOL *Dhcp4\r
1524 )\r
1525{\r
1526 EFI_PXE_BASE_CODE_MODE *PxeMode;\r
1527 EFI_DHCP4_CONFIG_DATA Config;\r
1528 EFI_DHCP4_MODE_DATA Mode;\r
1529 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];\r
1530 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];\r
1531 UINT32 OptCount;\r
1532 EFI_STATUS Status;\r
1533\r
1534 ASSERT (Dhcp4 != NULL);\r
1535\r
1536 Status = EFI_SUCCESS;\r
1537 PxeMode = Private->PxeBc.Mode;\r
1538\r
1539 //\r
1540 // Build option list for the request packet.\r
1541 //\r
1542 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);\r
1543 ASSERT (OptCount> 0);\r
1544\r
1545 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));\r
1546 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
1547\r
1548 Config.OptionCount = OptCount;\r
1549 Config.OptionList = OptList;\r
1550 Config.Dhcp4Callback = PxeBcDhcp4CallBack;\r
1551 Config.CallbackContext = Private;\r
1552 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;\r
1553 Config.DiscoverTimeout = mPxeDhcpTimeout;\r
1554\r
1555 //\r
1556 // Configure the DHCPv4 instance for PXE boot.\r
1557 //\r
1558 Status = Dhcp4->Configure (Dhcp4, &Config);\r
1559 if (EFI_ERROR (Status)) {\r
1560 goto ON_EXIT;\r
1561 }\r
1562\r
1563 //\r
1564 // Initialize the record fields for DHCPv4 offer in private data.\r
1565 //\r
1566 Private->IsProxyRecved = FALSE;\r
1567 Private->OfferNum = 0;\r
1568 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
1569 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
1570\r
1571 //\r
61047329
ZL
1572 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. This may \r
1573 // have already been done, thus do not leave in error if the return\r
1574 // code is EFI_ALREADY_STARTED.\r
a3bcde70
HT
1575 //\r
1576 Status = Dhcp4->Start (Dhcp4, NULL);\r
61047329 1577 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
a3bcde70
HT
1578 if (Status == EFI_ICMP_ERROR) {\r
1579 PxeMode->IcmpErrorReceived = TRUE;\r
1580 }\r
1581 goto ON_EXIT;\r
1582 }\r
1583\r
1584 //\r
1585 // Get the acquired IPv4 address and store them.\r
1586 //\r
1587 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
1588 if (EFI_ERROR (Status)) {\r
1589 goto ON_EXIT;\r
1590 }\r
1591\r
1592 ASSERT (Mode.State == Dhcp4Bound);\r
1593\r
1594 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
1595 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
1596 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
1597 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
1598 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
1599\r
0e7f6f50 1600 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);\r
a3bcde70
HT
1601 if (EFI_ERROR (Status)) {\r
1602 goto ON_EXIT;\r
1603 }\r
1604\r
1605 //\r
1606 // Check the selected offer whether BINL retry is needed.\r
1607 //\r
1608 Status = PxeBcHandleDhcp4Offer (Private);\r
1609\r
1610 AsciiPrint ("\n Station IP address is ");\r
1611\r
1612 PxeBcShowIp4Addr (&Private->StationIp.v4);\r
9063c328 1613 AsciiPrint ("\n");\r
a3bcde70
HT
1614\r
1615ON_EXIT:\r
1616 if (EFI_ERROR (Status)) {\r
1617 Dhcp4->Stop (Dhcp4);\r
1618 Dhcp4->Configure (Dhcp4, NULL);\r
1619 } else {\r
1620 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
1621 Dhcp4->Configure (Dhcp4, &Config);\r
1622 Private->IsAddressOk = TRUE;\r
1623 }\r
1624\r
1625 return Status;\r
1626}\r