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