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