]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcDhcp.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / Network / UefiPxeBcDxe / PxeBcDhcp.c
CommitLineData
dc361cc5 1/** @file\r
f737cfb9 2 Support for PxeBc dhcp functions.\r
e2851998 3\r
e3cf3c20 4Copyright (c) 2013, Red Hat, Inc.\r
3fad4a95 5Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 6This program and the accompanying materials\r
dc361cc5 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
dc361cc5 14**/\r
15\r
16\r
17#include "PxeBcImpl.h"\r
18\r
19//\r
20// This is a map from the interested DHCP4 option tags' index to the tag value.\r
21//\r
22UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {\r
ac6c3d90
ZL
23 DHCP4_TAG_BOOTFILE_LEN,\r
24 DHCP4_TAG_VENDOR,\r
25 DHCP4_TAG_OVERLOAD,\r
26 DHCP4_TAG_MSG_TYPE,\r
27 DHCP4_TAG_SERVER_ID,\r
28 DHCP4_TAG_VENDOR_CLASS_ID,\r
29 DHCP4_TAG_BOOTFILE\r
dc361cc5 30};\r
31\r
32\r
33/**\r
f737cfb9 34 This function initialize the DHCP4 message instance.\r
dc361cc5 35\r
f737cfb9 36 This function will pad each item of dhcp4 message packet.\r
e2851998 37\r
f737cfb9 38 @param Seed Pointer to the message instance of the DHCP4 packet.\r
39 @param Udp4 Pointer to the EFI_UDP4_PROTOCOL instance.\r
dc361cc5 40\r
dc361cc5 41**/\r
42VOID\r
43PxeBcInitSeedPacket (\r
44 IN EFI_DHCP4_PACKET *Seed,\r
45 IN EFI_UDP4_PROTOCOL *Udp4\r
46 )\r
47{\r
48 EFI_SIMPLE_NETWORK_MODE Mode;\r
49 EFI_DHCP4_HEADER *Header;\r
50\r
51 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);\r
52\r
53 Seed->Size = sizeof (EFI_DHCP4_PACKET);\r
54 Seed->Length = sizeof (Seed->Dhcp4);\r
55\r
56 Header = &Seed->Dhcp4.Header;\r
57\r
e48e37fc 58 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));\r
dc361cc5 59 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;\r
60 Header->HwType = Mode.IfType;\r
61 Header->HwAddrLen = (UINT8) Mode.HwAddressSize;\r
e48e37fc 62 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);\r
dc361cc5 63\r
64 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;\r
ac6c3d90 65 Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;\r
dc361cc5 66}\r
67\r
68\r
69/**\r
f737cfb9 70 Copy the DCHP4 packet from srouce to destination.\r
dc361cc5 71\r
471342bb
FS
72 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.\r
73 @param[in] Src Pointer to the DHCPv4 packet to be cached.\r
74\r
75 @retval EFI_SUCCESS Packet is copied.\r
76 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
dc361cc5 77\r
dc361cc5 78**/\r
471342bb 79EFI_STATUS\r
dc361cc5 80PxeBcCopyEfiDhcp4Packet (\r
81 IN EFI_DHCP4_PACKET *Dst,\r
82 IN EFI_DHCP4_PACKET *Src\r
83 )\r
84{\r
471342bb
FS
85 if (Dst->Size < Src->Length) {\r
86 return EFI_BUFFER_TOO_SMALL;\r
87 }\r
dc361cc5 88\r
e48e37fc 89 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
dc361cc5 90 Dst->Length = Src->Length;\r
471342bb 91 return EFI_SUCCESS;\r
dc361cc5 92}\r
93\r
94\r
95/**\r
f737cfb9 96 Copy the dhcp4 packet to the PxeBc private data and parse the dhcp4 packet.\r
dc361cc5 97\r
f737cfb9 98 @param Private Pointer to PxeBc private data.\r
99 @param OfferIndex Index of cached packets as complements of pxe mode data,\r
100 the index is maximum offer number.\r
dc361cc5 101\r
471342bb
FS
102 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
103 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
104\r
dc361cc5 105**/\r
471342bb 106EFI_STATUS\r
dc361cc5 107PxeBcCopyProxyOffer (\r
108 IN PXEBC_PRIVATE_DATA *Private,\r
109 IN UINT32 OfferIndex\r
110 )\r
111{\r
112 EFI_PXE_BASE_CODE_MODE *Mode;\r
113 EFI_DHCP4_PACKET *Offer;\r
471342bb 114 EFI_STATUS Status;\r
dc361cc5 115\r
116 ASSERT (OfferIndex < Private->NumOffers);\r
890986ca 117 ASSERT (OfferIndex < PXEBC_MAX_OFFER_NUM);\r
dc361cc5 118\r
119 Mode = Private->PxeBc.Mode;\r
120 Offer = &Private->Dhcp4Offers[OfferIndex].Packet.Offer;\r
121\r
471342bb
FS
122 Status = PxeBcCopyEfiDhcp4Packet (&Private->ProxyOffer.Packet.Offer, Offer);\r
123 if (EFI_ERROR(Status)) {\r
124 return Status;\r
125 }\r
e48e37fc 126 CopyMem (&Mode->ProxyOffer, &Offer->Dhcp4, Offer->Length);\r
dc361cc5 127 Mode->ProxyOfferReceived = TRUE;\r
128\r
129 PxeBcParseCachedDhcpPacket (&Private->ProxyOffer);\r
471342bb 130 return EFI_SUCCESS;\r
dc361cc5 131}\r
132\r
133\r
134/**\r
135 Parse the cached dhcp packet.\r
136\r
f737cfb9 137 @param CachedPacket Pointer to cached dhcp packet.\r
dc361cc5 138\r
f737cfb9 139 @retval TRUE Succeed to parse and validation.\r
140 @retval FALSE Fail to parse or validation.\r
dc361cc5 141\r
142**/\r
143BOOLEAN\r
144PxeBcParseCachedDhcpPacket (\r
145 IN PXEBC_CACHED_DHCP4_PACKET *CachedPacket\r
146 )\r
147{\r
148 EFI_DHCP4_PACKET *Offer;\r
149 EFI_DHCP4_PACKET_OPTION **Options;\r
150 EFI_DHCP4_PACKET_OPTION *Option;\r
151 UINT8 OfferType;\r
152 UINTN Index;\r
4546bcbb 153 UINT8 *Ptr8;\r
dc361cc5 154\r
155 CachedPacket->IsPxeOffer = FALSE;\r
e48e37fc 156 ZeroMem (CachedPacket->Dhcp4Option, sizeof (CachedPacket->Dhcp4Option));\r
157 ZeroMem (&CachedPacket->PxeVendorOption, sizeof (CachedPacket->PxeVendorOption));\r
dc361cc5 158\r
159 Offer = &CachedPacket->Packet.Offer;\r
160 Options = CachedPacket->Dhcp4Option;\r
161\r
162 //\r
163 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.\r
8cb92971 164 // First, try to parse DHCPv4 options from the DHCP optional parameters field.\r
dc361cc5 165 //\r
166 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
167 Options[Index] = PxeBcParseExtendOptions (\r
8cb92971
FS
168 Offer->Dhcp4.Option,\r
169 GET_OPTION_BUFFER_LEN (Offer),\r
170 mInterestedDhcp4Tags[Index]\r
171 );\r
172 }\r
173 //\r
d1102dba 174 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.\r
8cb92971
FS
175 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
176 //\r
177 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];\r
178 if (Option != NULL) {\r
179 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {\r
180 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
181 if (Options[Index] == NULL) {\r
182 Options[Index] = PxeBcParseExtendOptions (\r
183 (UINT8 *) Offer->Dhcp4.Header.BootFileName,\r
184 sizeof (Offer->Dhcp4.Header.BootFileName),\r
185 mInterestedDhcp4Tags[Index]\r
186 );\r
187 }\r
188 }\r
189 }\r
190 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
191 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
192 if (Options[Index] == NULL) {\r
193 Options[Index] = PxeBcParseExtendOptions (\r
194 (UINT8 *) Offer->Dhcp4.Header.ServerName,\r
195 sizeof (Offer->Dhcp4.Header.ServerName),\r
196 mInterestedDhcp4Tags[Index]\r
197 );\r
198 }\r
199 }\r
200 }\r
dc361cc5 201 }\r
202\r
203 //\r
204 // Check whether is an offer with PXEClient or not.\r
205 //\r
206 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];\r
207 if ((Option != NULL) && (Option->Length >= 9) &&\r
e48e37fc 208 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
dc361cc5 209\r
210 CachedPacket->IsPxeOffer = TRUE;\r
211 }\r
212\r
213 //\r
214 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.\r
215 //\r
216 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];\r
217 if (CachedPacket->IsPxeOffer && (Option != NULL)) {\r
218\r
219 if (!PxeBcParseVendorOptions (Option, &CachedPacket->PxeVendorOption)) {\r
220 return FALSE;\r
221 }\r
222 }\r
223\r
8cb92971 224\r
dc361cc5 225 //\r
8cb92971
FS
226 // Parse PXE boot file name:\r
227 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
228 // Otherwise, read from boot file field in DHCP header.\r
dc361cc5 229 //\r
8cb92971 230 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
4546bcbb 231 //\r
d1102dba 232 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
4546bcbb 233 // terminated string. So force to append null terminated character at the end of string.\r
234 //\r
8cb92971
FS
235 Ptr8 = (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
236 Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
237 if (*(Ptr8 - 1) != '\0') {\r
238 *Ptr8 = '\0';\r
a4ac31e0 239 }\r
8cb92971 240 } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
dc361cc5 241 //\r
242 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.\r
75dce340 243 // And do not count dhcp option header, or else will destroy the serverhostname.\r
dc361cc5 244 //\r
61e0f079
HG
245 // Make sure "BootFileName" is not overloaded.\r
246 //\r
247 if (Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD] == NULL ||\r
248 (Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD]->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) == 0) {\r
249 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *) (&Offer->Dhcp4.Header.BootFileName[0] -\r
f3f2e05d 250 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
61e0f079 251 }\r
dc361cc5 252 }\r
253\r
254 //\r
255 // Determine offer type of the dhcp packet.\r
256 //\r
257 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];\r
258 if ((Option == NULL) || (Option->Data[0] == 0)) {\r
259 //\r
260 // It's a bootp offer\r
261 //\r
262 Option = CachedPacket->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];\r
263 if (Option == NULL) {\r
264 //\r
265 // bootp offer without bootfilename, discard it.\r
266 //\r
267 return FALSE;\r
268 }\r
269\r
270 OfferType = DHCP4_PACKET_TYPE_BOOTP;\r
271\r
272 } else {\r
273\r
274 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket->PxeVendorOption.BitMap)) {\r
275 //\r
276 // It's a pxe10 offer with PXEClient and discover vendor option.\r
277 //\r
278 OfferType = DHCP4_PACKET_TYPE_PXE10;\r
279 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket->PxeVendorOption.BitMap)) {\r
280 //\r
281 // It's a wfm11a offer with PXEClient and mtftp vendor option, and\r
282 // return false since mtftp not supported currently.\r
283 //\r
284 return FALSE;\r
dc361cc5 285 } else {\r
286 //\r
287 // If the binl offer with only PXEClient.\r
288 //\r
289 OfferType = (UINT8) ((CachedPacket->IsPxeOffer) ? DHCP4_PACKET_TYPE_BINL : DHCP4_PACKET_TYPE_DHCP_ONLY);\r
290 }\r
291 }\r
292\r
293 CachedPacket->OfferType = OfferType;\r
294\r
295 return TRUE;\r
296}\r
297\r
298\r
299/**\r
f737cfb9 300 Offer dhcp service with a BINL dhcp offer.\r
dc361cc5 301\r
f737cfb9 302 @param Private Pointer to PxeBc private data.\r
303 @param Index Index of cached packets as complements of pxe mode data,\r
304 the index is maximum offer number.\r
dc361cc5 305\r
f737cfb9 306 @retval TRUE Offer the service successfully under priority BINL.\r
e2851998 307 @retval FALSE Boot Service failed, parse cached dhcp packet failed or this\r
f737cfb9 308 BINL ack cannot find options set or bootfile name specified.\r
e2851998 309\r
dc361cc5 310**/\r
311BOOLEAN\r
312PxeBcTryBinl (\r
313 IN PXEBC_PRIVATE_DATA *Private,\r
314 IN UINT32 Index\r
315 )\r
316{\r
317 EFI_DHCP4_PACKET *Offer;\r
318 EFI_IP_ADDRESS ServerIp;\r
319 EFI_STATUS Status;\r
320 PXEBC_CACHED_DHCP4_PACKET *CachedPacket;\r
321 EFI_DHCP4_PACKET *Reply;\r
322\r
894d038a 323 ASSERT (Index < PXEBC_MAX_OFFER_NUM);\r
dc361cc5 324 ASSERT (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL);\r
325\r
326 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
319075ff 327\r
328 //\r
2ce5c88a 329 // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)\r
330 // in DHCPOFFER packet.\r
331 // (It does not comply with PXE Spec, Ver2.1)\r
319075ff 332 //\r
2ce5c88a 333 if (EFI_IP4_EQUAL (&Offer->Dhcp4.Header.ServerAddr.Addr, &mZeroIp4Addr)) {\r
e48e37fc 334 CopyMem (\r
dc361cc5 335 &ServerIp.Addr[0],\r
336 Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
337 sizeof (EFI_IPv4_ADDRESS)\r
338 );\r
339 } else {\r
319075ff 340 CopyMem (\r
e2851998 341 &ServerIp.Addr[0],\r
342 &Offer->Dhcp4.Header.ServerAddr,\r
319075ff 343 sizeof (EFI_IPv4_ADDRESS)\r
344 );\r
345 }\r
346 if (ServerIp.Addr[0] == 0) {\r
347 return FALSE;\r
dc361cc5 348 }\r
349\r
350 CachedPacket = &Private->ProxyOffer;\r
351 Reply = &CachedPacket->Packet.Offer;\r
352\r
353 Status = PxeBcDiscvBootService (\r
354 Private,\r
355 0,\r
356 NULL,\r
357 FALSE,\r
358 &ServerIp,\r
359 0,\r
360 NULL,\r
361 FALSE,\r
362 Reply\r
363 );\r
364 if (EFI_ERROR (Status)) {\r
365 return FALSE;\r
366 }\r
367\r
368 if (!PxeBcParseCachedDhcpPacket (CachedPacket)) {\r
369 return FALSE;\r
370 }\r
371\r
372 if ((CachedPacket->OfferType != DHCP4_PACKET_TYPE_PXE10) &&\r
373 (CachedPacket->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL)) {\r
374 //\r
375 // This BINL ack doesn't have discovery options set or bootfile name\r
376 // specified.\r
377 //\r
378 return FALSE;\r
379 }\r
380\r
381 Private->PxeBc.Mode->ProxyOfferReceived = TRUE;\r
e48e37fc 382 CopyMem (&Private->PxeBc.Mode->ProxyOffer, &Reply->Dhcp4, Reply->Length);\r
dc361cc5 383\r
384 return TRUE;\r
385}\r
386\r
387\r
388/**\r
f737cfb9 389 Offer dhcp service for each proxy with a BINL dhcp offer.\r
dc361cc5 390\r
f737cfb9 391 @param Private Pointer to PxeBc private data\r
e2851998 392 @param OfferIndex Pointer to the index of cached packets as complements of\r
f737cfb9 393 pxe mode data, the index is maximum offer number.\r
dc361cc5 394\r
f737cfb9 395 @return If there is no service needed offer return FALSE, otherwise TRUE.\r
dc361cc5 396\r
397**/\r
398BOOLEAN\r
399PxeBcTryBinlProxy (\r
400 IN PXEBC_PRIVATE_DATA *Private,\r
401 OUT UINT32 *OfferIndex\r
402 )\r
403{\r
404 UINT32 Index;\r
405\r
406 for (Index = 0; Index < Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]; Index++) {\r
407\r
408 *OfferIndex = Private->BinlIndex[Index];\r
409 //\r
410 // Try this BINL proxy offer\r
411 //\r
412 if (PxeBcTryBinl (Private, *OfferIndex)) {\r
413 return TRUE;\r
414 }\r
415 }\r
416\r
417 return FALSE;\r
418}\r
419\r
420\r
421/**\r
f737cfb9 422 This function is to check the selected proxy offer (include BINL dhcp offer and\r
423 DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code\r
424 mode structure.\r
dc361cc5 425\r
f737cfb9 426 @param Private Pointer to PxeBc private data.\r
dc361cc5 427\r
471342bb
FS
428 @retval EFI_SUCCESS Operational successful.\r
429 @retval EFI_NO_RESPONSE Offer dhcp service failed.\r
430 @retval EFI_BUFFER_TOO_SMALL Failed to copy the packet to Pxe base code mode.\r
dc361cc5 431\r
432**/\r
433EFI_STATUS\r
434PxeBcCheckSelectedOffer (\r
435 IN PXEBC_PRIVATE_DATA *Private\r
436 )\r
437{\r
438 PXEBC_CACHED_DHCP4_PACKET *SelectedOffer;\r
439 EFI_DHCP4_PACKET_OPTION **Options;\r
440 UINT32 Index;\r
441 EFI_DHCP4_PACKET *Offer;\r
442 UINT32 ProxyOfferIndex;\r
443 EFI_STATUS Status;\r
444 EFI_PXE_BASE_CODE_MODE *Mode;\r
445 EFI_DHCP4_PACKET *Ack;\r
446\r
447 ASSERT (Private->SelectedOffer != 0);\r
448\r
449 Status = EFI_SUCCESS;\r
450 SelectedOffer = &Private->Dhcp4Offers[Private->SelectedOffer - 1];\r
451 Options = SelectedOffer->Dhcp4Option;\r
452\r
453 if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BINL) {\r
454 //\r
455 // The addresses are acquired from a BINL dhcp offer, try BINL to get\r
456 // the bootfile name\r
457 //\r
458 if (!PxeBcTryBinl (Private, Private->SelectedOffer - 1)) {\r
459 Status = EFI_NO_RESPONSE;\r
460 }\r
05c0e3cb 461 } else if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) {\r
dc361cc5 462 //\r
e2851998 463 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need\r
464 // try proxy offers if there are some, othewise the bootfile name must be\r
05c0e3cb 465 // set in this DHCP only offer.\r
dc361cc5 466 //\r
05c0e3cb 467 if (Private->GotProxyOffer) {\r
dc361cc5 468 //\r
05c0e3cb 469 // Get rid of the compiler warning.\r
dc361cc5 470 //\r
05c0e3cb 471 ProxyOfferIndex = 0;\r
472 if (Private->SortOffers) {\r
dc361cc5 473 //\r
05c0e3cb 474 // The offers are sorted before selecting, the proxy offer type must be\r
475 // already determined.\r
dc361cc5 476 //\r
05c0e3cb 477 ASSERT (Private->ProxyIndex[Private->ProxyOfferType] > 0);\r
478\r
479 if (Private->ProxyOfferType == DHCP4_PACKET_TYPE_BINL) {\r
480 //\r
481 // We buffer all received BINL proxy offers, try them all one by one\r
482 //\r
483 if (!PxeBcTryBinlProxy (Private, &ProxyOfferIndex)) {\r
484 Status = EFI_NO_RESPONSE;\r
485 }\r
486 } else {\r
487 //\r
488 // For other types, only one proxy offer is buffered.\r
489 //\r
490 ProxyOfferIndex = Private->ProxyIndex[Private->ProxyOfferType] - 1;\r
dc361cc5 491 }\r
492 } else {\r
493 //\r
e2851998 494 // The proxy offer type is not determined, choose proxy offer in the\r
05c0e3cb 495 // received order.\r
dc361cc5 496 //\r
05c0e3cb 497 Status = EFI_NO_RESPONSE;\r
dc361cc5 498\r
523f48e7 499 ASSERT (Private->NumOffers < PXEBC_MAX_OFFER_NUM);\r
05c0e3cb 500 for (Index = 0; Index < Private->NumOffers; Index++) {\r
dc361cc5 501\r
05c0e3cb 502 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
503 if (!IS_PROXY_DHCP_OFFER (Offer)) {\r
dc361cc5 504 //\r
05c0e3cb 505 // Skip non proxy dhcp offers.\r
dc361cc5 506 //\r
507 continue;\r
508 }\r
dc361cc5 509\r
05c0e3cb 510 if (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL) {\r
511 //\r
512 // Try BINL\r
513 //\r
514 if (!PxeBcTryBinl (Private, Index)) {\r
515 //\r
516 // Failed, skip to the next offer\r
517 //\r
518 continue;\r
519 }\r
520 }\r
521\r
522 Private->ProxyOfferType = Private->Dhcp4Offers[Index].OfferType;\r
523 ProxyOfferIndex = Index;\r
524 Status = EFI_SUCCESS;\r
525 break;\r
526 }\r
dc361cc5 527 }\r
dc361cc5 528\r
05c0e3cb 529 if (!EFI_ERROR (Status) && (Private->ProxyOfferType != DHCP4_PACKET_TYPE_BINL)) {\r
530 //\r
531 // Copy the proxy offer to Mode and set the flag\r
532 //\r
471342bb 533 Status = PxeBcCopyProxyOffer (Private, ProxyOfferIndex);\r
05c0e3cb 534 }\r
535 } else {\r
dc361cc5 536 //\r
05c0e3cb 537 // No proxy offer is received, the bootfile name MUST be set.\r
dc361cc5 538 //\r
05c0e3cb 539 ASSERT (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
dc361cc5 540 }\r
541 }\r
542\r
543 if (!EFI_ERROR (Status)) {\r
544 //\r
545 // Everything is OK, set the flag and copy the DHCP packets.\r
546 //\r
547 Mode = Private->PxeBc.Mode;\r
548 Offer = &SelectedOffer->Packet.Offer;\r
549\r
550 //\r
551 // The discover packet is already copied, just set flag here.\r
552 //\r
553 Mode->DhcpDiscoverValid = TRUE;\r
554\r
555 Ack = &Private->Dhcp4Ack.Packet.Ack;\r
556 if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BOOTP) {\r
557 //\r
558 // Other type of ACK is already cached. Bootp is special that we should\r
559 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.\r
560 //\r
471342bb 561 Status = PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Offer);\r
dc361cc5 562 }\r
563\r
564 PxeBcParseCachedDhcpPacket (&Private->Dhcp4Ack);\r
565\r
566 Mode->DhcpAckReceived = TRUE;\r
567\r
568 //\r
569 // Copy the dhcp ack.\r
570 //\r
e48e37fc 571 CopyMem (&Mode->DhcpAck, &Ack->Dhcp4, Ack->Length);\r
dc361cc5 572 }\r
573\r
574 return Status;\r
575}\r
576\r
577\r
578/**\r
f737cfb9 579 Cache the Dhcp4 packet offer, Parse and validate each option of the packet.\r
dc361cc5 580\r
f737cfb9 581 @param Private Pointer to PxeBc private data.\r
582 @param RcvdOffer Pointer to the received Dhcp proxy offer packet.\r
dc361cc5 583\r
471342bb
FS
584 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
585 @retval Others Operation failed.\r
586\r
dc361cc5 587**/\r
471342bb 588EFI_STATUS\r
dc361cc5 589PxeBcCacheDhcpOffer (\r
590 IN PXEBC_PRIVATE_DATA *Private,\r
591 IN EFI_DHCP4_PACKET *RcvdOffer\r
592 )\r
593{\r
594 PXEBC_CACHED_DHCP4_PACKET *CachedOffer;\r
595 EFI_DHCP4_PACKET *Offer;\r
596 UINT8 OfferType;\r
471342bb 597 EFI_STATUS Status;\r
dc361cc5 598\r
599 CachedOffer = &Private->Dhcp4Offers[Private->NumOffers];\r
600 Offer = &CachedOffer->Packet.Offer;\r
601\r
602 //\r
603 // Cache the orignal dhcp packet\r
604 //\r
471342bb
FS
605 Status = PxeBcCopyEfiDhcp4Packet (Offer, RcvdOffer);\r
606 if (EFI_ERROR(Status)) {\r
607 return Status;\r
608 }\r
dc361cc5 609\r
610 //\r
611 // Parse and validate the options (including dhcp option and vendor option)\r
612 //\r
613 if (!PxeBcParseCachedDhcpPacket (CachedOffer)) {\r
471342bb 614 return EFI_ABORTED;\r
dc361cc5 615 }\r
616\r
617 OfferType = CachedOffer->OfferType;\r
379db4ac 618 if (OfferType >= DHCP4_PACKET_TYPE_MAX) {\r
471342bb 619 return EFI_ABORTED;\r
379db4ac 620 }\r
dc361cc5 621\r
622 if (OfferType == DHCP4_PACKET_TYPE_BOOTP) {\r
623\r
624 if (Private->BootpIndex != 0) {\r
625 //\r
626 // Only cache the first bootp offer, discard others.\r
627 //\r
471342bb 628 return EFI_ABORTED;\r
dc361cc5 629 } else {\r
630 //\r
631 // Take as a dhcp only offer, but record index specifically.\r
632 //\r
633 Private->BootpIndex = Private->NumOffers + 1;\r
634 }\r
635 } else {\r
636\r
637 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
638 //\r
639 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.\r
640 //\r
05c0e3cb 641 Private->GotProxyOffer = TRUE;\r
642\r
dc361cc5 643 if (OfferType == DHCP4_PACKET_TYPE_BINL) {\r
644 //\r
645 // Cache all binl offers.\r
646 //\r
647 Private->BinlIndex[Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]] = Private->NumOffers;\r
648 Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]++;\r
649 } else if (Private->ProxyIndex[OfferType] != 0) {\r
650 //\r
651 // Only cache the first pxe10/wfm11a offers each, discard the others.\r
652 //\r
471342bb 653 return EFI_ABORTED;\r
dc361cc5 654 } else {\r
655 //\r
656 // Record index of the proxy dhcp offer with type other than binl.\r
657 //\r
658 Private->ProxyIndex[OfferType] = Private->NumOffers + 1;\r
659 }\r
660 } else {\r
661 //\r
662 // It's a dhcp offer with your address.\r
663 //\r
894d038a 664 ASSERT (Private->ServerCount[OfferType] < PXEBC_MAX_OFFER_NUM);\r
dc361cc5 665 Private->OfferIndex[OfferType][Private->ServerCount[OfferType]] = Private->NumOffers;\r
666 Private->ServerCount[OfferType]++;\r
667 }\r
668 }\r
669\r
670 //\r
671 // Count the accepted offers.\r
672 //\r
673 Private->NumOffers++;\r
471342bb
FS
674\r
675 return EFI_SUCCESS;\r
dc361cc5 676}\r
677\r
14e84fd8
ZL
678/**\r
679 Switch the Ip4 policy to static.\r
680\r
681 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
682\r
683 @retval EFI_SUCCESS The policy is already configured to static.\r
684 @retval Others Other error as indicated..\r
685\r
686**/\r
687EFI_STATUS\r
d1102dba 688PxeBcSetIp4Policy (\r
14e84fd8
ZL
689 IN PXEBC_PRIVATE_DATA *Private\r
690 )\r
691{\r
692 EFI_STATUS Status;\r
693 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
694 EFI_IP4_CONFIG2_POLICY Policy;\r
695 UINTN DataSize;\r
696\r
697 Ip4Config2 = Private->Ip4Config2;\r
698 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
699 Status = Ip4Config2->GetData (\r
700 Ip4Config2,\r
701 Ip4Config2DataTypePolicy,\r
702 &DataSize,\r
703 &Policy\r
704 );\r
705 if (EFI_ERROR (Status)) {\r
706 return Status;\r
707 }\r
d1102dba 708\r
14e84fd8
ZL
709 if (Policy != Ip4Config2PolicyStatic) {\r
710 Policy = Ip4Config2PolicyStatic;\r
711 Status= Ip4Config2->SetData (\r
712 Ip4Config2,\r
713 Ip4Config2DataTypePolicy,\r
714 sizeof (EFI_IP4_CONFIG2_POLICY),\r
715 &Policy\r
716 );\r
717 if (EFI_ERROR (Status)) {\r
718 return Status;\r
d1102dba 719 }\r
14e84fd8
ZL
720 }\r
721\r
722 return EFI_SUCCESS;\r
723}\r
724\r
dc361cc5 725\r
726/**\r
f737cfb9 727 Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.\r
728 If the proxy does not exist, try offers with bootfile.\r
e2851998 729\r
f737cfb9 730 @param Private Pointer to PxeBc private data.\r
dc361cc5 731\r
dc361cc5 732**/\r
733VOID\r
734PxeBcSelectOffer (\r
735 IN PXEBC_PRIVATE_DATA *Private\r
736 )\r
737{\r
738 UINT32 Index;\r
739 UINT32 OfferIndex;\r
740 EFI_DHCP4_PACKET *Offer;\r
dc361cc5 741\r
742 Private->SelectedOffer = 0;\r
743\r
744 if (Private->SortOffers) {\r
745 //\r
746 // Select offer according to the priority\r
747 //\r
748 if (Private->ServerCount[DHCP4_PACKET_TYPE_PXE10] > 0) {\r
749 //\r
750 // DHCP with PXE10\r
751 //\r
752 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_PXE10][0] + 1;\r
753\r
754 } else if (Private->ServerCount[DHCP4_PACKET_TYPE_WFM11A] > 0) {\r
755 //\r
756 // DHCP with WfM\r
757 //\r
758 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_WFM11A][0] + 1;\r
759\r
760 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_PXE10] > 0) &&\r
761 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
762 ) {\r
763 //\r
764 // DHCP only and proxy DHCP with PXE10\r
765 //\r
766 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
767 Private->ProxyOfferType = DHCP4_PACKET_TYPE_PXE10;\r
768\r
769 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_WFM11A] > 0) &&\r
770 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
771 ) {\r
772 //\r
773 // DHCP only and proxy DHCP with WfM\r
774 //\r
775 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
776 Private->ProxyOfferType = DHCP4_PACKET_TYPE_WFM11A;\r
777\r
778 } else if (Private->ServerCount[DHCP4_PACKET_TYPE_BINL] > 0) {\r
779 //\r
780 // DHCP with BINL\r
781 //\r
782 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_BINL][0] + 1;\r
783\r
784 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL] > 0) &&\r
785 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
786 ) {\r
787 //\r
788 // DHCP only and proxy DHCP with BINL\r
789 //\r
790 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
791 Private->ProxyOfferType = DHCP4_PACKET_TYPE_BINL;\r
792\r
793 } else {\r
794 //\r
795 // Try offers with bootfile\r
796 //\r
797 for (Index = 0; Index < Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY]; Index++) {\r
798 //\r
799 // Select the first DHCP only offer with bootfile\r
800 //\r
801 OfferIndex = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][Index];\r
802 if (Private->Dhcp4Offers[OfferIndex].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
803 Private->SelectedOffer = OfferIndex + 1;\r
804 break;\r
805 }\r
806 }\r
807\r
808 if (Private->SelectedOffer == 0) {\r
809 //\r
810 // Select the Bootp reply with bootfile if any\r
811 //\r
812 Private->SelectedOffer = Private->BootpIndex;\r
813 }\r
814 }\r
815 } else {\r
816 //\r
817 // Try the offers in the received order.\r
818 //\r
dc361cc5 819 for (Index = 0; Index < Private->NumOffers; Index++) {\r
820\r
821 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
822\r
823 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
824 //\r
825 // Skip proxy offers\r
826 //\r
827 continue;\r
828 }\r
829\r
830 if ((Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) &&\r
05c0e3cb 831 ((!Private->GotProxyOffer) && (Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))) {\r
dc361cc5 832 //\r
833 // DHCP only offer but no proxy offer received and no bootfile option in this offer\r
834 //\r
835 continue;\r
836 }\r
837\r
838 Private->SelectedOffer = Index + 1;\r
839 break;\r
840 }\r
841 }\r
842}\r
843\r
844\r
845/**\r
f737cfb9 846 Callback routine.\r
e2851998 847\r
f737cfb9 848 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
849 to intercept events that occurred in the configuration process. This structure\r
850 provides advanced control of each state transition of the DHCP process. The\r
851 returned status code determines the behavior of the EFI DHCPv4 Protocol driver.\r
852 There are three possible returned values, which are described in the following\r
853 table.\r
854\r
855 @param This Pointer to the EFI DHCPv4 Protocol instance that is used to\r
856 configure this callback function.\r
857 @param Context Pointer to the context that is initialized by\r
858 EFI_DHCP4_PROTOCOL.Configure().\r
859 @param CurrentState The current operational state of the EFI DHCPv4 Protocol\r
860 driver.\r
861 @param Dhcp4Event The event that occurs in the current state, which usually means a\r
862 state transition.\r
863 @param Packet The DHCP packet that is going to be sent or already received.\r
864 @param NewPacket The packet that is used to replace the above Packet.\r
865\r
866 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
867 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
868 driver will continue to wait for more DHCPOFFER packets until the retry\r
869 timeout expires.\r
870 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and\r
871 return to the Dhcp4Init or Dhcp4InitReboot state.\r
dc361cc5 872\r
873**/\r
874EFI_STATUS\r
6d3ea23f 875EFIAPI\r
dc361cc5 876PxeBcDhcpCallBack (\r
877 IN EFI_DHCP4_PROTOCOL * This,\r
878 IN VOID *Context,\r
879 IN EFI_DHCP4_STATE CurrentState,\r
880 IN EFI_DHCP4_EVENT Dhcp4Event,\r
881 IN EFI_DHCP4_PACKET * Packet OPTIONAL,\r
882 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
883 )\r
884{\r
885 PXEBC_PRIVATE_DATA *Private;\r
886 EFI_PXE_BASE_CODE_MODE *Mode;\r
887 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
888 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
889 UINT16 Value;\r
890 EFI_STATUS Status;\r
891 BOOLEAN Received;\r
982a9eae 892 EFI_DHCP4_HEADER *DhcpHeader;\r
dc361cc5 893\r
894 if ((Dhcp4Event != Dhcp4RcvdOffer) &&\r
895 (Dhcp4Event != Dhcp4SelectOffer) &&\r
896 (Dhcp4Event != Dhcp4SendDiscover) &&\r
982a9eae 897 (Dhcp4Event != Dhcp4RcvdAck) &&\r
898 (Dhcp4Event != Dhcp4SendRequest)) {\r
dc361cc5 899 return EFI_SUCCESS;\r
900 }\r
901\r
902 Private = (PXEBC_PRIVATE_DATA *) Context;\r
903 Mode = Private->PxeBc.Mode;\r
904 Callback = Private->PxeBcCallback;\r
905\r
906 //\r
907 // Override the Maximum DHCP Message Size.\r
908 //\r
909 MaxMsgSize = PxeBcParseExtendOptions (\r
910 Packet->Dhcp4.Option,\r
911 GET_OPTION_BUFFER_LEN (Packet),\r
ac6c3d90 912 DHCP4_TAG_MAXMSG\r
dc361cc5 913 );\r
914 if (MaxMsgSize != NULL) {\r
915 Value = HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
e48e37fc 916 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
dc361cc5 917 }\r
918\r
919 if ((Dhcp4Event != Dhcp4SelectOffer) && (Callback != NULL)) {\r
920 Received = (BOOLEAN) ((Dhcp4Event == Dhcp4RcvdOffer) || (Dhcp4Event == Dhcp4RcvdAck));\r
921 Status = Callback->Callback (\r
922 Callback,\r
923 Private->Function,\r
924 Received,\r
925 Packet->Length,\r
926 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4\r
927 );\r
928 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
929 return EFI_ABORTED;\r
930 }\r
931 }\r
932\r
933 Status = EFI_SUCCESS;\r
934\r
935 switch (Dhcp4Event) {\r
936\r
937 case Dhcp4SendDiscover:\r
982a9eae 938 case Dhcp4SendRequest:\r
4f6b33b4
FS
939 if (Packet->Length > PXEBC_DHCP4_MAX_PACKET_SIZE) {\r
940 //\r
941 // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
942 //\r
943 Status = EFI_ABORTED;\r
944 break;\r
945 }\r
d1102dba 946\r
982a9eae 947 if (Mode->SendGUID) {\r
948 //\r
949 // send the system GUID instead of the MAC address as the hardware address\r
950 // in the DHCP packet header.\r
951 //\r
952 DhcpHeader = &Packet->Dhcp4.Header;\r
953\r
57b301b5 954 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) DhcpHeader->ClientHwAddr))) {\r
982a9eae 955 //\r
956 // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
957 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
958 // GUID not yet set - send all 0's to show not programable\r
959 //\r
3fad4a95 960 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
982a9eae 961 ZeroMem (DhcpHeader->ClientHwAddr, sizeof (EFI_GUID));\r
962 }\r
963\r
c9325700 964 DhcpHeader->HwAddrLen = (UINT8) sizeof (EFI_GUID);\r
982a9eae 965 }\r
966\r
967 if (Dhcp4Event == Dhcp4SendDiscover) {\r
968 //\r
969 // Cache the dhcp discover packet, of which some information will be used later.\r
970 //\r
971 CopyMem (Mode->DhcpDiscover.Raw, &Packet->Dhcp4, Packet->Length);\r
972 }\r
dc361cc5 973\r
974 break;\r
975\r
976 case Dhcp4RcvdOffer:\r
977 Status = EFI_NOT_READY;\r
4f6b33b4
FS
978 if (Packet->Length > PXEBC_DHCP4_MAX_PACKET_SIZE) {\r
979 //\r
980 // Ignore the incoming Offers which exceed the maximum length.\r
981 //\r
982 break;\r
983 }\r
d1102dba 984\r
dc361cc5 985 if (Private->NumOffers < PXEBC_MAX_OFFER_NUM) {\r
986 //\r
987 // Cache the dhcp offers in Private->Dhcp4Offers[]\r
471342bb 988 // If error happens, just ignore this packet and continue to wait more offer.\r
dc361cc5 989 //\r
990 PxeBcCacheDhcpOffer (Private, Packet);\r
991 }\r
992\r
993 break;\r
994\r
995 case Dhcp4SelectOffer:\r
996 //\r
997 // Select an offer, if succeeded, Private->SelectedOffer points to\r
998 // the index of the selected one.\r
999 //\r
1000 PxeBcSelectOffer (Private);\r
1001\r
1002 if (Private->SelectedOffer == 0) {\r
1003 Status = EFI_ABORTED;\r
1004 } else {\r
1005 *NewPacket = &Private->Dhcp4Offers[Private->SelectedOffer - 1].Packet.Offer;\r
1006 }\r
1007\r
1008 break;\r
1009\r
1010 case Dhcp4RcvdAck:\r
1011 //\r
1012 // Cache Ack\r
1013 //\r
1014 ASSERT (Private->SelectedOffer != 0);\r
1015\r
471342bb
FS
1016 Status = PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Packet);\r
1017 if (EFI_ERROR (Status)) {\r
1018 return EFI_ABORTED;\r
1019 }\r
dc361cc5 1020 break;\r
12f3a142 1021\r
1022 default:\r
1023 break;\r
dc361cc5 1024 }\r
1025\r
1026 return Status;\r
1027}\r
1028\r
1029\r
1030/**\r
f737cfb9 1031 Initialize the DHCP options and build the option list.\r
dc361cc5 1032\r
f737cfb9 1033 @param Private Pointer to PxeBc private data.\r
1034 @param OptList Pointer to a DHCP option list.\r
e2851998 1035\r
1036 @param IsDhcpDiscover Discover dhcp option or not.\r
dc361cc5 1037\r
f737cfb9 1038 @return The index item number of the option list.\r
dc361cc5 1039\r
1040**/\r
1041UINT32\r
1042PxeBcBuildDhcpOptions (\r
1043 IN PXEBC_PRIVATE_DATA *Private,\r
1044 IN EFI_DHCP4_PACKET_OPTION **OptList,\r
1045 IN BOOLEAN IsDhcpDiscover\r
1046 )\r
1047{\r
1048 UINT32 Index;\r
1049 PXEBC_DHCP4_OPTION_ENTRY OptEnt;\r
1050 UINT16 Value;\r
dc361cc5 1051\r
1052 Index = 0;\r
1053 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Private->OptionBuffer;\r
1054\r
1055 if (!IsDhcpDiscover) {\r
1056 //\r
1057 // Append message type.\r
1058 //\r
ac6c3d90 1059 OptList[Index]->OpCode = DHCP4_TAG_MSG_TYPE;\r
dc361cc5 1060 OptList[Index]->Length = 1;\r
1061 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;\r
1062 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;\r
1063 Index++;\r
1064 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1065\r
1066 //\r
1067 // Append max message size.\r
1068 //\r
ac6c3d90 1069 OptList[Index]->OpCode = DHCP4_TAG_MAXMSG;\r
c9325700 1070 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);\r
dc361cc5 1071 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;\r
1072 Value = NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
e48e37fc 1073 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));\r
dc361cc5 1074 Index++;\r
1075 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1076 }\r
1077 //\r
1078 // Parameter request list option.\r
1079 //\r
ac6c3d90 1080 OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;\r
dc361cc5 1081 OptList[Index]->Length = 35;\r
1082 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
ac6c3d90
ZL
1083 OptEnt.Para->ParaList[0] = DHCP4_TAG_NETMASK;\r
1084 OptEnt.Para->ParaList[1] = DHCP4_TAG_TIME_OFFSET;\r
1085 OptEnt.Para->ParaList[2] = DHCP4_TAG_ROUTER;\r
1086 OptEnt.Para->ParaList[3] = DHCP4_TAG_TIME_SERVER;\r
1087 OptEnt.Para->ParaList[4] = DHCP4_TAG_NAME_SERVER;\r
1088 OptEnt.Para->ParaList[5] = DHCP4_TAG_DNS_SERVER;\r
1089 OptEnt.Para->ParaList[6] = DHCP4_TAG_HOSTNAME;\r
1090 OptEnt.Para->ParaList[7] = DHCP4_TAG_BOOTFILE_LEN;\r
1091 OptEnt.Para->ParaList[8] = DHCP4_TAG_DOMAINNAME;\r
1092 OptEnt.Para->ParaList[9] = DHCP4_TAG_ROOTPATH;\r
1093 OptEnt.Para->ParaList[10] = DHCP4_TAG_EXTEND_PATH;\r
1094 OptEnt.Para->ParaList[11] = DHCP4_TAG_EMTU;\r
1095 OptEnt.Para->ParaList[12] = DHCP4_TAG_TTL;\r
1096 OptEnt.Para->ParaList[13] = DHCP4_TAG_BROADCAST;\r
1097 OptEnt.Para->ParaList[14] = DHCP4_TAG_NIS_DOMAIN;\r
1098 OptEnt.Para->ParaList[15] = DHCP4_TAG_NIS_SERVER;\r
1099 OptEnt.Para->ParaList[16] = DHCP4_TAG_NTP_SERVER;\r
1100 OptEnt.Para->ParaList[17] = DHCP4_TAG_VENDOR;\r
1101 OptEnt.Para->ParaList[18] = DHCP4_TAG_REQUEST_IP;\r
1102 OptEnt.Para->ParaList[19] = DHCP4_TAG_LEASE;\r
1103 OptEnt.Para->ParaList[20] = DHCP4_TAG_SERVER_ID;\r
1104 OptEnt.Para->ParaList[21] = DHCP4_TAG_T1;\r
1105 OptEnt.Para->ParaList[22] = DHCP4_TAG_T2;\r
1106 OptEnt.Para->ParaList[23] = DHCP4_TAG_VENDOR_CLASS_ID;\r
1107 OptEnt.Para->ParaList[24] = DHCP4_TAG_TFTP;\r
1108 OptEnt.Para->ParaList[25] = DHCP4_TAG_BOOTFILE;\r
1109 OptEnt.Para->ParaList[26] = DHCP4_TAG_UUID;\r
dc361cc5 1110 OptEnt.Para->ParaList[27] = 0x80;\r
1111 OptEnt.Para->ParaList[28] = 0x81;\r
1112 OptEnt.Para->ParaList[29] = 0x82;\r
1113 OptEnt.Para->ParaList[30] = 0x83;\r
1114 OptEnt.Para->ParaList[31] = 0x84;\r
1115 OptEnt.Para->ParaList[32] = 0x85;\r
1116 OptEnt.Para->ParaList[33] = 0x86;\r
1117 OptEnt.Para->ParaList[34] = 0x87;\r
1118 Index++;\r
1119 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1120\r
1121 //\r
1122 // Append UUID/Guid-based client identifier option\r
1123 //\r
ac6c3d90 1124 OptList[Index]->OpCode = DHCP4_TAG_UUID;\r
c9325700 1125 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID);\r
dc361cc5 1126 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
1127 OptEnt.Uuid->Type = 0;\r
1128 Index++;\r
1129 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1130\r
57b301b5 1131 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {\r
dc361cc5 1132 //\r
1133 // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
1134 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
1135 // GUID not yet set - send all 0's to show not programable\r
1136 //\r
3fad4a95 1137 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
dc361cc5 1138 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
1139 }\r
1140\r
1141 //\r
1142 // Append client network device interface option\r
1143 //\r
ac6c3d90 1144 OptList[Index]->OpCode = DHCP4_TAG_UNDI;\r
c9325700 1145 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);\r
dc361cc5 1146 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
169a3461 1147 if (Private->Nii != NULL) {\r
1148 OptEnt.Undi->Type = Private->Nii->Type;\r
1149 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
1150 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
1151 } else {\r
1152 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
1153 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
1154 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
1155 }\r
dc361cc5 1156\r
1157 Index++;\r
1158 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1159\r
1160 //\r
1161 // Append client system architecture option\r
1162 //\r
ac6c3d90 1163 OptList[Index]->OpCode = DHCP4_TAG_ARCH;\r
c9325700 1164 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);\r
dc361cc5 1165 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
ecd28a61 1166 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);\r
e48e37fc 1167 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
dc361cc5 1168 Index++;\r
1169 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1170\r
1171 //\r
1172 // Append client system architecture option\r
1173 //\r
ac6c3d90 1174 OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;\r
c9325700 1175 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);\r
dc361cc5 1176 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
e48e37fc 1177 CopyMem (OptEnt.Clid, DEFAULT_CLASS_ID_DATA, sizeof (PXEBC_DHCP4_OPTION_CLID));\r
ecd28a61 1178 CvtNum (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE, OptEnt.Clid->ArchitectureType, sizeof (OptEnt.Clid->ArchitectureType));\r
169a3461 1179\r
1180 if (Private->Nii != NULL) {\r
e2851998 1181 //\r
169a3461 1182 // If NII protocol exists, update DHCP option data\r
1183 //\r
1184 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
1185 CvtNum (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
1186 CvtNum (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
1187 }\r
1188\r
dc361cc5 1189 Index++;\r
1190\r
1191 return Index;\r
1192}\r
1193\r
1194\r
1195/**\r
f737cfb9 1196 Discover the boot of service and initialize the vendor option if exists.\r
1197\r
1198 @param Private Pointer to PxeBc private data.\r
1199 @param Type PxeBc option boot item type\r
1200 @param Layer PxeBc option boot item layer\r
1201 @param UseBis Use BIS or not\r
e2851998 1202 @param DestIp Ip address for server\r
1203 @param IpCount The total count of the server ip address\r
f737cfb9 1204 @param SrvList Server list\r
1205 @param IsDiscv Discover the vendor or not\r
1206 @param Reply The dhcp4 packet of Pxe reply\r
1207\r
1208 @retval EFI_SUCCESS Operation succeeds.\r
1209 @retval EFI_OUT_OF_RESOURCES Allocate memory pool failed.\r
1210 @retval EFI_NOT_FOUND There is no vendor option exists.\r
e2851998 1211 @retval EFI_TIMEOUT Send Pxe Discover time out.\r
1212\r
dc361cc5 1213**/\r
1214EFI_STATUS\r
1215PxeBcDiscvBootService (\r
1216 IN PXEBC_PRIVATE_DATA * Private,\r
1217 IN UINT16 Type,\r
1218 IN UINT16 *Layer,\r
1219 IN BOOLEAN UseBis,\r
1220 IN EFI_IP_ADDRESS * DestIp,\r
1221 IN UINT16 IpCount,\r
1222 IN EFI_PXE_BASE_CODE_SRVLIST * SrvList,\r
1223 IN BOOLEAN IsDiscv,\r
1224 OUT EFI_DHCP4_PACKET * Reply OPTIONAL\r
1225 )\r
1226{\r
1227 EFI_PXE_BASE_CODE_UDP_PORT Sport;\r
1228 EFI_PXE_BASE_CODE_MODE *Mode;\r
1229 EFI_DHCP4_PROTOCOL *Dhcp4;\r
1230 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;\r
1231 BOOLEAN IsBCast;\r
1232 EFI_STATUS Status;\r
1233 UINT16 RepIndex;\r
1234 UINT16 SrvIndex;\r
1235 UINT16 TryIndex;\r
1236 EFI_DHCP4_LISTEN_POINT ListenPoint;\r
1237 EFI_DHCP4_PACKET *Response;\r
1238 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
1239 UINT32 OptCount;\r
1240 EFI_DHCP4_PACKET_OPTION *PxeOpt;\r
1241 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;\r
1242 UINT8 VendorOptLen;\r
982a9eae 1243 EFI_DHCP4_HEADER *DhcpHeader;\r
434ce3fe 1244 UINT32 Xid;\r
982a9eae 1245\r
dc361cc5 1246 Mode = Private->PxeBc.Mode;\r
1247 Dhcp4 = Private->Dhcp4;\r
1248 Status = EFI_SUCCESS;\r
1249\r
1250 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
1251\r
1252 if (DestIp == NULL) {\r
1253 Sport = PXEBC_DHCP4_S_PORT;\r
1254 IsBCast = TRUE;\r
1255 } else {\r
1256 Sport = PXEBC_BS_DISCOVER_PORT;\r
1257 IsBCast = FALSE;\r
1258 }\r
1259\r
1260 if (!UseBis && Layer != NULL) {\r
1261 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1262 }\r
1263\r
1264 OptCount = PxeBcBuildDhcpOptions (Private, OptList, FALSE);\r
1265\r
1266 if (IsDiscv) {\r
944bf8db 1267 ASSERT (Layer != NULL);\r
dc361cc5 1268 //\r
1269 // Add vendor option of PXE_BOOT_ITEM\r
1270 //\r
c9325700 1271 VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);\r
e48e37fc 1272 OptList[OptCount] = AllocatePool (VendorOptLen);\r
dc361cc5 1273 if (OptList[OptCount] == NULL) {\r
1274 return EFI_OUT_OF_RESOURCES;\r
1275 }\r
1276\r
ac6c3d90 1277 OptList[OptCount]->OpCode = DHCP4_TAG_VENDOR;\r
dc361cc5 1278 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);\r
1279 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;\r
1280 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;\r
c9325700 1281 PxeOpt->Length = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);\r
dc361cc5 1282 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;\r
1283 PxeBootItem->Type = HTONS (Type);\r
1284 PxeBootItem->Layer = HTONS (*Layer);\r
ac6c3d90 1285 PxeOpt->Data[PxeOpt->Length] = DHCP4_TAG_EOP;\r
dc361cc5 1286\r
1287 OptCount++;\r
1288 }\r
1289\r
1290 Status = Dhcp4->Build (Dhcp4, &Private->SeedPacket, 0, NULL, OptCount, OptList, &Token.Packet);\r
1291\r
1292 if (IsDiscv) {\r
766c7483 1293 FreePool (OptList[OptCount - 1]);\r
dc361cc5 1294 }\r
1295\r
1296 if (EFI_ERROR (Status)) {\r
1297 return Status;\r
1298 }\r
1299\r
982a9eae 1300 DhcpHeader = &Token.Packet->Dhcp4.Header;\r
1301 if (Mode->SendGUID) {\r
57b301b5 1302 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) DhcpHeader->ClientHwAddr))) {\r
982a9eae 1303 //\r
1304 // GUID not yet set - send all 0's to show not programable\r
1305 //\r
3fad4a95 1306 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
982a9eae 1307 ZeroMem (DhcpHeader->ClientHwAddr, sizeof (EFI_GUID));\r
1308 }\r
1309\r
c9325700 1310 DhcpHeader->HwAddrLen = (UINT8) sizeof (EFI_GUID);\r
982a9eae 1311 }\r
e2851998 1312\r
434ce3fe 1313 Xid = NET_RANDOM (NetRandomInitSeed ());\r
1314 Token.Packet->Dhcp4.Header.Xid = HTONL(Xid);\r
1204fe83 1315 Token.Packet->Dhcp4.Header.Reserved = HTONS((UINT16) ((IsBCast) ? 0x8000 : 0));\r
e48e37fc 1316 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1317\r
1318 Token.RemotePort = Sport;\r
1319\r
434ce3fe 1320 if (IsBCast) {\r
e48e37fc 1321 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
dc361cc5 1322 } else {\r
e48e37fc 1323 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1324 }\r
1325\r
e48e37fc 1326 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1327\r
1328 if (!IsBCast) {\r
1329 Token.ListenPointCount = 1;\r
1330 Token.ListenPoints = &ListenPoint;\r
1331 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;\r
e48e37fc 1332 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));\r
1333 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));\r
dc361cc5 1334 }\r
1335 //\r
1336 // Send Pxe Discover\r
1337 //\r
1338 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {\r
1339\r
434ce3fe 1340 Token.TimeoutValue = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);\r
1341 Token.Packet->Dhcp4.Header.Seconds = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));\r
dc361cc5 1342\r
1343 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
1344\r
1345 if (Token.Status != EFI_TIMEOUT) {\r
1346 break;\r
1347 }\r
1348 }\r
1349\r
0bf47d3d 1350 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {\r
1351 //\r
1352 // No server response our PXE request\r
1353 //\r
1354 Status = EFI_TIMEOUT;\r
1355 }\r
1356\r
dc361cc5 1357 if (!EFI_ERROR (Status)) {\r
1358 //\r
1359 // Find Pxe Reply\r
1360 //\r
1361 RepIndex = 0;\r
1362 SrvIndex = 0;\r
1363 Response = Token.ResponseList;\r
1364\r
1365 while (RepIndex < Token.ResponseCount) {\r
471342bb
FS
1366 if (Response->Length > PXEBC_DHCP4_MAX_PACKET_SIZE) {\r
1367 SrvIndex = 0;\r
1368 RepIndex++;\r
1369 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1370 continue;\r
1371 }\r
dc361cc5 1372\r
1373 while (SrvIndex < IpCount) {\r
1374\r
1375 if (SrvList[SrvIndex].AcceptAnyResponse) {\r
1376 break;\r
1377 }\r
1378\r
1379 if ((SrvList[SrvIndex].Type == Type) && EFI_IP4_EQUAL (&(Response->Dhcp4.Header.ServerAddr), &(Private->ServerIp))) {\r
1380 break;\r
1381 }\r
1382\r
1383 SrvIndex++;\r
1384 }\r
1385\r
1386 if ((IpCount != SrvIndex) || (IpCount == 0)) {\r
1387 break;\r
1388 }\r
1389\r
1390 SrvIndex = 0;\r
1391 RepIndex++;\r
dc361cc5 1392 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1393 }\r
1394\r
1395 if (RepIndex < Token.ResponseCount) {\r
1396\r
1397 if (Reply != NULL) {\r
471342bb
FS
1398 Status = PxeBcCopyEfiDhcp4Packet (Reply, Response);\r
1399 if (EFI_ERROR(Status)) {\r
1400 goto ON_EXIT;\r
1401 }\r
dc361cc5 1402 }\r
1403\r
1404 if (IsDiscv) {\r
e48e37fc 1405 CopyMem (&(Mode->PxeDiscover), &(Token.Packet->Dhcp4), Token.Packet->Length);\r
dc361cc5 1406 Mode->PxeDiscoverValid = TRUE;\r
1407\r
e48e37fc 1408 CopyMem (Mode->PxeReply.Raw, &Response->Dhcp4, Response->Length);\r
dc361cc5 1409 Mode->PxeReplyReceived = TRUE;\r
1410 }\r
1411 } else {\r
1412 Status = EFI_NOT_FOUND;\r
1413 }\r
471342bb 1414 }\r
dc361cc5 1415\r
471342bb
FS
1416ON_EXIT:\r
1417 //\r
1418 // free the responselist\r
1419 //\r
1420 if (Token.ResponseList != NULL) {\r
1421 FreePool (Token.ResponseList);\r
dc361cc5 1422 }\r
1423 //\r
1424 // Free the dhcp packet\r
1425 //\r
471342bb
FS
1426 if (Token.Packet != NULL) {\r
1427 FreePool (Token.Packet);\r
1428 }\r
dc361cc5 1429\r
1430 return Status;\r
1431}\r
1432\r
1433\r
1434/**\r
f737cfb9 1435 Parse interested dhcp options.\r
dc361cc5 1436\r
f737cfb9 1437 @param Buffer Pointer to the dhcp options packet.\r
1438 @param Length The length of the dhcp options.\r
1439 @param OptTag The option OpCode.\r
dc361cc5 1440\r
e2851998 1441 @return NULL if the buffer length is 0 and OpCode is not\r
ac6c3d90 1442 DHCP4_TAG_EOP, or the pointer to the buffer.\r
dc361cc5 1443\r
1444**/\r
1445EFI_DHCP4_PACKET_OPTION *\r
1446PxeBcParseExtendOptions (\r
1447 IN UINT8 *Buffer,\r
1448 IN UINT32 Length,\r
1449 IN UINT8 OptTag\r
1450 )\r
1451{\r
1452 EFI_DHCP4_PACKET_OPTION *Option;\r
1453 UINT32 Offset;\r
1454\r
1455 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
1456 Offset = 0;\r
1457\r
ac6c3d90 1458 while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {\r
dc361cc5 1459\r
1460 if (Option->OpCode == OptTag) {\r
1461\r
1462 return Option;\r
1463 }\r
1464\r
ac6c3d90 1465 if (Option->OpCode == DHCP4_TAG_PAD) {\r
dc361cc5 1466 Offset++;\r
1467 } else {\r
1468 Offset += Option->Length + 2;\r
1469 }\r
1470\r
1471 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
1472 }\r
1473\r
1474 return NULL;\r
1475}\r
1476\r
1477\r
1478/**\r
1479 This function is to parse and check vendor options.\r
1480\r
1481 @param Dhcp4Option Pointer to dhcp options\r
1482 @param VendorOption Pointer to vendor options\r
1483\r
f737cfb9 1484 @return TRUE if valid for vendor options, or FALSE.\r
dc361cc5 1485\r
1486**/\r
1487BOOLEAN\r
1488PxeBcParseVendorOptions (\r
1489 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,\r
1490 IN PXEBC_VENDOR_OPTION *VendorOption\r
1491 )\r
1492{\r
1493 UINT32 *BitMap;\r
1494 UINT8 VendorOptionLen;\r
1495 EFI_DHCP4_PACKET_OPTION *PxeOption;\r
1496 UINT8 Offset;\r
1497\r
1498 BitMap = VendorOption->BitMap;\r
1499 VendorOptionLen = Dhcp4Option->Length;\r
1500 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];\r
1501 Offset = 0;\r
1502\r
ac6c3d90 1503 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != DHCP4_TAG_EOP)) {\r
dc361cc5 1504 //\r
1505 // Parse every Vendor Option and set its BitMap\r
1506 //\r
1507 switch (PxeOption->OpCode) {\r
1508\r
1509 case PXEBC_VENDOR_TAG_MTFTP_IP:\r
1510\r
e48e37fc 1511 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1512 break;\r
1513\r
1514 case PXEBC_VENDOR_TAG_MTFTP_CPORT:\r
1515\r
e48e37fc 1516 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));\r
dc361cc5 1517 break;\r
1518\r
1519 case PXEBC_VENDOR_TAG_MTFTP_SPORT:\r
1520\r
e48e37fc 1521 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));\r
dc361cc5 1522 break;\r
1523\r
1524 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:\r
1525\r
1526 VendorOption->MtftpTimeout = *PxeOption->Data;\r
1527 break;\r
1528\r
1529 case PXEBC_VENDOR_TAG_MTFTP_DELAY:\r
1530\r
1531 VendorOption->MtftpDelay = *PxeOption->Data;\r
1532 break;\r
1533\r
1534 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:\r
1535\r
1536 VendorOption->DiscoverCtrl = *PxeOption->Data;\r
1537 break;\r
1538\r
1539 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:\r
1540\r
e48e37fc 1541 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1542 break;\r
1543\r
1544 case PXEBC_VENDOR_TAG_BOOT_SERVERS:\r
1545\r
1546 VendorOption->BootSvrLen = PxeOption->Length;\r
1547 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;\r
1548 break;\r
1549\r
1550 case PXEBC_VENDOR_TAG_BOOT_MENU:\r
1551\r
1552 VendorOption->BootMenuLen = PxeOption->Length;\r
1553 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;\r
1554 break;\r
1555\r
1556 case PXEBC_VENDOR_TAG_MENU_PROMPT:\r
1557\r
1558 VendorOption->MenuPromptLen = PxeOption->Length;\r
1559 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data;\r
1560 break;\r
1561\r
1562 case PXEBC_VENDOR_TAG_MCAST_ALLOC:\r
1563\r
e48e37fc 1564 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
1565 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));\r
1566 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));\r
dc361cc5 1567 break;\r
1568\r
1569 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:\r
1570\r
1571 VendorOption->CredTypeLen = PxeOption->Length;\r
1572 VendorOption->CredType = (UINT32 *) PxeOption->Data;\r
1573 break;\r
1574\r
1575 case PXEBC_VENDOR_TAG_BOOT_ITEM:\r
1576\r
e48e37fc 1577 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));\r
1578 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));\r
dc361cc5 1579 break;\r
1580 }\r
1581\r
1582 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);\r
1583\r
ac6c3d90 1584 if (PxeOption->OpCode == DHCP4_TAG_PAD) {\r
dc361cc5 1585 Offset++;\r
1586 } else {\r
1587 Offset = (UINT8) (Offset + PxeOption->Length + 2);\r
1588 }\r
1589\r
1590 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);\r
1591 }\r
1592\r
1593 //\r
1594 // FixMe, return falas if invalid of any vendor option\r
1595 //\r
1596\r
1597 return TRUE;\r
1598}\r
1599\r
1600\r
1601/**\r
f737cfb9 1602 This function display boot item detail.\r
dc361cc5 1603\r
e2851998 1604 If the length of the boot item string over 70 Char, just display 70 Char.\r
1605\r
f737cfb9 1606 @param Str Pointer to a string (boot item string).\r
1607 @param Len The length of string.\r
dc361cc5 1608\r
dc361cc5 1609**/\r
1610VOID\r
1611PxeBcDisplayBootItem (\r
1612 IN UINT8 *Str,\r
1613 IN UINT8 Len\r
1614 )\r
1615{\r
1616 UINT8 Tmp;\r
1617\r
1618 Len = (UINT8) MIN (70, Len);\r
1619 Tmp = Str[Len];\r
1620 Str[Len] = 0;\r
1621 AsciiPrint ("%a \n", Str);\r
1622 Str[Len] = Tmp;\r
1623}\r
1624\r
1625\r
1626/**\r
f737cfb9 1627 Choose the boot prompt.\r
dc361cc5 1628\r
f737cfb9 1629 @param Private Pointer to PxeBc private data.\r
dc361cc5 1630\r
f737cfb9 1631 @retval EFI_SUCCESS Select boot prompt done.\r
e2851998 1632 @retval EFI_TIMEOUT Select boot prompt time out.\r
f737cfb9 1633 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.\r
1634 @retval EFI_ABORTED User cancel the operation.\r
1635 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.\r
e2851998 1636\r
dc361cc5 1637**/\r
1638EFI_STATUS\r
1639PxeBcSelectBootPrompt (\r
1640 IN PXEBC_PRIVATE_DATA *Private\r
1641 )\r
1642{\r
1643 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1644 PXEBC_VENDOR_OPTION *VendorOpt;\r
1645 EFI_EVENT TimeoutEvent;\r
1646 EFI_EVENT DescendEvent;\r
1647 EFI_INPUT_KEY InputKey;\r
1648 EFI_STATUS Status;\r
1649 UINT8 Timeout;\r
1650 UINT8 *Prompt;\r
1651 UINT8 PromptLen;\r
1652 INT32 SecCol;\r
1653 INT32 SecRow;\r
1654\r
1655 TimeoutEvent = NULL;\r
1656 DescendEvent = NULL;\r
1657\r
1658 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1659\r
1660 Packet = &Private->ProxyOffer;\r
1661 } else {\r
1662\r
1663 Packet = &Private->Dhcp4Ack;\r
1664 }\r
1665\r
1666 if (Packet->OfferType != DHCP4_PACKET_TYPE_PXE10) {\r
1667 return EFI_NOT_FOUND;\r
1668 }\r
1669\r
1670 VendorOpt = &Packet->PxeVendorOption;\r
30a95d4d 1671 //\r
d1102dba
LG
1672 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options (Full\r
1673 // List), we must not consider a boot prompt or boot menu if all of the\r
e3cf3c20 1674 // following hold:\r
1675 // - the PXE_DISCOVERY_CONTROL PXE tag is present inside the Vendor Options\r
1676 // (=43) DHCP tag, and\r
d1102dba 1677 // - the PXE_DISCOVERY_CONTROL PXE tag has bit 3 set, and\r
e3cf3c20 1678 // - a boot file name has been presented with DHCP option 67.\r
30a95d4d 1679 //\r
1680 if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) &&\r
1681 Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
1682 return EFI_ABORTED;\r
1683 }\r
dc361cc5 1684\r
1685 if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
1686 return EFI_SUCCESS;\r
1687 }\r
1688\r
1689 Timeout = VendorOpt->MenuPrompt->Timeout;\r
1690 Prompt = VendorOpt->MenuPrompt->Prompt;\r
1691 PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);\r
1692\r
1693 if (Timeout == 0) {\r
1694 return EFI_SUCCESS;\r
1695 }\r
1696\r
1697 if (Timeout == 255) {\r
1698 return EFI_TIMEOUT;\r
1699 }\r
1700\r
1701 Status = gBS->CreateEvent (\r
1702 EVT_TIMER,\r
1703 TPL_CALLBACK,\r
1704 NULL,\r
1705 NULL,\r
1706 &TimeoutEvent\r
1707 );\r
1708\r
1709 if (EFI_ERROR (Status)) {\r
1710 return Status;\r
1711 }\r
1712\r
1713 Status = gBS->SetTimer (\r
1714 TimeoutEvent,\r
1715 TimerRelative,\r
e719fcb5 1716 MultU64x32 (Timeout, TICKS_PER_SECOND)\r
dc361cc5 1717 );\r
1718\r
1719 if (EFI_ERROR (Status)) {\r
1720 goto ON_EXIT;\r
1721 }\r
1722\r
1723 Status = gBS->CreateEvent (\r
1724 EVT_TIMER,\r
1725 TPL_CALLBACK,\r
1726 NULL,\r
1727 NULL,\r
1728 &DescendEvent\r
1729 );\r
1730\r
1731 if (EFI_ERROR (Status)) {\r
1732 goto ON_EXIT;\r
1733 }\r
1734\r
1735 Status = gBS->SetTimer (\r
1736 DescendEvent,\r
1737 TimerPeriodic,\r
1738 TICKS_PER_SECOND\r
1739 );\r
1740\r
1741 if (EFI_ERROR (Status)) {\r
1742 goto ON_EXIT;\r
1743 }\r
1744\r
1745 SecCol = gST->ConOut->Mode->CursorColumn;\r
1746 SecRow = gST->ConOut->Mode->CursorRow;\r
1747\r
1748 PxeBcDisplayBootItem (Prompt, PromptLen);\r
1749\r
1750 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1751 AsciiPrint ("(%d) ", Timeout--);\r
1752\r
1753 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
1754\r
1755 if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {\r
1756 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1757 AsciiPrint ("(%d) ", Timeout--);\r
1758 }\r
1759\r
1760 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1761\r
1762 gBS->Stall (10 * TICKS_PER_MS);\r
1763 continue;\r
1764 }\r
1765\r
1766 if (InputKey.ScanCode == 0) {\r
1767\r
1768 switch (InputKey.UnicodeChar) {\r
1769 case CTRL ('c'):\r
1770 Status = EFI_ABORTED;\r
1771 break;\r
1772\r
1773 case CTRL ('m'):\r
1774 case 'm':\r
1775 case 'M':\r
1776 Status = EFI_TIMEOUT;\r
1777 break;\r
1778\r
1779 default:\r
1780 continue;\r
1781 }\r
1782 } else {\r
1783\r
1784 switch (InputKey.ScanCode) {\r
1785 case SCAN_F8:\r
1786 Status = EFI_TIMEOUT;\r
1787 break;\r
1788\r
1789 case SCAN_ESC:\r
1790 Status = EFI_ABORTED;\r
1791 break;\r
1792\r
1793 default:\r
1794 continue;\r
1795 }\r
1796 }\r
1797\r
1798 break;\r
1799 }\r
1800\r
1801 gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);\r
1802\r
1803ON_EXIT:\r
1804\r
1805 if (DescendEvent != NULL) {\r
1806 gBS->CloseEvent (DescendEvent);\r
1807 }\r
1808\r
1809 if (TimeoutEvent != NULL) {\r
1810 gBS->CloseEvent (TimeoutEvent);\r
1811 }\r
1812\r
1813 return Status;\r
1814}\r
1815\r
1816\r
1817/**\r
f737cfb9 1818 Select the boot menu.\r
dc361cc5 1819\r
f737cfb9 1820 @param Private Pointer to PxeBc private data.\r
1821 @param Type The type of the menu.\r
1822 @param UseDefaultItem Use default item or not.\r
e2851998 1823\r
f737cfb9 1824 @retval EFI_ABORTED User cancel operation.\r
1825 @retval EFI_SUCCESS Select the boot menu success.\r
e2851998 1826 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.\r
dc361cc5 1827\r
1828**/\r
1829EFI_STATUS\r
1830PxeBcSelectBootMenu (\r
1831 IN PXEBC_PRIVATE_DATA *Private,\r
1832 OUT UINT16 *Type,\r
1833 IN BOOLEAN UseDefaultItem\r
1834 )\r
1835{\r
1836 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
e2851998 1837 PXEBC_VENDOR_OPTION *VendorOpt;\r
dc361cc5 1838 EFI_INPUT_KEY InputKey;\r
1839 UINT8 MenuSize;\r
1840 UINT8 MenuNum;\r
1841 INT32 TopRow;\r
1842 UINT16 Select;\r
1843 UINT16 LastSelect;\r
1844 UINT8 Index;\r
1845 BOOLEAN Finish;\r
1846 CHAR8 Blank[70];\r
1847 PXEBC_BOOT_MENU_ENTRY *MenuItem;\r
1848 PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MAX_MENU_NUM];\r
1849\r
1850 Finish = FALSE;\r
ef931b31 1851 Select = 0;\r
dc361cc5 1852 Index = 0;\r
1853 *Type = 0;\r
1854\r
1855 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1856\r
1857 Packet = &Private->ProxyOffer;\r
1858 } else {\r
1859\r
1860 Packet = &Private->Dhcp4Ack;\r
1861 }\r
1862\r
1863 ASSERT (Packet->OfferType == DHCP4_PACKET_TYPE_PXE10);\r
1864\r
1865 VendorOpt = &Packet->PxeVendorOption;\r
1866\r
1867 if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {\r
1868 return EFI_SUCCESS;\r
1869 }\r
1870\r
1871 SetMem (Blank, sizeof(Blank), ' ');\r
1872\r
1873 MenuSize = VendorOpt->BootMenuLen;\r
1874 MenuItem = VendorOpt->BootMenu;\r
1875\r
894d038a 1876 if (MenuSize == 0) {\r
1877 return EFI_NOT_READY;\r
1878 }\r
1879\r
dc361cc5 1880 while (MenuSize > 0) {\r
7b0ae7e8 1881 MenuArray[Index++] = MenuItem;\r
dc361cc5 1882 MenuSize = (UINT8) (MenuSize - (MenuItem->DescLen + 3));\r
1883 MenuItem = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);\r
7b0ae7e8 1884 if (Index >= PXEBC_MAX_MENU_NUM) {\r
894d038a 1885 break;\r
1886 }\r
dc361cc5 1887 }\r
1888\r
1889 if (UseDefaultItem) {\r
894d038a 1890 *Type = MenuArray[0]->Type;\r
58bba940 1891 *Type = NTOHS (*Type);\r
dc361cc5 1892 return EFI_SUCCESS;\r
1893 }\r
1894\r
1895 MenuNum = Index;\r
1896\r
1897 for (Index = 0; Index < MenuNum; Index++) {\r
1898 PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);\r
1899 }\r
1900\r
1901 TopRow = gST->ConOut->Mode->CursorRow - MenuNum;\r
1902\r
1903 do {\r
7b0ae7e8 1904 ASSERT (Select < PXEBC_MAX_MENU_NUM);\r
dc361cc5 1905 //\r
1906 // highlight selected row\r
1907 //\r
1908 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
1909 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);\r
1910 Blank[MenuArray[Select]->DescLen] = 0;\r
1911 AsciiPrint ("%a\r", Blank);\r
1912 PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);\r
1913 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1914 LastSelect = Select;\r
1915\r
1916 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1917 gBS->Stall (10 * TICKS_PER_MS);\r
1918 }\r
1919\r
ef931b31 1920 if (InputKey.ScanCode == 0) {\r
dc361cc5 1921 switch (InputKey.UnicodeChar) {\r
1922 case CTRL ('c'):\r
1923 InputKey.ScanCode = SCAN_ESC;\r
1924 break;\r
1925\r
1926 case CTRL ('j'): /* linefeed */\r
1927 case CTRL ('m'): /* return */\r
1928 Finish = TRUE;\r
1929 break;\r
1930\r
1931 case CTRL ('i'): /* tab */\r
1932 case ' ':\r
1933 case 'd':\r
1934 case 'D':\r
1935 InputKey.ScanCode = SCAN_DOWN;\r
1936 break;\r
1937\r
1938 case CTRL ('h'): /* backspace */\r
1939 case 'u':\r
1940 case 'U':\r
1941 InputKey.ScanCode = SCAN_UP;\r
1942 break;\r
1943\r
1944 default:\r
1945 InputKey.ScanCode = 0;\r
1946 }\r
1947 }\r
1948\r
1949 switch (InputKey.ScanCode) {\r
1950 case SCAN_LEFT:\r
1951 case SCAN_UP:\r
f737cfb9 1952 if (Select > 0) {\r
dc361cc5 1953 --Select;\r
1954 }\r
1955\r
1956 break;\r
1957\r
1958 case SCAN_DOWN:\r
1959 case SCAN_RIGHT:\r
1960 if (++Select == MenuNum) {\r
1961 --Select;\r
1962 }\r
1963\r
1964 break;\r
1965\r
1966 case SCAN_PAGE_UP:\r
1967 case SCAN_HOME:\r
1968 Select = 0;\r
1969 break;\r
1970\r
1971 case SCAN_PAGE_DOWN:\r
1972 case SCAN_END:\r
1973 Select = (UINT16) (MenuNum - 1);\r
1974 break;\r
1975\r
1976 case SCAN_ESC:\r
1977 return EFI_ABORTED;\r
1978 }\r
1979\r
1980 /* unhighlight last selected row */\r
1981 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
1982 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);\r
1983 Blank[MenuArray[LastSelect]->DescLen] = 0;\r
1984 AsciiPrint ("%a\r", Blank);\r
1985 PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);\r
1986 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1987 } while (!Finish);\r
1988\r
29a4f92d 1989 ASSERT (Select < PXEBC_MAX_MENU_NUM);\r
1990\r
dc361cc5 1991 //\r
1992 // Swap the byte order\r
1993 //\r
58bba940 1994 CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16));\r
1995 *Type = NTOHS (*Type);\r
dc361cc5 1996\r
1997 return EFI_SUCCESS;\r
1998}\r
1999\r