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