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