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