NetworkPkg: Add warning message for PXE if failed to read system GUID from SMBIOS.
[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
6a4eed9b 4 Copyright (c) 2009 - 2018, 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
142c00c3
ZL
22 DHCP4_TAG_BOOTFILE_LEN,\r
23 DHCP4_TAG_VENDOR,\r
24 DHCP4_TAG_OVERLOAD,\r
25 DHCP4_TAG_MSG_TYPE,\r
26 DHCP4_TAG_SERVER_ID,\r
27 DHCP4_TAG_VENDOR_CLASS_ID,\r
28 DHCP4_TAG_BOOTFILE\r
a3bcde70
HT
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
142c00c3 61 while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {\r
a3bcde70
HT
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
142c00c3 73 if (Option->OpCode == DHCP4_TAG_PAD) {\r
a3bcde70
HT
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
142c00c3 111 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != DHCP4_TAG_EOP)) {\r
a3bcde70
HT
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
142c00c3 204 if (PxeOption->OpCode == DHCP4_TAG_PAD) {\r
a3bcde70
HT
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
142c00c3 246 OptList[Index]->OpCode = DHCP4_TAG_MSG_TYPE;\r
a3bcde70
HT
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
142c00c3 256 OptList[Index]->OpCode = DHCP4_TAG_MAXMSG;\r
a3bcde70
HT
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
632dcfd6 259 Value = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE);\r
a3bcde70
HT
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
142c00c3 268 OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;\r
a3bcde70
HT
269 OptList[Index]->Length = 35;\r
270 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
142c00c3
ZL
271 OptEnt.Para->ParaList[0] = DHCP4_TAG_NETMASK;\r
272 OptEnt.Para->ParaList[1] = DHCP4_TAG_TIME_OFFSET;\r
273 OptEnt.Para->ParaList[2] = DHCP4_TAG_ROUTER;\r
274 OptEnt.Para->ParaList[3] = DHCP4_TAG_TIME_SERVER;\r
275 OptEnt.Para->ParaList[4] = DHCP4_TAG_NAME_SERVER;\r
276 OptEnt.Para->ParaList[5] = DHCP4_TAG_DNS_SERVER;\r
277 OptEnt.Para->ParaList[6] = DHCP4_TAG_HOSTNAME;\r
278 OptEnt.Para->ParaList[7] = DHCP4_TAG_BOOTFILE_LEN;\r
279 OptEnt.Para->ParaList[8] = DHCP4_TAG_DOMAINNAME;\r
280 OptEnt.Para->ParaList[9] = DHCP4_TAG_ROOTPATH;\r
281 OptEnt.Para->ParaList[10] = DHCP4_TAG_EXTEND_PATH;\r
282 OptEnt.Para->ParaList[11] = DHCP4_TAG_EMTU;\r
283 OptEnt.Para->ParaList[12] = DHCP4_TAG_TTL;\r
284 OptEnt.Para->ParaList[13] = DHCP4_TAG_BROADCAST;\r
285 OptEnt.Para->ParaList[14] = DHCP4_TAG_NIS_DOMAIN;\r
286 OptEnt.Para->ParaList[15] = DHCP4_TAG_NIS_SERVER;\r
287 OptEnt.Para->ParaList[16] = DHCP4_TAG_NTP_SERVER;\r
288 OptEnt.Para->ParaList[17] = DHCP4_TAG_VENDOR;\r
289 OptEnt.Para->ParaList[18] = DHCP4_TAG_REQUEST_IP;\r
290 OptEnt.Para->ParaList[19] = DHCP4_TAG_LEASE;\r
291 OptEnt.Para->ParaList[20] = DHCP4_TAG_SERVER_ID;\r
292 OptEnt.Para->ParaList[21] = DHCP4_TAG_T1;\r
293 OptEnt.Para->ParaList[22] = DHCP4_TAG_T2;\r
294 OptEnt.Para->ParaList[23] = DHCP4_TAG_VENDOR_CLASS_ID;\r
295 OptEnt.Para->ParaList[24] = DHCP4_TAG_TFTP;\r
296 OptEnt.Para->ParaList[25] = DHCP4_TAG_BOOTFILE;\r
297 OptEnt.Para->ParaList[26] = DHCP4_TAG_UUID;\r
a3bcde70
HT
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
142c00c3 312 OptList[Index]->OpCode = DHCP4_TAG_UUID;\r
a3bcde70
HT
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
ccd05ddd 323 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
a3bcde70
HT
324 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
325 }\r
326\r
327 //\r
328 // Append client network device interface option\r
329 //\r
142c00c3 330 OptList[Index]->OpCode = DHCP4_TAG_UNDI;\r
a3bcde70
HT
331 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);\r
332 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
333\r
334 if (Private->Nii != NULL) {\r
335 OptEnt.Undi->Type = Private->Nii->Type;\r
336 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
337 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
338 } else {\r
339 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
340 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
341 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
342 }\r
343\r
344 Index++;\r
345 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
346\r
347 //\r
348 // Append client system architecture option\r
349 //\r
142c00c3 350 OptList[Index]->OpCode = DHCP4_TAG_ARCH;\r
a3bcde70
HT
351 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);\r
352 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
353 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);\r
354 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
355 Index++;\r
356 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
357\r
358 //\r
359 // Append vendor class identify option\r
360 //\r
142c00c3 361 OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;\r
a3bcde70
HT
362 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);\r
363 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
364 CopyMem (\r
365 OptEnt.Clid,\r
366 DEFAULT_CLASS_ID_DATA,\r
367 sizeof (PXEBC_DHCP4_OPTION_CLID)\r
368 );\r
369 PxeBcUintnToAscDecWithFormat (\r
370 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,\r
371 OptEnt.Clid->ArchitectureType,\r
372 sizeof (OptEnt.Clid->ArchitectureType)\r
373 );\r
374\r
375 if (Private->Nii != NULL) {\r
376 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
377 PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
378 PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
379 }\r
380\r
381 Index++;\r
382\r
383 return Index;\r
384}\r
385\r
386\r
387/**\r
388 Create a template DHCPv4 packet as a seed.\r
389\r
390 @param[out] Seed Pointer to the seed packet.\r
391 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.\r
392\r
393**/\r
394VOID\r
395PxeBcSeedDhcp4Packet (\r
396 OUT EFI_DHCP4_PACKET *Seed,\r
397 IN EFI_UDP4_PROTOCOL *Udp4\r
398 )\r
399{\r
400 EFI_SIMPLE_NETWORK_MODE Mode;\r
401 EFI_DHCP4_HEADER *Header;\r
402\r
403 //\r
404 // Get IfType and HwAddressSize from SNP mode data.\r
405 //\r
406 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);\r
407\r
408 Seed->Size = sizeof (EFI_DHCP4_PACKET);\r
409 Seed->Length = sizeof (Seed->Dhcp4);\r
410 Header = &Seed->Dhcp4.Header;\r
411 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));\r
412 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;\r
413 Header->HwType = Mode.IfType;\r
414 Header->HwAddrLen = (UINT8) Mode.HwAddressSize;\r
415 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);\r
416\r
417 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;\r
142c00c3 418 Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;\r
a3bcde70
HT
419}\r
420\r
421\r
422/**\r
423 Cache the DHCPv4 packet.\r
424\r
425 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.\r
426 @param[in] Src Pointer to the DHCPv4 packet to be cached.\r
427\r
a35dc649
FS
428 @retval EFI_SUCCESS Packet is copied.\r
429 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
430\r
a3bcde70 431**/\r
a35dc649 432EFI_STATUS\r
a3bcde70
HT
433PxeBcCacheDhcp4Packet (\r
434 IN EFI_DHCP4_PACKET *Dst,\r
435 IN EFI_DHCP4_PACKET *Src\r
436 )\r
437{\r
a35dc649
FS
438 if (Dst->Size < Src->Length) {\r
439 return EFI_BUFFER_TOO_SMALL;\r
440 }\r
441 \r
a3bcde70
HT
442 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
443 Dst->Length = Src->Length;\r
a35dc649
FS
444\r
445 return EFI_SUCCESS;\r
a3bcde70
HT
446}\r
447\r
448\r
449/**\r
450 Parse the cached DHCPv4 packet, including all the options.\r
451\r
452 @param[in] Cache4 Pointer to cached DHCPv4 packet.\r
453\r
454 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.\r
455 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.\r
456\r
457**/\r
458EFI_STATUS\r
459PxeBcParseDhcp4Packet (\r
460 IN PXEBC_DHCP4_PACKET_CACHE *Cache4\r
461 )\r
462{\r
463 EFI_DHCP4_PACKET *Offer;\r
464 EFI_DHCP4_PACKET_OPTION **Options;\r
465 EFI_DHCP4_PACKET_OPTION *Option;\r
466 PXEBC_OFFER_TYPE OfferType;\r
467 UINTN Index;\r
468 BOOLEAN IsProxyOffer;\r
469 BOOLEAN IsPxeOffer;\r
470 UINT8 *Ptr8;\r
aa437778 471 BOOLEAN FileFieldOverloaded;\r
a3bcde70
HT
472\r
473 IsProxyOffer = FALSE;\r
474 IsPxeOffer = FALSE;\r
aa437778 475 FileFieldOverloaded = FALSE;\r
a3bcde70
HT
476\r
477 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));\r
478 ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));\r
479\r
480 Offer = &Cache4->Packet.Offer;\r
481 Options = Cache4->OptList;\r
482\r
483 //\r
484 // Parse DHCPv4 options in this offer, and store the pointers.\r
8cb92971 485 // First, try to parse DHCPv4 options from the DHCP optional parameters field.\r
a3bcde70
HT
486 //\r
487 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
488 Options[Index] = PxeBcParseDhcp4Options (\r
489 Offer->Dhcp4.Option,\r
490 GET_OPTION_BUFFER_LEN (Offer),\r
491 mInterestedDhcp4Tags[Index]\r
492 );\r
493 }\r
8cb92971
FS
494 //\r
495 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132. \r
496 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
497 //\r
498 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];\r
499 if (Option != NULL) {\r
500 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {\r
aa437778 501 FileFieldOverloaded = TRUE;\r
8cb92971
FS
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.BootFileName,\r
506 sizeof (Offer->Dhcp4.Header.BootFileName),\r
507 mInterestedDhcp4Tags[Index]\r
508 );\r
509 }\r
510 }\r
511 }\r
512 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
513 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
514 if (Options[Index] == NULL) {\r
515 Options[Index] = PxeBcParseDhcp4Options (\r
516 (UINT8 *) Offer->Dhcp4.Header.ServerName,\r
517 sizeof (Offer->Dhcp4.Header.ServerName),\r
518 mInterestedDhcp4Tags[Index]\r
519 );\r
520 }\r
521 }\r
522 }\r
523 }\r
a3bcde70
HT
524\r
525 //\r
ae97201c 526 // The offer with zero "yiaddr" is a proxy offer.\r
a3bcde70
HT
527 //\r
528 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {\r
529 IsProxyOffer = TRUE;\r
530 }\r
531\r
532 //\r
533 // The offer with "PXEClient" is a PXE offer.\r
534 //\r
535 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];\r
536 if ((Option != NULL) && (Option->Length >= 9) &&\r
537 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
538 IsPxeOffer = TRUE;\r
539 }\r
540\r
541 //\r
542 // Parse PXE vendor options in this offer, and store the contents/pointers.\r
543 //\r
544 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];\r
545 if (IsPxeOffer && Option != NULL) {\r
546 PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);\r
547 }\r
548\r
549 //\r
8cb92971
FS
550 // Parse PXE boot file name:\r
551 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
552 // Otherwise, read from boot file field in DHCP header.\r
a3bcde70 553 //\r
8cb92971 554 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
a3bcde70
HT
555 //\r
556 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
557 // terminated string. So force to append null terminated character at the end of string.\r
558 //\r
8cb92971
FS
559 Ptr8 = (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
560 Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
561 if (*(Ptr8 - 1) != '\0') {\r
562 *Ptr8 = '\0';\r
a3bcde70 563 }\r
aa437778 564 } else if (!FileFieldOverloaded && Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
a3bcde70
HT
565 //\r
566 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.\r
75dce340 567 // Do not count dhcp option header here, or else will destroy the serverhostname.\r
a3bcde70
HT
568 //\r
569 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)\r
570 (&Offer->Dhcp4.Header.BootFileName[0] -\r
571 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
572\r
573 }\r
574\r
575 //\r
576 // Determine offer type of the DHCPv4 packet.\r
577 //\r
578 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];\r
579 if (Option == NULL || Option->Data[0] == 0) {\r
580 //\r
581 // It's a Bootp offer.\r
582 //\r
583 OfferType = PxeOfferTypeBootp;\r
584\r
585 Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];\r
586 if (Option == NULL) {\r
587 //\r
588 // If the Bootp offer without bootfilename, discard it.\r
589 //\r
590 return EFI_DEVICE_ERROR;\r
591 }\r
592 } else {\r
593\r
594 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {\r
595 //\r
596 // It's a PXE10 offer with PXEClient and discover vendor option.\r
597 //\r
598 OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;\r
599 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {\r
600 //\r
601 // It's a WFM11a offer with PXEClient and mtftp vendor option.\r
602 // But multi-cast download is not supported currently, so discard it.\r
603 //\r
604 return EFI_DEVICE_ERROR;\r
605 } else if (IsPxeOffer) {\r
606 //\r
607 // It's a BINL offer only with PXEClient.\r
608 //\r
609 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;\r
610 } else {\r
611 //\r
612 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.\r
613 //\r
614 OfferType = PxeOfferTypeDhcpOnly;\r
615 }\r
616 }\r
617\r
618 Cache4->OfferType = OfferType;\r
619\r
620 return EFI_SUCCESS;\r
621}\r
622\r
623\r
624/**\r
625 Cache the DHCPv4 ack packet, and parse it on demand.\r
626\r
627 @param[in] Private Pointer to PxeBc private data.\r
628 @param[in] Ack Pointer to the DHCPv4 ack packet.\r
629 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.\r
630\r
a35dc649
FS
631 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
632 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
633\r
a3bcde70 634**/\r
a35dc649 635EFI_STATUS\r
a3bcde70
HT
636PxeBcCopyDhcp4Ack (\r
637 IN PXEBC_PRIVATE_DATA *Private,\r
638 IN EFI_DHCP4_PACKET *Ack,\r
639 IN BOOLEAN Verified\r
640 )\r
641{\r
642 EFI_PXE_BASE_CODE_MODE *Mode;\r
a35dc649 643 EFI_STATUS Status;\r
a3bcde70
HT
644\r
645 Mode = Private->PxeBc.Mode;\r
646\r
a35dc649
FS
647 Status = PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);\r
648 if (EFI_ERROR (Status)) {\r
649 return Status;\r
650 }\r
a3bcde70
HT
651\r
652 if (Verified) {\r
653 //\r
654 // Parse the ack packet and store it into mode data if needed.\r
655 //\r
656 PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);\r
657 CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);\r
658 Mode->DhcpAckReceived = TRUE;\r
659 }\r
a35dc649
FS
660 \r
661 return EFI_SUCCESS;\r
a3bcde70
HT
662}\r
663\r
664\r
665/**\r
666 Cache the DHCPv4 proxy offer packet according to the received order.\r
667\r
668 @param[in] Private Pointer to PxeBc private data.\r
669 @param[in] OfferIndex The received order of offer packets.\r
670\r
a35dc649
FS
671 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
672 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
673\r
a3bcde70 674**/\r
a35dc649 675EFI_STATUS\r
a3bcde70
HT
676PxeBcCopyProxyOffer (\r
677 IN PXEBC_PRIVATE_DATA *Private,\r
678 IN UINT32 OfferIndex\r
679 )\r
680{\r
681 EFI_PXE_BASE_CODE_MODE *Mode;\r
682 EFI_DHCP4_PACKET *Offer;\r
a35dc649 683 EFI_STATUS Status;\r
a3bcde70
HT
684\r
685 ASSERT (OfferIndex < Private->OfferNum);\r
686 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);\r
687\r
688 Mode = Private->PxeBc.Mode;\r
689 Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;\r
690\r
691 //\r
692 // Cache the proxy offer packet and parse it.\r
693 //\r
a35dc649
FS
694 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);\r
695 if (EFI_ERROR(Status)) {\r
696 return Status;\r
697 }\r
698 \r
a3bcde70
HT
699 PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);\r
700\r
701 //\r
702 // Store this packet into mode data.\r
703 //\r
704 CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);\r
705 Mode->ProxyOfferReceived = TRUE;\r
a35dc649
FS
706\r
707 return EFI_SUCCESS;\r
a3bcde70
HT
708}\r
709\r
710\r
711/**\r
712 Retry to request bootfile name by the BINL offer.\r
713\r
714 @param[in] Private Pointer to PxeBc private data.\r
715 @param[in] Index The received order of offer packets.\r
716\r
717 @retval EFI_SUCCESS Successfully retried to request bootfile name.\r
718 @retval EFI_DEVICE_ERROR Failed to retry bootfile name.\r
719\r
720**/\r
721EFI_STATUS\r
722PxeBcRetryBinlOffer (\r
723 IN PXEBC_PRIVATE_DATA *Private,\r
724 IN UINT32 Index\r
725 )\r
726{\r
727 EFI_DHCP4_PACKET *Offer;\r
728 EFI_IP_ADDRESS ServerIp;\r
729 EFI_STATUS Status;\r
730 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
731 EFI_DHCP4_PACKET *Reply;\r
732\r
733 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
734 ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||\r
735 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl);\r
736\r
737 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;\r
738\r
739 //\r
740 // Prefer to siaddr in header as next server address. If it's zero, then use option 54.\r
741 //\r
742 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {\r
743 CopyMem (\r
744 &ServerIp.Addr[0],\r
745 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
746 sizeof (EFI_IPv4_ADDRESS)\r
747 );\r
748 } else {\r
749 CopyMem (\r
750 &ServerIp.Addr[0],\r
751 &Offer->Dhcp4.Header.ServerAddr,\r
752 sizeof (EFI_IPv4_ADDRESS)\r
753 );\r
754 }\r
755\r
756 Private->IsDoDiscover = FALSE;\r
757 Cache4 = &Private->ProxyOffer.Dhcp4;\r
758 Reply = &Cache4->Packet.Offer;\r
759\r
760 //\r
761 // Send another request packet for bootfile name.\r
762 //\r
763 Status = PxeBcDhcp4Discover (\r
764 Private,\r
765 0,\r
766 NULL,\r
767 FALSE,\r
768 &ServerIp,\r
769 0,\r
770 NULL\r
771 );\r
772 if (EFI_ERROR (Status)) {\r
773 return Status;\r
774 }\r
775\r
776 //\r
777 // Parse the reply for the last request packet.\r
778 //\r
779 Status = PxeBcParseDhcp4Packet (Cache4);\r
780 if (EFI_ERROR (Status)) {\r
781 return Status;\r
782 }\r
783\r
784 if (Cache4->OfferType != PxeOfferTypeProxyPxe10 &&\r
785 Cache4->OfferType != PxeOfferTypeProxyWfm11a &&\r
786 Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
787 //\r
788 // This BINL ack doesn't have discovery option set or multicast option set\r
789 // or bootfile name specified.\r
790 //\r
791 return EFI_DEVICE_ERROR;\r
792 }\r
793\r
794 //\r
795 // Store the reply into mode data.\r
796 //\r
797 Private->PxeBc.Mode->ProxyOfferReceived = TRUE;\r
798 CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);\r
799\r
800 return EFI_SUCCESS;\r
801}\r
802\r
803\r
804/**\r
805 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.\r
806\r
807 @param[in] Private Pointer to PxeBc private data.\r
808 @param[in] RcvdOffer Pointer to the received offer packet.\r
809\r
a35dc649
FS
810 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
811 @retval Others Operation failed.\r
812\r
a3bcde70 813**/\r
a35dc649 814EFI_STATUS\r
a3bcde70
HT
815PxeBcCacheDhcp4Offer (\r
816 IN PXEBC_PRIVATE_DATA *Private,\r
817 IN EFI_DHCP4_PACKET *RcvdOffer\r
818 )\r
819{\r
820 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
821 EFI_DHCP4_PACKET *Offer;\r
822 PXEBC_OFFER_TYPE OfferType;\r
a35dc649 823 EFI_STATUS Status;\r
a3bcde70
HT
824\r
825 ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);\r
826 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;\r
827 Offer = &Cache4->Packet.Offer;\r
828\r
829 //\r
830 // Cache the content of DHCPv4 packet firstly.\r
831 //\r
a35dc649
FS
832 Status = PxeBcCacheDhcp4Packet (Offer, RcvdOffer);\r
833 if (EFI_ERROR(Status)) {\r
834 return Status;\r
835 }\r
a3bcde70
HT
836\r
837 //\r
838 // Validate the DHCPv4 packet, and parse the options and offer type.\r
839 //\r
840 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {\r
a35dc649 841 return EFI_ABORTED;\r
a3bcde70
HT
842 }\r
843\r
844 //\r
845 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
846 //\r
847 OfferType = Cache4->OfferType;\r
848 ASSERT (OfferType < PxeOfferTypeMax);\r
849\r
850 if (OfferType == PxeOfferTypeBootp) {\r
851 //\r
852 // It's a Bootp offer, only cache the first one, and discard the others.\r
853 //\r
854 if (Private->OfferCount[OfferType] == 0) {\r
855 Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
856 Private->OfferCount[OfferType] = 1;\r
857 } else {\r
a35dc649 858 return EFI_ABORTED;\r
a3bcde70
HT
859 }\r
860 } else {\r
861 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);\r
862 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
863 //\r
864 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.\r
865 //\r
866 Private->IsProxyRecved = TRUE;\r
867\r
868 if (OfferType == PxeOfferTypeProxyBinl) {\r
869 //\r
870 // Cache all proxy BINL offers.\r
871 //\r
872 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
873 Private->OfferCount[OfferType]++;\r
8cdd559b
JW
874 } else if ((OfferType == PxeOfferTypeProxyPxe10 || OfferType == PxeOfferTypeProxyWfm11a) && \r
875 Private->OfferCount[OfferType] < 1) {\r
a3bcde70
HT
876 //\r
877 // Only cache the first PXE10/WFM11a offer, and discard the others.\r
878 //\r
879 Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
880 Private->OfferCount[OfferType] = 1;\r
881 } else {\r
a35dc649 882 return EFI_ABORTED;\r
a3bcde70
HT
883 }\r
884 } else {\r
885 //\r
886 // It's a DHCPv4 offer with yiaddr, and cache them all.\r
887 //\r
888 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
889 Private->OfferCount[OfferType]++;\r
890 }\r
891 }\r
892\r
893 Private->OfferNum++;\r
a35dc649
FS
894\r
895 return EFI_SUCCESS;\r
a3bcde70
HT
896}\r
897\r
898\r
899/**\r
900 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.\r
901\r
902 @param[in] Private Pointer to PxeBc private data.\r
903\r
904**/\r
905VOID\r
906PxeBcSelectDhcp4Offer (\r
907 IN PXEBC_PRIVATE_DATA *Private\r
908 )\r
909{\r
910 UINT32 Index;\r
911 UINT32 OfferIndex;\r
912 EFI_DHCP4_PACKET *Offer;\r
913\r
914 Private->SelectIndex = 0;\r
915\r
916 if (Private->IsOfferSorted) {\r
917 //\r
918 // Select offer by default policy.\r
919 //\r
920 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {\r
921 //\r
922 // 1. DhcpPxe10 offer\r
923 //\r
924 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;\r
925\r
926 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {\r
927 //\r
928 // 2. DhcpWfm11a offer\r
929 //\r
930 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;\r
931\r
932 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
933 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {\r
934 //\r
935 // 3. DhcpOnly offer and ProxyPxe10 offer.\r
936 //\r
937 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
938 Private->SelectProxyType = PxeOfferTypeProxyPxe10;\r
939\r
940 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
941 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {\r
942 //\r
943 // 4. DhcpOnly offer and ProxyWfm11a offer.\r
944 //\r
945 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
946 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;\r
947\r
948 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {\r
949 //\r
950 // 5. DhcpBinl offer.\r
951 //\r
952 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;\r
953\r
954 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
955 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {\r
956 //\r
957 // 6. DhcpOnly offer and ProxyBinl offer.\r
958 //\r
959 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
960 Private->SelectProxyType = PxeOfferTypeProxyBinl;\r
961\r
962 } else {\r
963 //\r
964 // 7. DhcpOnly offer with bootfilename.\r
965 //\r
966 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {\r
967 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];\r
968 if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
969 Private->SelectIndex = OfferIndex + 1;\r
970 break;\r
971 }\r
972 }\r
973 //\r
974 // 8. Bootp offer with bootfilename.\r
975 //\r
976 OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];\r
977 if (Private->SelectIndex == 0 &&\r
978 Private->OfferCount[PxeOfferTypeBootp] > 0 &&\r
979 Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
980 Private->SelectIndex = OfferIndex + 1;\r
981 }\r
982 }\r
983 } else {\r
984 //\r
985 // Select offer by received order.\r
986 //\r
987 for (Index = 0; Index < Private->OfferNum; Index++) {\r
988\r
989 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;\r
990\r
991 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
992 //\r
993 // Skip proxy offers\r
994 //\r
995 continue;\r
996 }\r
997\r
998 if (!Private->IsProxyRecved &&\r
999 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly &&\r
1000 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
1001 //\r
1002 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.\r
1003 //\r
1004 continue;\r
1005 }\r
1006\r
1007 //\r
1008 // Record the index of the select offer.\r
1009 //\r
1010 Private->SelectIndex = Index + 1;\r
1011 break;\r
1012 }\r
1013 }\r
1014}\r
1015\r
1016\r
1017/**\r
1018 Handle the DHCPv4 offer packet.\r
1019\r
a35dc649 1020 @param[in] Private Pointer to PxeBc private data.\r
a3bcde70 1021\r
a35dc649
FS
1022 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.\r
1023 @retval EFI_NO_RESPONSE No response to the following request packet.\r
1024 @retval EFI_NOT_FOUND No boot filename received.\r
1025 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.\r
a3bcde70
HT
1026\r
1027**/\r
1028EFI_STATUS\r
1029PxeBcHandleDhcp4Offer (\r
1030 IN PXEBC_PRIVATE_DATA *Private\r
1031 )\r
1032{\r
1033 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
1034 EFI_DHCP4_PACKET_OPTION **Options;\r
1035 UINT32 Index;\r
1036 EFI_DHCP4_PACKET *Offer;\r
1037 PXEBC_OFFER_TYPE OfferType;\r
1038 UINT32 ProxyIndex;\r
1039 UINT32 SelectIndex;\r
1040 EFI_STATUS Status;\r
1041 EFI_PXE_BASE_CODE_MODE *Mode;\r
1042 EFI_DHCP4_PACKET *Ack;\r
1043\r
1044 ASSERT (Private->SelectIndex > 0);\r
1045 SelectIndex = (UINT32) (Private->SelectIndex - 1);\r
1046 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);\r
1047 Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4;\r
1048 Options = Cache4->OptList;\r
1049 Status = EFI_SUCCESS;\r
1050\r
1051 if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {\r
1052 //\r
1053 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
1054 //\r
1055 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {\r
1056 Status = EFI_NO_RESPONSE;\r
1057 }\r
1058 } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {\r
1059\r
1060 if (Private->IsProxyRecved) {\r
1061 //\r
1062 // DhcpOnly offer is selected, so need try to request bootfile name.\r
1063 //\r
1064 ProxyIndex = 0;\r
1065 if (Private->IsOfferSorted) {\r
1066 //\r
1067 // The proxy offer should be determined if select by default policy.\r
1068 // IsOfferSorted means all offers are labeled by OfferIndex.\r
1069 //\r
1070 ASSERT (Private->SelectProxyType < PxeOfferTypeMax);\r
1071 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);\r
1072\r
1073 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {\r
1074 //\r
1075 // Try all the cached ProxyBinl offer one by one to request bootfile name.\r
1076 //\r
1077 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {\r
1078 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
1079 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];\r
1080 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {\r
1081 break;\r
1082 }\r
1083 }\r
1084 if (Index == Private->OfferCount[Private->SelectProxyType]) {\r
1085 Status = EFI_NO_RESPONSE;\r
1086 }\r
1087 } else {\r
1088 //\r
1089 // For other proxy offers, only one is buffered.\r
1090 //\r
1091 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
1092 }\r
1093 } else {\r
1094 //\r
1095 // The proxy offer should not be determined if select by received order.\r
1096 //\r
1097 Status = EFI_NO_RESPONSE;\r
1098\r
1099 for (Index = 0; Index < Private->OfferNum; Index++) {\r
1100 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
1101 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;\r
1102 OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;\r
1103 if (!IS_PROXY_DHCP_OFFER (Offer)) {\r
1104 //\r
1105 // Skip non proxy DHCPv4 offers.\r
1106 //\r
1107 continue;\r
1108 }\r
1109\r
1110 if (OfferType == PxeOfferTypeProxyBinl) {\r
1111 //\r
1112 // Try all the cached ProxyBinl offer one by one to request bootfile name.\r
1113 //\r
1114 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {\r
1115 continue;\r
1116 }\r
1117 }\r
1118\r
1119 Private->SelectProxyType = OfferType;\r
1120 ProxyIndex = Index;\r
1121 Status = EFI_SUCCESS;\r
1122 break;\r
1123 }\r
1124 }\r
1125\r
1126 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {\r
1127 //\r
1128 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.\r
1129 //\r
a35dc649 1130 Status = PxeBcCopyProxyOffer (Private, ProxyIndex);\r
a3bcde70
HT
1131 }\r
1132 } else {\r
1133 //\r
1134 // Othewise, the bootfile name must be included in DhcpOnly offer.\r
1135 //\r
4496ff75 1136 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
1137 Status = EFI_NOT_FOUND;\r
1138 }\r
a3bcde70
HT
1139 }\r
1140 }\r
1141\r
1142 if (!EFI_ERROR (Status)) {\r
1143 //\r
1144 // All PXE boot information is ready by now.\r
1145 //\r
1146 Mode = Private->PxeBc.Mode;\r
1147 Offer = &Cache4->Packet.Offer;\r
1148 Ack = &Private->DhcpAck.Dhcp4.Packet.Ack;\r
1149 if (Cache4->OfferType == PxeOfferTypeBootp) {\r
1150 //\r
1151 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply\r
1152 // should be taken as ack.\r
1153 //\r
1154 Ack = Offer;\r
1155 }\r
1156\r
a35dc649
FS
1157 Status = PxeBcCopyDhcp4Ack (Private, Ack, TRUE);\r
1158 if (EFI_ERROR (Status)) {\r
1159 return Status;\r
1160 }\r
a3bcde70
HT
1161 Mode->DhcpDiscoverValid = TRUE;\r
1162 }\r
1163\r
1164 return Status;\r
1165}\r
1166\r
1167\r
1168/**\r
1169 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
1170 to intercept events that occurred in the configuration process.\r
1171\r
1172 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
1173 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
1174 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
1175 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
1176 state transition.\r
1177 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
1178 @param[out] NewPacket The packet that is used to replace the above Packet.\r
1179\r
1180 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
1181 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
1182 driver will continue to wait for more DHCPOFFER packets until the\r
1183 retry timeout expires.\r
1184 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
1185 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
1186\r
1187**/\r
1188EFI_STATUS\r
1189EFIAPI\r
1190PxeBcDhcp4CallBack (\r
1191 IN EFI_DHCP4_PROTOCOL *This,\r
1192 IN VOID *Context,\r
1193 IN EFI_DHCP4_STATE CurrentState,\r
1194 IN EFI_DHCP4_EVENT Dhcp4Event,\r
1195 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
1196 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
1197 )\r
1198{\r
1199 PXEBC_PRIVATE_DATA *Private;\r
1200 EFI_PXE_BASE_CODE_MODE *Mode;\r
1201 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
1202 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
1203 UINT16 Value;\r
1204 EFI_STATUS Status;\r
1205 BOOLEAN Received;\r
1206\r
1207 if ((Dhcp4Event != Dhcp4RcvdOffer) &&\r
1208 (Dhcp4Event != Dhcp4SelectOffer) &&\r
1209 (Dhcp4Event != Dhcp4SendDiscover) &&\r
1210 (Dhcp4Event != Dhcp4RcvdAck)) {\r
1211 return EFI_SUCCESS;\r
1212 }\r
1213\r
9d1c98e6
FS
1214 ASSERT (Packet != NULL);\r
1215\r
a3bcde70
HT
1216 Private = (PXEBC_PRIVATE_DATA *) Context;\r
1217 Mode = Private->PxeBc.Mode;\r
1218 Callback = Private->PxeBcCallback;\r
1219\r
1220 //\r
1221 // Override the Maximum DHCP Message Size.\r
1222 //\r
1223 MaxMsgSize = PxeBcParseDhcp4Options (\r
1224 Packet->Dhcp4.Option,\r
1225 GET_OPTION_BUFFER_LEN (Packet),\r
142c00c3 1226 DHCP4_TAG_MAXMSG\r
a3bcde70
HT
1227 );\r
1228 if (MaxMsgSize != NULL) {\r
632dcfd6 1229 Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE);\r
a3bcde70
HT
1230 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
1231 }\r
1232\r
1233 //\r
1234 // Callback to user if any packets sent or received.\r
1235 //\r
1236 if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) {\r
1237 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);\r
1238 Status = Callback->Callback (\r
1239 Callback,\r
1240 Private->Function,\r
1241 Received,\r
1242 Packet->Length,\r
1243 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4\r
1244 );\r
1245 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
1246 return EFI_ABORTED;\r
1247 }\r
1248 }\r
1249\r
1250 Status = EFI_SUCCESS;\r
1251\r
1252 switch (Dhcp4Event) {\r
1253\r
1254 case Dhcp4SendDiscover:\r
632dcfd6
FS
1255 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {\r
1256 //\r
1257 // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
1258 //\r
1259 Status = EFI_ABORTED;\r
1260 break;\r
1261 }\r
1262\r
a3bcde70
HT
1263 //\r
1264 // Cache the DHCPv4 discover packet to mode data directly.\r
1265 // It need to check SendGuid as well as Dhcp4SendRequest.\r
1266 //\r
1267 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);\r
1268\r
1269 case Dhcp4SendRequest:\r
632dcfd6
FS
1270 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {\r
1271 //\r
1272 // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
1273 //\r
1274 Status = EFI_ABORTED;\r
1275 break;\r
1276 }\r
1277 \r
a3bcde70
HT
1278 if (Mode->SendGUID) {\r
1279 //\r
1280 // Send the system Guid instead of the MAC address as the hardware address if required.\r
1281 //\r
19ddbb25 1282 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) {\r
a3bcde70
HT
1283 //\r
1284 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
1285 //\r
ccd05ddd 1286 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
a3bcde70
HT
1287 ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));\r
1288 }\r
1289 Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);\r
1290 }\r
1291 break;\r
1292\r
1293 case Dhcp4RcvdOffer:\r
1294 Status = EFI_NOT_READY;\r
632dcfd6
FS
1295 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {\r
1296 //\r
1297 // Ignore the incoming packets which exceed the maximum length.\r
1298 //\r
1299 break;\r
1300 }\r
a3bcde70
HT
1301 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {\r
1302 //\r
1303 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
1304 // the OfferIndex and OfferCount.\r
a35dc649 1305 // If error happens, just ignore this packet and continue to wait more offer.\r
a3bcde70
HT
1306 //\r
1307 PxeBcCacheDhcp4Offer (Private, Packet);\r
1308 }\r
1309 break;\r
1310\r
1311 case Dhcp4SelectOffer:\r
9d1c98e6
FS
1312 ASSERT (NewPacket != NULL);\r
1313 \r
a3bcde70
HT
1314 //\r
1315 // Select offer by the default policy or by order, and record the SelectIndex\r
1316 // and SelectProxyType.\r
1317 //\r
1318 PxeBcSelectDhcp4Offer (Private);\r
1319\r
1320 if (Private->SelectIndex == 0) {\r
1321 Status = EFI_ABORTED;\r
1322 } else {\r
1323 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
1324 }\r
1325 break;\r
1326\r
1327 case Dhcp4RcvdAck:\r
1328 //\r
1329 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data\r
1330 // without verification.\r
1331 //\r
1332 ASSERT (Private->SelectIndex != 0);\r
1333\r
a35dc649
FS
1334 Status = PxeBcCopyDhcp4Ack (Private, Packet, FALSE);\r
1335 if (EFI_ERROR (Status)) {\r
1336 Status = EFI_ABORTED;\r
1337 }\r
a3bcde70
HT
1338 break;\r
1339\r
1340 default:\r
1341 break;\r
1342 }\r
1343\r
1344 return Status;\r
1345}\r
1346\r
1347\r
1348/**\r
1349 Build and send out the request packet for the bootfile, and parse the reply.\r
1350\r
1351 @param[in] Private Pointer to PxeBc private data.\r
1352 @param[in] Type PxeBc option boot item type.\r
1353 @param[in] Layer Pointer to option boot item layer.\r
1354 @param[in] UseBis Use BIS or not.\r
1355 @param[in] DestIp Pointer to the server address.\r
1356 @param[in] IpCount The total count of the server address.\r
1357 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.\r
1358\r
1359 @retval EFI_SUCCESS Successfully discovered boot file.\r
1360 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
1361 @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
1362 @retval Others Failed to discover boot file.\r
1363\r
1364**/\r
1365EFI_STATUS\r
1366PxeBcDhcp4Discover (\r
1367 IN PXEBC_PRIVATE_DATA *Private,\r
1368 IN UINT16 Type,\r
1369 IN UINT16 *Layer,\r
1370 IN BOOLEAN UseBis,\r
1371 IN EFI_IP_ADDRESS *DestIp,\r
1372 IN UINT16 IpCount,\r
1373 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList\r
1374 )\r
1375{\r
1376 EFI_PXE_BASE_CODE_UDP_PORT Sport;\r
1377 EFI_PXE_BASE_CODE_MODE *Mode;\r
1378 EFI_DHCP4_PROTOCOL *Dhcp4;\r
1379 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;\r
1380 BOOLEAN IsBCast;\r
1381 EFI_STATUS Status;\r
1382 UINT16 RepIndex;\r
1383 UINT16 SrvIndex;\r
1384 UINT16 TryIndex;\r
1385 EFI_DHCP4_LISTEN_POINT ListenPoint;\r
1386 EFI_DHCP4_PACKET *Response;\r
1387 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];\r
1388 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];\r
1389 UINT32 OptCount;\r
1390 EFI_DHCP4_PACKET_OPTION *PxeOpt;\r
1391 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;\r
1392 UINT8 VendorOptLen;\r
1393 UINT32 Xid;\r
1394\r
1395 Mode = Private->PxeBc.Mode;\r
1396 Dhcp4 = Private->Dhcp4;\r
1397 Status = EFI_SUCCESS;\r
1398\r
1399 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
1400\r
1401 //\r
1402 // Use broadcast if destination address not specified.\r
1403 //\r
1404 if (DestIp == NULL) {\r
1405 Sport = PXEBC_DHCP4_S_PORT;\r
1406 IsBCast = TRUE;\r
1407 } else {\r
1408 Sport = PXEBC_BS_DISCOVER_PORT;\r
1409 IsBCast = FALSE;\r
1410 }\r
1411\r
1412 if (!UseBis && Layer != NULL) {\r
1413 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1414 }\r
1415\r
1416 //\r
1417 // Build all the options for the request packet.\r
1418 //\r
1419 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);\r
1420\r
1421 if (Private->IsDoDiscover) {\r
1422 //\r
1423 // Add vendor option of PXE_BOOT_ITEM\r
1424 //\r
1425 VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);\r
1426 OptList[OptCount] = AllocateZeroPool (VendorOptLen);\r
1427 if (OptList[OptCount] == NULL) {\r
1428 return EFI_OUT_OF_RESOURCES;\r
1429 }\r
1430\r
142c00c3 1431 OptList[OptCount]->OpCode = DHCP4_TAG_VENDOR;\r
a3bcde70
HT
1432 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);\r
1433 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;\r
1434 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;\r
1435 PxeOpt->Length = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);\r
1436 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;\r
1437 PxeBootItem->Type = HTONS (Type);\r
142c00c3 1438 PxeOpt->Data[PxeOpt->Length] = DHCP4_TAG_EOP;\r
a3bcde70
HT
1439\r
1440 if (Layer != NULL) {\r
1441 PxeBootItem->Layer = HTONS (*Layer);\r
1442 }\r
1443\r
1444 OptCount++;\r
1445 }\r
1446\r
1447 //\r
1448 // Build the request packet with seed packet and option list.\r
1449 //\r
1450 Status = Dhcp4->Build (\r
1451 Dhcp4,\r
1452 &Private->SeedPacket,\r
1453 0,\r
1454 NULL,\r
1455 OptCount,\r
1456 OptList,\r
1457 &Token.Packet\r
1458 );\r
1459 //\r
1460 // Free the vendor option of PXE_BOOT_ITEM.\r
1461 //\r
1462 if (Private->IsDoDiscover) {\r
1463 FreePool (OptList[OptCount - 1]);\r
1464 }\r
1465\r
1466 if (EFI_ERROR (Status)) {\r
1467 return Status;\r
1468 }\r
1469\r
1470 if (Mode->SendGUID) {\r
19ddbb25 1471 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) {\r
a3bcde70
HT
1472 //\r
1473 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
1474 //\r
ccd05ddd 1475 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
a3bcde70
HT
1476 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));\r
1477 }\r
1478 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);\r
1479 }\r
1480\r
1481 //\r
1482 // Set fields of the token for the request packet.\r
1483 //\r
1484 Xid = NET_RANDOM (NetRandomInitSeed ());\r
1485 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid);\r
1486 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0));\r
1487 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
1488\r
1489 Token.RemotePort = Sport;\r
1490\r
1491 if (IsBCast) {\r
1492 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
1493 } else {\r
1494 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
1495 }\r
1496\r
1497 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
1498\r
1499 if (!IsBCast) {\r
1500 Token.ListenPointCount = 1;\r
1501 Token.ListenPoints = &ListenPoint;\r
1502 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;\r
1503 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));\r
1504 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));\r
1505 }\r
1506\r
1507 //\r
1508 // Send out the request packet to discover the bootfile.\r
1509 //\r
1510 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {\r
1511\r
1512 Token.TimeoutValue = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);\r
1513 Token.Packet->Dhcp4.Header.Seconds = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));\r
1514\r
1515 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
1516 if (Token.Status != EFI_TIMEOUT) {\r
1517 break;\r
1518 }\r
1519 }\r
1520\r
1521 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {\r
1522 //\r
1523 // No server response our PXE request\r
1524 //\r
1525 Status = EFI_TIMEOUT;\r
1526 }\r
1527\r
1528 if (!EFI_ERROR (Status)) {\r
1529\r
1530 RepIndex = 0;\r
1531 SrvIndex = 0;\r
1532 Response = Token.ResponseList;\r
1533 //\r
1534 // Find the right PXE Reply according to server address.\r
1535 //\r
1536 while (RepIndex < Token.ResponseCount) {\r
a35dc649
FS
1537 if (Response->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {\r
1538 SrvIndex = 0;\r
1539 RepIndex++;\r
1540 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1541 continue;\r
1542 }\r
a3bcde70
HT
1543\r
1544 while (SrvIndex < IpCount) {\r
1545 if (SrvList[SrvIndex].AcceptAnyResponse) {\r
1546 break;\r
1547 }\r
1548 if ((SrvList[SrvIndex].Type == Type) &&\r
9063c328 1549 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) {\r
a3bcde70
HT
1550 break;\r
1551 }\r
1552 SrvIndex++;\r
1553 }\r
1554\r
1555 if ((IpCount != SrvIndex) || (IpCount == 0)) {\r
1556 break;\r
1557 }\r
1558\r
1559 SrvIndex = 0;\r
1560 RepIndex++;\r
a3bcde70
HT
1561 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1562 }\r
1563\r
1564 if (RepIndex < Token.ResponseCount) {\r
1565 //\r
1566 // Cache the right PXE reply packet here, set valid flag later.\r
1567 // Especially for PXE discover packet, store it into mode data here.\r
1568 //\r
1569 if (Private->IsDoDiscover) {\r
a35dc649
FS
1570 Status = PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);\r
1571 if (EFI_ERROR(Status)) {\r
1572 goto ON_EXIT;\r
1573 }\r
a3bcde70
HT
1574 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);\r
1575 } else {\r
a35dc649
FS
1576 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);\r
1577 if (EFI_ERROR(Status)) {\r
1578 goto ON_EXIT;\r
1579 }\r
a3bcde70
HT
1580 }\r
1581 } else {\r
1582 //\r
1583 // Not found the right PXE reply packet.\r
1584 //\r
1585 Status = EFI_NOT_FOUND;\r
1586 }\r
a3bcde70 1587 }\r
a35dc649
FS
1588ON_EXIT:\r
1589 \r
1590 if (Token.ResponseList != NULL) {\r
1591 FreePool (Token.ResponseList);\r
1592 }\r
1593 if (Token.Packet != NULL) {\r
1594 FreePool (Token.Packet);\r
1595 }\r
a3bcde70
HT
1596 return Status;\r
1597}\r
1598\r
ac99793b
ZL
1599/**\r
1600 Switch the Ip4 policy to static.\r
1601\r
1602 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1603\r
1604 @retval EFI_SUCCESS The policy is already configured to static.\r
1605 @retval Others Other error as indicated..\r
1606\r
1607**/\r
1608EFI_STATUS\r
1609PxeBcSetIp4Policy ( \r
1610 IN PXEBC_PRIVATE_DATA *Private\r
1611 )\r
1612{\r
1613 EFI_STATUS Status;\r
1614 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
1615 EFI_IP4_CONFIG2_POLICY Policy;\r
1616 UINTN DataSize;\r
1617\r
1618 Ip4Config2 = Private->Ip4Config2;\r
1619 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
1620 Status = Ip4Config2->GetData (\r
1621 Ip4Config2,\r
1622 Ip4Config2DataTypePolicy,\r
1623 &DataSize,\r
1624 &Policy\r
1625 );\r
1626 if (EFI_ERROR (Status)) {\r
1627 return Status;\r
1628 }\r
1629 \r
1630 if (Policy != Ip4Config2PolicyStatic) {\r
1631 Policy = Ip4Config2PolicyStatic;\r
1632 Status= Ip4Config2->SetData (\r
1633 Ip4Config2,\r
1634 Ip4Config2DataTypePolicy,\r
1635 sizeof (EFI_IP4_CONFIG2_POLICY),\r
1636 &Policy\r
1637 );\r
1638 if (EFI_ERROR (Status)) {\r
1639 return Status;\r
1640 } \r
1641 }\r
1642\r
1643 return EFI_SUCCESS;\r
1644}\r
a3bcde70
HT
1645\r
1646/**\r
1647 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.\r
1648\r
1649 @param[in] Private Pointer to PxeBc private data.\r
1650 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL\r
1651\r
1652 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
1653 @retval Others Failed to finish the D.O.R.A process.\r
1654\r
1655**/\r
1656EFI_STATUS\r
1657PxeBcDhcp4Dora (\r
1658 IN PXEBC_PRIVATE_DATA *Private,\r
1659 IN EFI_DHCP4_PROTOCOL *Dhcp4\r
1660 )\r
1661{\r
1662 EFI_PXE_BASE_CODE_MODE *PxeMode;\r
1663 EFI_DHCP4_CONFIG_DATA Config;\r
1664 EFI_DHCP4_MODE_DATA Mode;\r
1665 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];\r
1666 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];\r
1667 UINT32 OptCount;\r
1668 EFI_STATUS Status;\r
1669\r
1670 ASSERT (Dhcp4 != NULL);\r
1671\r
1672 Status = EFI_SUCCESS;\r
1673 PxeMode = Private->PxeBc.Mode;\r
1674\r
1675 //\r
1676 // Build option list for the request packet.\r
1677 //\r
1678 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);\r
1679 ASSERT (OptCount> 0);\r
1680\r
1681 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));\r
1682 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
1683\r
1684 Config.OptionCount = OptCount;\r
1685 Config.OptionList = OptList;\r
1686 Config.Dhcp4Callback = PxeBcDhcp4CallBack;\r
1687 Config.CallbackContext = Private;\r
1688 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;\r
1689 Config.DiscoverTimeout = mPxeDhcpTimeout;\r
1690\r
1691 //\r
1692 // Configure the DHCPv4 instance for PXE boot.\r
1693 //\r
1694 Status = Dhcp4->Configure (Dhcp4, &Config);\r
1695 if (EFI_ERROR (Status)) {\r
1696 goto ON_EXIT;\r
1697 }\r
1698\r
1699 //\r
1700 // Initialize the record fields for DHCPv4 offer in private data.\r
1701 //\r
1702 Private->IsProxyRecved = FALSE;\r
1703 Private->OfferNum = 0;\r
1704 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
1705 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
1706\r
a3bcde70 1707 Status = Dhcp4->Start (Dhcp4, NULL);\r
6a4eed9b 1708 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
1709 if (Status == EFI_ICMP_ERROR) {\r
1710 PxeMode->IcmpErrorReceived = TRUE;\r
1711 }\r
10e62442
JW
1712\r
1713 if (Status == EFI_TIMEOUT && Private->OfferNum > 0) {\r
1714 Status = EFI_NO_RESPONSE;\r
1715 }\r
1716 \r
a3bcde70
HT
1717 goto ON_EXIT;\r
1718 }\r
1719\r
1720 //\r
1721 // Get the acquired IPv4 address and store them.\r
1722 //\r
1723 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
1724 if (EFI_ERROR (Status)) {\r
1725 goto ON_EXIT;\r
1726 }\r
1727\r
1728 ASSERT (Mode.State == Dhcp4Bound);\r
1729\r
1730 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
1731 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
1732 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
1733 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
1734 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
1735\r
0e7f6f50 1736 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);\r
a3bcde70
HT
1737 if (EFI_ERROR (Status)) {\r
1738 goto ON_EXIT;\r
1739 }\r
1740\r
1741 //\r
1742 // Check the selected offer whether BINL retry is needed.\r
1743 //\r
1744 Status = PxeBcHandleDhcp4Offer (Private);\r
1745\r
1746 AsciiPrint ("\n Station IP address is ");\r
1747\r
1748 PxeBcShowIp4Addr (&Private->StationIp.v4);\r
9063c328 1749 AsciiPrint ("\n");\r
a3bcde70
HT
1750\r
1751ON_EXIT:\r
1752 if (EFI_ERROR (Status)) {\r
1753 Dhcp4->Stop (Dhcp4);\r
1754 Dhcp4->Configure (Dhcp4, NULL);\r
1755 } else {\r
1756 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
1757 Dhcp4->Configure (Dhcp4, &Config);\r
1758 Private->IsAddressOk = TRUE;\r
1759 }\r
1760\r
1761 return Status;\r
1762}\r