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