3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Support for PxeBc dhcp functions
24 #include "PxeBcImpl.h"
27 // This is a map from the interested DHCP4 option tags' index to the tag value.
29 UINT8 mInterestedDhcp4Tags
[PXEBC_DHCP4_TAG_INDEX_MAX
] = {
30 PXEBC_DHCP4_TAG_BOOTFILE_LEN
,
31 PXEBC_DHCP4_TAG_VENDOR
,
32 PXEBC_DHCP4_TAG_OVERLOAD
,
33 PXEBC_DHCP4_TAG_MSG_TYPE
,
34 PXEBC_DHCP4_TAG_SERVER_ID
,
35 PXEBC_DHCP4_TAG_CLASS_ID
,
36 PXEBC_DHCP4_TAG_BOOTFILE
41 GC_NOTO: Add function description
43 @param Seed GC_NOTO: add argument description
44 @param Udp4 GC_NOTO: add argument description
46 @return GC_NOTO: add return values
51 IN EFI_DHCP4_PACKET
*Seed
,
52 IN EFI_UDP4_PROTOCOL
*Udp4
55 EFI_SIMPLE_NETWORK_MODE Mode
;
56 EFI_DHCP4_HEADER
*Header
;
58 Udp4
->GetModeData (Udp4
, NULL
, NULL
, NULL
, &Mode
);
60 Seed
->Size
= sizeof (EFI_DHCP4_PACKET
);
61 Seed
->Length
= sizeof (Seed
->Dhcp4
);
63 Header
= &Seed
->Dhcp4
.Header
;
65 NetZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
66 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
67 Header
->HwType
= Mode
.IfType
;
68 Header
->HwAddrLen
= (UINT8
) Mode
.HwAddressSize
;
69 NetCopyMem (Header
->ClientHwAddr
, &Mode
.CurrentAddress
, Header
->HwAddrLen
);
71 Seed
->Dhcp4
.Magik
= PXEBC_DHCP4_MAGIC
;
72 Seed
->Dhcp4
.Option
[0] = PXEBC_DHCP4_TAG_EOP
;
77 GC_NOTO: Add function description
79 @param Dst GC_NOTO: add argument description
80 @param Src GC_NOTO: add argument description
82 @return GC_NOTO: add return values
86 PxeBcCopyEfiDhcp4Packet (
87 IN EFI_DHCP4_PACKET
*Dst
,
88 IN EFI_DHCP4_PACKET
*Src
91 ASSERT (Dst
->Size
>= Src
->Length
);
93 NetCopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
94 Dst
->Length
= Src
->Length
;
99 GC_NOTO: Add function description
101 @param Private GC_NOTO: add argument description
102 @param OfferIndex GC_NOTO: add argument description
104 @return GC_NOTO: add return values
108 PxeBcCopyProxyOffer (
109 IN PXEBC_PRIVATE_DATA
*Private
,
113 EFI_PXE_BASE_CODE_MODE
*Mode
;
114 EFI_DHCP4_PACKET
*Offer
;
116 ASSERT (OfferIndex
< Private
->NumOffers
);
118 Mode
= Private
->PxeBc
.Mode
;
119 Offer
= &Private
->Dhcp4Offers
[OfferIndex
].Packet
.Offer
;
121 PxeBcCopyEfiDhcp4Packet (&Private
->ProxyOffer
.Packet
.Offer
, Offer
);
122 NetCopyMem (&Mode
->ProxyOffer
, &Offer
->Dhcp4
, Offer
->Length
);
123 Mode
->ProxyOfferReceived
= TRUE
;
125 PxeBcParseCachedDhcpPacket (&Private
->ProxyOffer
);
130 Parse the cached dhcp packet.
132 @param CachedPacket Pointer to cached dhcp packet
134 @return TRUE : Success to parse and validation
135 @return FALSE : Fail to parse or validation
139 PxeBcParseCachedDhcpPacket (
140 IN PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
143 EFI_DHCP4_PACKET
*Offer
;
144 EFI_DHCP4_PACKET_OPTION
**Options
;
145 EFI_DHCP4_PACKET_OPTION
*Option
;
149 CachedPacket
->IsPxeOffer
= FALSE
;
150 NetZeroMem (CachedPacket
->Dhcp4Option
, sizeof (CachedPacket
->Dhcp4Option
));
151 NetZeroMem (&CachedPacket
->PxeVendorOption
, sizeof (CachedPacket
->PxeVendorOption
));
153 Offer
= &CachedPacket
->Packet
.Offer
;
154 Options
= CachedPacket
->Dhcp4Option
;
157 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.
159 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
160 Options
[Index
] = PxeBcParseExtendOptions (
162 GET_OPTION_BUFFER_LEN (Offer
),
163 mInterestedDhcp4Tags
[Index
]
168 // Check whether is an offer with PXEClient or not.
170 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
171 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
172 (NetCompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
174 CachedPacket
->IsPxeOffer
= TRUE
;
178 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
180 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
181 if (CachedPacket
->IsPxeOffer
&& (Option
!= NULL
)) {
183 if (!PxeBcParseVendorOptions (Option
, &CachedPacket
->PxeVendorOption
)) {
189 // Check whether bootfilename/serverhostname overloaded (See details in dhcp spec).
190 // If overloaded, parse this buffer as nested dhcp options, or just parse bootfilename/
191 // serverhostname option.
193 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
194 if ((Option
!= NULL
) && (Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
)) {
196 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = PxeBcParseExtendOptions (
197 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
198 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
199 PXEBC_DHCP4_TAG_BOOTFILE
202 } else if ((Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) &&
203 (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
205 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
206 // And do not count dhcp option header, or else will destory the serverhostname.
208 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*) (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
209 EFI_FIELD_OFFSET (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
214 // Determine offer type of the dhcp packet.
216 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
217 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
219 // It's a bootp offer
221 Option
= CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
222 if (Option
== NULL
) {
224 // bootp offer without bootfilename, discard it.
229 OfferType
= DHCP4_PACKET_TYPE_BOOTP
;
233 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
235 // It's a pxe10 offer with PXEClient and discover vendor option.
237 OfferType
= DHCP4_PACKET_TYPE_PXE10
;
238 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
240 // It's a wfm11a offer with PXEClient and mtftp vendor option, and
241 // return false since mtftp not supported currently.
246 // WFM11A, make sure bootfile is present
248 if (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) {
250 // Discard this offer.
255 OfferType
= DHCP4_PACKET_TYPE_WFM11A
;
259 // If the binl offer with only PXEClient.
261 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
265 CachedPacket
->OfferType
= OfferType
;
272 GC_NOTO: Add function description
274 @param Private GC_NOTO: add argument description
275 @param Index GC_NOTO: add argument description
277 @return GC_NOTO: add return values
282 IN PXEBC_PRIVATE_DATA
*Private
,
286 EFI_DHCP4_PACKET
*Offer
;
287 EFI_IP_ADDRESS ServerIp
;
289 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
290 EFI_DHCP4_PACKET
*Reply
;
292 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
294 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
295 if (Offer
->Dhcp4
.Header
.ServerAddr
.Addr
[0] == 0) {
297 // next server ip address is zero, use server id option instead.
301 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
302 sizeof (EFI_IPv4_ADDRESS
)
306 // use next server ip address.
308 NetCopyMem (&ServerIp
.Addr
[0], &Offer
->Dhcp4
.Header
.ServerAddr
, sizeof (EFI_IPv4_ADDRESS
));
311 CachedPacket
= &Private
->ProxyOffer
;
312 Reply
= &CachedPacket
->Packet
.Offer
;
314 Status
= PxeBcDiscvBootService (
325 if (EFI_ERROR (Status
)) {
329 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
333 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
334 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
336 // This BINL ack doesn't have discovery options set or bootfile name
342 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
343 NetCopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
350 GC_NOTO: Add function description
352 @param Private GC_NOTO: add argument description
353 @param OfferIndex GC_NOTO: add argument description
355 @return GC_NOTO: add return values
360 IN PXEBC_PRIVATE_DATA
*Private
,
361 OUT UINT32
*OfferIndex
366 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
368 *OfferIndex
= Private
->BinlIndex
[Index
];
370 // Try this BINL proxy offer
372 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
382 GC_NOTO: Add function description
384 @param Private GC_NOTO: add argument description
386 @return GC_NOTO: add return values
390 PxeBcCheckSelectedOffer (
391 IN PXEBC_PRIVATE_DATA
*Private
394 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
395 EFI_DHCP4_PACKET_OPTION
**Options
;
397 EFI_DHCP4_PACKET
*Offer
;
398 UINT32 ProxyOfferIndex
;
400 EFI_PXE_BASE_CODE_MODE
*Mode
;
401 EFI_DHCP4_PACKET
*Ack
;
403 ASSERT (Private
->SelectedOffer
!= 0);
405 Status
= EFI_SUCCESS
;
406 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
407 Options
= SelectedOffer
->Dhcp4Option
;
409 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
411 // The addresses are acquired from a BINL dhcp offer, try BINL to get
414 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
415 Status
= EFI_NO_RESPONSE
;
417 } else if ((SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
418 (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
420 // The selected offer to finish the D.O.R.A. is a DHCP only offer and
421 // bootfile name is not provided in this offer, we need try proxy offers
422 // to get the bootfile name or the discovery info
424 ProxyOfferIndex
= Private
->NumOffers
;
426 if (Private
->SortOffers
) {
428 // Choose proxy offer from the type we stored during DHCP offer selection
430 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
432 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
434 // We buffer all received BINL proxy offers, try them all one by one
436 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
437 Status
= EFI_NO_RESPONSE
;
441 // For other types, only one proxy offer is buffered.
443 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
447 // Choose proxy offer in the received order.
449 Status
= EFI_NO_RESPONSE
;
451 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
453 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
454 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
456 // Skip non proxy dhcp offers.
461 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
465 if (!PxeBcTryBinl (Private
, Index
)) {
467 // Failed, skip to the next offer
473 Status
= EFI_SUCCESS
;
478 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
480 // Copy the proxy offer to Mode and set the flag
482 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
486 if (!EFI_ERROR (Status
)) {
488 // Everything is OK, set the flag and copy the DHCP packets.
490 Mode
= Private
->PxeBc
.Mode
;
491 Offer
= &SelectedOffer
->Packet
.Offer
;
494 // The discover packet is already copied, just set flag here.
496 Mode
->DhcpDiscoverValid
= TRUE
;
498 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
499 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
501 // Other type of ACK is already cached. Bootp is special that we should
502 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
504 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
507 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
509 Mode
->DhcpAckReceived
= TRUE
;
512 // Copy the dhcp ack.
514 NetCopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
522 GC_NOTO: Add function description
524 @param Private GC_NOTO: add argument description
525 @param RcvdOffer GC_NOTO: add argument description
527 @return GC_NOTO: add return values
531 PxeBcCacheDhcpOffer (
532 IN PXEBC_PRIVATE_DATA
*Private
,
533 IN EFI_DHCP4_PACKET
*RcvdOffer
536 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
537 EFI_DHCP4_PACKET
*Offer
;
540 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
541 Offer
= &CachedOffer
->Packet
.Offer
;
544 // Cache the orignal dhcp packet
546 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
549 // Parse and validate the options (including dhcp option and vendor option)
551 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
555 OfferType
= CachedOffer
->OfferType
;
557 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
559 if (Private
->BootpIndex
!= 0) {
561 // Only cache the first bootp offer, discard others.
566 // Take as a dhcp only offer, but record index specifically.
568 Private
->BootpIndex
= Private
->NumOffers
+ 1;
572 if (IS_PROXY_DHCP_OFFER (Offer
)) {
574 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
576 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
578 // Cache all binl offers.
580 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
581 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
582 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
584 // Only cache the first pxe10/wfm11a offers each, discard the others.
589 // Record index of the proxy dhcp offer with type other than binl.
591 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
595 // It's a dhcp offer with your address.
597 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
598 Private
->ServerCount
[OfferType
]++;
603 // Count the accepted offers.
605 Private
->NumOffers
++;
610 GC_NOTO: Add function description
612 @param Private GC_NOTO: add argument description
614 @return GC_NOTO: add return values
619 IN PXEBC_PRIVATE_DATA
*Private
624 EFI_DHCP4_PACKET
*Offer
;
625 BOOLEAN GotProxyOffer
;
627 Private
->SelectedOffer
= 0;
629 if (Private
->SortOffers
) {
631 // Select offer according to the priority
633 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
637 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
639 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
643 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
645 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
646 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
649 // DHCP only and proxy DHCP with PXE10
651 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
652 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
654 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
655 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
658 // DHCP only and proxy DHCP with WfM
660 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
661 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
663 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
667 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
669 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
670 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
673 // DHCP only and proxy DHCP with BINL
675 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
676 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
680 // Try offers with bootfile
682 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
684 // Select the first DHCP only offer with bootfile
686 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
687 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
688 Private
->SelectedOffer
= OfferIndex
+ 1;
693 if (Private
->SelectedOffer
== 0) {
695 // Select the Bootp reply with bootfile if any
697 Private
->SelectedOffer
= Private
->BootpIndex
;
702 // Try the offers in the received order.
704 GotProxyOffer
= FALSE
;
705 for (Index
= 0; Index
< DHCP4_PACKET_TYPE_MAX
; Index
++) {
707 GotProxyOffer
= (BOOLEAN
) (Private
->ProxyIndex
[Index
] > 0);
713 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
715 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
717 if (IS_PROXY_DHCP_OFFER (Offer
)) {
724 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
725 ((!GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
727 // DHCP only offer but no proxy offer received and no bootfile option in this offer
732 Private
->SelectedOffer
= Index
+ 1;
740 GC_NOTO: Add function description
742 @param This GC_NOTO: add argument description
743 @param Context GC_NOTO: add argument description
744 @param CurrentState GC_NOTO: add argument description
745 @param Dhcp4Event GC_NOTO: add argument description
746 @param Packet GC_NOTO: add argument description
747 @param NewPacket GC_NOTO: add argument description
749 @retval EFI_SUCCESS GC_NOTO: Add description for return value
750 @retval EFI_ABORTED GC_NOTO: Add description for return value
755 IN EFI_DHCP4_PROTOCOL
* This
,
757 IN EFI_DHCP4_STATE CurrentState
,
758 IN EFI_DHCP4_EVENT Dhcp4Event
,
759 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
760 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
763 PXEBC_PRIVATE_DATA
*Private
;
764 EFI_PXE_BASE_CODE_MODE
*Mode
;
765 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
766 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
771 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
772 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
773 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
774 (Dhcp4Event
!= Dhcp4RcvdAck
)) {
778 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
779 Mode
= Private
->PxeBc
.Mode
;
780 Callback
= Private
->PxeBcCallback
;
783 // Override the Maximum DHCP Message Size.
785 MaxMsgSize
= PxeBcParseExtendOptions (
786 Packet
->Dhcp4
.Option
,
787 GET_OPTION_BUFFER_LEN (Packet
),
788 PXEBC_DHCP4_TAG_MAXMSG
790 if (MaxMsgSize
!= NULL
) {
791 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
792 NetCopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
795 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
796 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
797 Status
= Callback
->Callback (
802 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
804 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
809 Status
= EFI_SUCCESS
;
811 switch (Dhcp4Event
) {
813 case Dhcp4SendDiscover
:
815 // Cache the dhcp discover packet, of which some information will be used later.
817 NetCopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
822 Status
= EFI_NOT_READY
;
823 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
825 // Cache the dhcp offers in Private->Dhcp4Offers[]
827 PxeBcCacheDhcpOffer (Private
, Packet
);
832 case Dhcp4SelectOffer
:
834 // Select an offer, if succeeded, Private->SelectedOffer points to
835 // the index of the selected one.
837 PxeBcSelectOffer (Private
);
839 if (Private
->SelectedOffer
== 0) {
840 Status
= EFI_ABORTED
;
842 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
851 ASSERT (Private
->SelectedOffer
!= 0);
853 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
862 GC_NOTO: Add function description
864 @param Private GC_NOTO: add argument description
865 @param OptList GC_NOTO: add argument description
866 @param IsDhcpDiscover GC_NOTO: add argument description
868 @return GC_NOTO: add return values
872 PxeBcBuildDhcpOptions (
873 IN PXEBC_PRIVATE_DATA
*Private
,
874 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
875 IN BOOLEAN IsDhcpDiscover
879 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
881 CHAR8
*SystemSerialNumber
;
884 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
886 if (!IsDhcpDiscover
) {
888 // Append message type.
890 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
891 OptList
[Index
]->Length
= 1;
892 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
893 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
895 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
898 // Append max message size.
900 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
901 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
902 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
903 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
904 NetCopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
906 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
909 // Parameter request list option.
911 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
912 OptList
[Index
]->Length
= 35;
913 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
914 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
915 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
916 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
917 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
918 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
919 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
920 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
921 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
922 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
923 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
924 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
925 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
926 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
927 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
928 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
929 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
930 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
931 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
932 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
933 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
934 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
935 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
936 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
937 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
938 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
939 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
940 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
941 OptEnt
.Para
->ParaList
[27] = 0x80;
942 OptEnt
.Para
->ParaList
[28] = 0x81;
943 OptEnt
.Para
->ParaList
[29] = 0x82;
944 OptEnt
.Para
->ParaList
[30] = 0x83;
945 OptEnt
.Para
->ParaList
[31] = 0x84;
946 OptEnt
.Para
->ParaList
[32] = 0x85;
947 OptEnt
.Para
->ParaList
[33] = 0x86;
948 OptEnt
.Para
->ParaList
[34] = 0x87;
950 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
953 // Append UUID/Guid-based client identifier option
955 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
956 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
957 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
958 OptEnt
.Uuid
->Type
= 0;
960 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
962 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
964 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
965 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
966 // GUID not yet set - send all 0's to show not programable
968 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
972 // Append client network device interface option
974 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
975 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
976 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
977 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
978 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
979 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
982 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
985 // Append client system architecture option
987 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
988 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
989 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
990 Value
= HTONS (SYS_ARCH
);
991 NetCopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
993 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
996 // Append client system architecture option
998 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
999 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
1000 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1001 NetCopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1002 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1003 NetCopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1004 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1005 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1013 GC_NOTO: Add function description
1015 @param Private GC_NOTO: add argument description
1016 @param Type GC_NOTO: add argument description
1017 @param Layer GC_NOTO: add argument description
1018 @param UseBis GC_NOTO: add argument description
1019 @param DestIp GC_NOTO: add argument description
1020 @param IpCount GC_NOTO: add argument description
1021 @param SrvList GC_NOTO: add argument description
1022 @param IsDiscv GC_NOTO: add argument description
1023 @param Reply GC_NOTO: add argument description
1025 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value
1029 PxeBcDiscvBootService (
1030 IN PXEBC_PRIVATE_DATA
* Private
,
1034 IN EFI_IP_ADDRESS
* DestIp
,
1036 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1038 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1041 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1042 EFI_PXE_BASE_CODE_MODE
*Mode
;
1043 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1044 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1050 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1051 EFI_DHCP4_PACKET
*Response
;
1052 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1054 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1055 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1058 Mode
= Private
->PxeBc
.Mode
;
1059 Dhcp4
= Private
->Dhcp4
;
1060 Status
= EFI_SUCCESS
;
1062 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1064 if (DestIp
== NULL
) {
1065 Sport
= PXEBC_DHCP4_S_PORT
;
1068 Sport
= PXEBC_BS_DISCOVER_PORT
;
1072 if (!UseBis
&& Layer
!= NULL
) {
1073 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1076 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1080 // Add vendor option of PXE_BOOT_ITEM
1082 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1083 OptList
[OptCount
] = NetAllocatePool (VendorOptLen
);
1084 if (OptList
[OptCount
] == NULL
) {
1085 return EFI_OUT_OF_RESOURCES
;
1088 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1089 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1090 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1091 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1092 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1093 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1094 PxeBootItem
->Type
= HTONS (Type
);
1095 PxeBootItem
->Layer
= HTONS (*Layer
);
1096 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1101 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1104 NetFreePool (OptList
[OptCount
- 1]);
1107 if (EFI_ERROR (Status
)) {
1111 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1112 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1113 NetCopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1115 Token
.RemotePort
= Sport
;
1117 if (DestIp
== NULL
) {
1118 NetSetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1120 NetCopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1123 NetCopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1126 Token
.ListenPointCount
= 1;
1127 Token
.ListenPoints
= &ListenPoint
;
1128 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1129 NetCopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1130 NetCopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1133 // Send Pxe Discover
1135 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1137 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1139 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1141 if (Token
.Status
!= EFI_TIMEOUT
) {
1146 if (!EFI_ERROR (Status
)) {
1152 Response
= Token
.ResponseList
;
1154 while (RepIndex
< Token
.ResponseCount
) {
1156 while (SrvIndex
< IpCount
) {
1158 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1162 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1169 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1176 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1179 if (RepIndex
< Token
.ResponseCount
) {
1181 if (Reply
!= NULL
) {
1182 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1186 NetCopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1187 Mode
->PxeDiscoverValid
= TRUE
;
1189 NetCopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1190 Mode
->PxeReplyReceived
= TRUE
;
1193 Status
= EFI_NOT_FOUND
;
1197 // free the responselist
1199 NetFreePool (Token
.ResponseList
);
1202 // Free the dhcp packet
1204 NetFreePool (Token
.Packet
);
1211 GC_NOTO: Add function description
1213 @param Buffer GC_NOTO: add argument description
1214 @param Length GC_NOTO: add argument description
1215 @param OptTag GC_NOTO: add argument description
1217 @return GC_NOTO: add return values
1220 EFI_DHCP4_PACKET_OPTION
*
1221 PxeBcParseExtendOptions (
1227 EFI_DHCP4_PACKET_OPTION
*Option
;
1230 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1233 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1235 if (Option
->OpCode
== OptTag
) {
1240 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1243 Offset
+= Option
->Length
+ 2;
1246 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1254 This function is to parse and check vendor options.
1256 @param Dhcp4Option Pointer to dhcp options
1257 @param VendorOption Pointer to vendor options
1259 @return TRUE : Valid vendor options
1260 @return FALSE : Invalid vendor options
1264 PxeBcParseVendorOptions (
1265 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1266 IN PXEBC_VENDOR_OPTION
*VendorOption
1270 UINT8 VendorOptionLen
;
1271 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1274 BitMap
= VendorOption
->BitMap
;
1275 VendorOptionLen
= Dhcp4Option
->Length
;
1276 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1279 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1281 // Parse every Vendor Option and set its BitMap
1283 switch (PxeOption
->OpCode
) {
1285 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1287 NetCopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1290 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1292 NetCopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1295 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1297 NetCopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1300 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1302 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1305 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1307 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1310 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1312 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1315 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1317 NetCopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1320 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1322 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1323 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1326 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1328 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1329 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1332 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1334 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1335 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1338 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1340 NetCopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1341 NetCopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1342 NetCopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1345 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1347 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1348 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1351 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1353 NetCopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1354 NetCopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1358 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1360 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1363 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1366 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1370 // FixMe, return falas if invalid of any vendor option
1378 GC_NOTO: Add function description
1380 @param Str GC_NOTO: add argument description
1381 @param Len GC_NOTO: add argument description
1383 @return GC_NOTO: add return values
1387 PxeBcDisplayBootItem (
1394 Len
= (UINT8
) MIN (70, Len
);
1397 AsciiPrint ("%a \n", Str
);
1403 GC_NOTO: Add function description
1405 @param Private GC_NOTO: add argument description
1407 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1408 @retval EFI_TIMEOUT GC_NOTO: Add description for return value
1412 PxeBcSelectBootPrompt (
1413 IN PXEBC_PRIVATE_DATA
*Private
1416 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1417 PXEBC_VENDOR_OPTION
*VendorOpt
;
1418 EFI_EVENT TimeoutEvent
;
1419 EFI_EVENT DescendEvent
;
1420 EFI_INPUT_KEY InputKey
;
1428 TimeoutEvent
= NULL
;
1429 DescendEvent
= NULL
;
1431 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1433 Packet
= &Private
->ProxyOffer
;
1436 Packet
= &Private
->Dhcp4Ack
;
1439 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1440 return EFI_NOT_FOUND
;
1443 VendorOpt
= &Packet
->PxeVendorOption
;
1445 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1449 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1450 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1451 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1457 if (Timeout
== 255) {
1461 Status
= gBS
->CreateEvent (
1469 if (EFI_ERROR (Status
)) {
1473 Status
= gBS
->SetTimer (
1476 Timeout
* TICKS_PER_SECOND
1479 if (EFI_ERROR (Status
)) {
1483 Status
= gBS
->CreateEvent (
1491 if (EFI_ERROR (Status
)) {
1495 Status
= gBS
->SetTimer (
1501 if (EFI_ERROR (Status
)) {
1505 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1506 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1508 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1510 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1511 AsciiPrint ("(%d) ", Timeout
--);
1513 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1515 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1516 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1517 AsciiPrint ("(%d) ", Timeout
--);
1520 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1522 gBS
->Stall (10 * TICKS_PER_MS
);
1526 if (InputKey
.ScanCode
== 0) {
1528 switch (InputKey
.UnicodeChar
) {
1530 Status
= EFI_ABORTED
;
1536 Status
= EFI_TIMEOUT
;
1544 switch (InputKey
.ScanCode
) {
1546 Status
= EFI_TIMEOUT
;
1550 Status
= EFI_ABORTED
;
1561 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1565 if (DescendEvent
!= NULL
) {
1566 gBS
->CloseEvent (DescendEvent
);
1569 if (TimeoutEvent
!= NULL
) {
1570 gBS
->CloseEvent (TimeoutEvent
);
1578 GC_NOTO: Add function description
1580 @param Private GC_NOTO: add argument description
1581 @param Type GC_NOTO: add argument description
1583 @retval EFI_ABORTED GC_NOTO: Add description for return value
1584 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1588 PxeBcSelectBootMenu (
1589 IN PXEBC_PRIVATE_DATA
*Private
,
1591 IN BOOLEAN UseDefaultItem
1594 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1595 PXEBC_VENDOR_OPTION
*VendorOpt
;
1596 EFI_INPUT_KEY InputKey
;
1605 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1606 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1613 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1615 Packet
= &Private
->ProxyOffer
;
1618 Packet
= &Private
->Dhcp4Ack
;
1621 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1623 VendorOpt
= &Packet
->PxeVendorOption
;
1625 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1629 SetMem (Blank
, sizeof(Blank
), ' ');
1631 MenuSize
= VendorOpt
->BootMenuLen
;
1632 MenuItem
= VendorOpt
->BootMenu
;
1634 while (MenuSize
> 0) {
1635 MenuArray
[Index
] = MenuItem
;
1636 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1637 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1641 if (UseDefaultItem
) {
1642 *Type
= NTOHS (MenuArray
[0]->Type
);
1648 for (Index
= 0; Index
< MenuNum
; Index
++) {
1649 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1652 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1656 // highlight selected row
1658 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1659 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1660 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1661 AsciiPrint ("%a\r", Blank
);
1662 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1663 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1664 LastSelect
= Select
;
1666 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1667 gBS
->Stall (10 * TICKS_PER_MS
);
1670 if (!InputKey
.ScanCode
) {
1671 switch (InputKey
.UnicodeChar
) {
1673 InputKey
.ScanCode
= SCAN_ESC
;
1676 case CTRL ('j'): /* linefeed */
1677 case CTRL ('m'): /* return */
1681 case CTRL ('i'): /* tab */
1685 InputKey
.ScanCode
= SCAN_DOWN
;
1688 case CTRL ('h'): /* backspace */
1691 InputKey
.ScanCode
= SCAN_UP
;
1695 InputKey
.ScanCode
= 0;
1699 switch (InputKey
.ScanCode
) {
1710 if (++Select
== MenuNum
) {
1721 case SCAN_PAGE_DOWN
:
1723 Select
= (UINT16
) (MenuNum
- 1);
1730 /* unhighlight last selected row */
1731 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1732 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1733 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1734 AsciiPrint ("%a\r", Blank
);
1735 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1736 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1740 // Swap the byte order
1742 *Type
= NTOHS (MenuArray
[Select
]->Type
);