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