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 ZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
66 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
67 Header
->HwType
= Mode
.IfType
;
68 Header
->HwAddrLen
= (UINT8
) Mode
.HwAddressSize
;
69 CopyMem (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 CopyMem (&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 CopyMem (&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 ZeroMem (CachedPacket
->Dhcp4Option
, sizeof (CachedPacket
->Dhcp4Option
));
151 ZeroMem (&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 (CompareMem (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 // If the binl offer with only PXEClient.
248 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
252 CachedPacket
->OfferType
= OfferType
;
259 GC_NOTO: Add function description
261 @param Private GC_NOTO: add argument description
262 @param Index GC_NOTO: add argument description
264 @return GC_NOTO: add return values
269 IN PXEBC_PRIVATE_DATA
*Private
,
273 EFI_DHCP4_PACKET
*Offer
;
274 EFI_IP_ADDRESS ServerIp
;
276 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
277 EFI_DHCP4_PACKET
*Reply
;
279 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
281 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
282 if (Offer
->Dhcp4
.Header
.ServerAddr
.Addr
[0] == 0) {
284 // next server ip address is zero, use server id option instead.
288 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
289 sizeof (EFI_IPv4_ADDRESS
)
293 // use next server ip address.
295 CopyMem (&ServerIp
.Addr
[0], &Offer
->Dhcp4
.Header
.ServerAddr
, sizeof (EFI_IPv4_ADDRESS
));
298 CachedPacket
= &Private
->ProxyOffer
;
299 Reply
= &CachedPacket
->Packet
.Offer
;
301 Status
= PxeBcDiscvBootService (
312 if (EFI_ERROR (Status
)) {
316 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
320 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
321 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
323 // This BINL ack doesn't have discovery options set or bootfile name
329 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
330 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
337 GC_NOTO: Add function description
339 @param Private GC_NOTO: add argument description
340 @param OfferIndex GC_NOTO: add argument description
342 @return GC_NOTO: add return values
347 IN PXEBC_PRIVATE_DATA
*Private
,
348 OUT UINT32
*OfferIndex
353 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
355 *OfferIndex
= Private
->BinlIndex
[Index
];
357 // Try this BINL proxy offer
359 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
369 GC_NOTO: Add function description
371 @param Private GC_NOTO: add argument description
373 @return GC_NOTO: add return values
377 PxeBcCheckSelectedOffer (
378 IN PXEBC_PRIVATE_DATA
*Private
381 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
382 EFI_DHCP4_PACKET_OPTION
**Options
;
384 EFI_DHCP4_PACKET
*Offer
;
385 UINT32 ProxyOfferIndex
;
387 EFI_PXE_BASE_CODE_MODE
*Mode
;
388 EFI_DHCP4_PACKET
*Ack
;
390 ASSERT (Private
->SelectedOffer
!= 0);
392 Status
= EFI_SUCCESS
;
393 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
394 Options
= SelectedOffer
->Dhcp4Option
;
396 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
398 // The addresses are acquired from a BINL dhcp offer, try BINL to get
401 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
402 Status
= EFI_NO_RESPONSE
;
404 } else if ((SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
405 (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
407 // The selected offer to finish the D.O.R.A. is a DHCP only offer and
408 // bootfile name is not provided in this offer, we need try proxy offers
409 // to get the bootfile name or the discovery info
411 ProxyOfferIndex
= Private
->NumOffers
;
413 if (Private
->SortOffers
) {
415 // Choose proxy offer from the type we stored during DHCP offer selection
417 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
419 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
421 // We buffer all received BINL proxy offers, try them all one by one
423 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
424 Status
= EFI_NO_RESPONSE
;
428 // For other types, only one proxy offer is buffered.
430 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
434 // Choose proxy offer in the received order.
436 Status
= EFI_NO_RESPONSE
;
438 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
440 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
441 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
443 // Skip non proxy dhcp offers.
448 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
452 if (!PxeBcTryBinl (Private
, Index
)) {
454 // Failed, skip to the next offer
460 Status
= EFI_SUCCESS
;
465 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
467 // Copy the proxy offer to Mode and set the flag
469 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
473 if (!EFI_ERROR (Status
)) {
475 // Everything is OK, set the flag and copy the DHCP packets.
477 Mode
= Private
->PxeBc
.Mode
;
478 Offer
= &SelectedOffer
->Packet
.Offer
;
481 // The discover packet is already copied, just set flag here.
483 Mode
->DhcpDiscoverValid
= TRUE
;
485 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
486 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
488 // Other type of ACK is already cached. Bootp is special that we should
489 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
491 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
494 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
496 Mode
->DhcpAckReceived
= TRUE
;
499 // Copy the dhcp ack.
501 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
509 GC_NOTO: Add function description
511 @param Private GC_NOTO: add argument description
512 @param RcvdOffer GC_NOTO: add argument description
514 @return GC_NOTO: add return values
518 PxeBcCacheDhcpOffer (
519 IN PXEBC_PRIVATE_DATA
*Private
,
520 IN EFI_DHCP4_PACKET
*RcvdOffer
523 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
524 EFI_DHCP4_PACKET
*Offer
;
527 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
528 Offer
= &CachedOffer
->Packet
.Offer
;
531 // Cache the orignal dhcp packet
533 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
536 // Parse and validate the options (including dhcp option and vendor option)
538 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
542 OfferType
= CachedOffer
->OfferType
;
544 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
546 if (Private
->BootpIndex
!= 0) {
548 // Only cache the first bootp offer, discard others.
553 // Take as a dhcp only offer, but record index specifically.
555 Private
->BootpIndex
= Private
->NumOffers
+ 1;
559 if (IS_PROXY_DHCP_OFFER (Offer
)) {
561 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
563 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
565 // Cache all binl offers.
567 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
568 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
569 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
571 // Only cache the first pxe10/wfm11a offers each, discard the others.
576 // Record index of the proxy dhcp offer with type other than binl.
578 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
582 // It's a dhcp offer with your address.
584 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
585 Private
->ServerCount
[OfferType
]++;
590 // Count the accepted offers.
592 Private
->NumOffers
++;
597 GC_NOTO: Add function description
599 @param Private GC_NOTO: add argument description
601 @return GC_NOTO: add return values
606 IN PXEBC_PRIVATE_DATA
*Private
611 EFI_DHCP4_PACKET
*Offer
;
612 BOOLEAN GotProxyOffer
;
614 Private
->SelectedOffer
= 0;
616 if (Private
->SortOffers
) {
618 // Select offer according to the priority
620 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
624 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
626 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
630 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
632 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
633 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
636 // DHCP only and proxy DHCP with PXE10
638 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
639 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
641 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
642 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
645 // DHCP only and proxy DHCP with WfM
647 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
648 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
650 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
654 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
656 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
657 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
660 // DHCP only and proxy DHCP with BINL
662 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
663 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
667 // Try offers with bootfile
669 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
671 // Select the first DHCP only offer with bootfile
673 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
674 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
675 Private
->SelectedOffer
= OfferIndex
+ 1;
680 if (Private
->SelectedOffer
== 0) {
682 // Select the Bootp reply with bootfile if any
684 Private
->SelectedOffer
= Private
->BootpIndex
;
689 // Try the offers in the received order.
691 GotProxyOffer
= FALSE
;
692 for (Index
= 0; Index
< DHCP4_PACKET_TYPE_MAX
; Index
++) {
694 GotProxyOffer
= (BOOLEAN
) (Private
->ProxyIndex
[Index
] > 0);
700 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
702 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
704 if (IS_PROXY_DHCP_OFFER (Offer
)) {
711 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
712 ((!GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
714 // DHCP only offer but no proxy offer received and no bootfile option in this offer
719 Private
->SelectedOffer
= Index
+ 1;
727 GC_NOTO: Add function description
729 @param This GC_NOTO: add argument description
730 @param Context GC_NOTO: add argument description
731 @param CurrentState GC_NOTO: add argument description
732 @param Dhcp4Event GC_NOTO: add argument description
733 @param Packet GC_NOTO: add argument description
734 @param NewPacket GC_NOTO: add argument description
736 @retval EFI_SUCCESS GC_NOTO: Add description for return value
737 @retval EFI_ABORTED GC_NOTO: Add description for return value
742 IN EFI_DHCP4_PROTOCOL
* This
,
744 IN EFI_DHCP4_STATE CurrentState
,
745 IN EFI_DHCP4_EVENT Dhcp4Event
,
746 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
747 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
750 PXEBC_PRIVATE_DATA
*Private
;
751 EFI_PXE_BASE_CODE_MODE
*Mode
;
752 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
753 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
758 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
759 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
760 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
761 (Dhcp4Event
!= Dhcp4RcvdAck
)) {
765 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
766 Mode
= Private
->PxeBc
.Mode
;
767 Callback
= Private
->PxeBcCallback
;
770 // Override the Maximum DHCP Message Size.
772 MaxMsgSize
= PxeBcParseExtendOptions (
773 Packet
->Dhcp4
.Option
,
774 GET_OPTION_BUFFER_LEN (Packet
),
775 PXEBC_DHCP4_TAG_MAXMSG
777 if (MaxMsgSize
!= NULL
) {
778 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
779 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
782 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
783 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
784 Status
= Callback
->Callback (
789 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
791 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
796 Status
= EFI_SUCCESS
;
798 switch (Dhcp4Event
) {
800 case Dhcp4SendDiscover
:
802 // Cache the dhcp discover packet, of which some information will be used later.
804 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
809 Status
= EFI_NOT_READY
;
810 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
812 // Cache the dhcp offers in Private->Dhcp4Offers[]
814 PxeBcCacheDhcpOffer (Private
, Packet
);
819 case Dhcp4SelectOffer
:
821 // Select an offer, if succeeded, Private->SelectedOffer points to
822 // the index of the selected one.
824 PxeBcSelectOffer (Private
);
826 if (Private
->SelectedOffer
== 0) {
827 Status
= EFI_ABORTED
;
829 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
838 ASSERT (Private
->SelectedOffer
!= 0);
840 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
849 GC_NOTO: Add function description
851 @param Private GC_NOTO: add argument description
852 @param OptList GC_NOTO: add argument description
853 @param IsDhcpDiscover GC_NOTO: add argument description
855 @return GC_NOTO: add return values
859 PxeBcBuildDhcpOptions (
860 IN PXEBC_PRIVATE_DATA
*Private
,
861 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
862 IN BOOLEAN IsDhcpDiscover
866 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
868 CHAR8
*SystemSerialNumber
;
871 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
873 if (!IsDhcpDiscover
) {
875 // Append message type.
877 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
878 OptList
[Index
]->Length
= 1;
879 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
880 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
882 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
885 // Append max message size.
887 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
888 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
889 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
890 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
891 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
893 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
896 // Parameter request list option.
898 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
899 OptList
[Index
]->Length
= 35;
900 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
901 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
902 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
903 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
904 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
905 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
906 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
907 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
908 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
909 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
910 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
911 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
912 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
913 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
914 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
915 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
916 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
917 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
918 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
919 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
920 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
921 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
922 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
923 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
924 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
925 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
926 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
927 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
928 OptEnt
.Para
->ParaList
[27] = 0x80;
929 OptEnt
.Para
->ParaList
[28] = 0x81;
930 OptEnt
.Para
->ParaList
[29] = 0x82;
931 OptEnt
.Para
->ParaList
[30] = 0x83;
932 OptEnt
.Para
->ParaList
[31] = 0x84;
933 OptEnt
.Para
->ParaList
[32] = 0x85;
934 OptEnt
.Para
->ParaList
[33] = 0x86;
935 OptEnt
.Para
->ParaList
[34] = 0x87;
937 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
940 // Append UUID/Guid-based client identifier option
942 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
943 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
944 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
945 OptEnt
.Uuid
->Type
= 0;
947 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
949 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
951 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
952 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
953 // GUID not yet set - send all 0's to show not programable
955 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
959 // Append client network device interface option
961 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
962 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
963 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
964 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
965 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
966 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
969 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
972 // Append client system architecture option
974 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
975 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
976 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
977 Value
= HTONS (SYS_ARCH
);
978 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
980 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
983 // Append client system architecture option
985 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
986 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
987 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
988 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
989 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
990 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
991 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
992 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1000 GC_NOTO: Add function description
1002 @param Private GC_NOTO: add argument description
1003 @param Type GC_NOTO: add argument description
1004 @param Layer GC_NOTO: add argument description
1005 @param UseBis GC_NOTO: add argument description
1006 @param DestIp GC_NOTO: add argument description
1007 @param IpCount GC_NOTO: add argument description
1008 @param SrvList GC_NOTO: add argument description
1009 @param IsDiscv GC_NOTO: add argument description
1010 @param Reply GC_NOTO: add argument description
1012 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value
1016 PxeBcDiscvBootService (
1017 IN PXEBC_PRIVATE_DATA
* Private
,
1021 IN EFI_IP_ADDRESS
* DestIp
,
1023 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1025 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1028 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1029 EFI_PXE_BASE_CODE_MODE
*Mode
;
1030 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1031 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1037 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1038 EFI_DHCP4_PACKET
*Response
;
1039 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1041 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1042 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1045 Mode
= Private
->PxeBc
.Mode
;
1046 Dhcp4
= Private
->Dhcp4
;
1047 Status
= EFI_SUCCESS
;
1049 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1051 if (DestIp
== NULL
) {
1052 Sport
= PXEBC_DHCP4_S_PORT
;
1055 Sport
= PXEBC_BS_DISCOVER_PORT
;
1059 if (!UseBis
&& Layer
!= NULL
) {
1060 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1063 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1067 // Add vendor option of PXE_BOOT_ITEM
1069 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1070 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1071 if (OptList
[OptCount
] == NULL
) {
1072 return EFI_OUT_OF_RESOURCES
;
1075 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1076 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1077 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1078 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1079 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1080 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1081 PxeBootItem
->Type
= HTONS (Type
);
1082 PxeBootItem
->Layer
= HTONS (*Layer
);
1083 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1088 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1091 gBS
->FreePool (OptList
[OptCount
- 1]);
1094 if (EFI_ERROR (Status
)) {
1098 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1099 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1100 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1102 Token
.RemotePort
= Sport
;
1104 if (DestIp
== NULL
) {
1105 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1107 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1110 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1113 Token
.ListenPointCount
= 1;
1114 Token
.ListenPoints
= &ListenPoint
;
1115 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1116 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1117 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1120 // Send Pxe Discover
1122 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1124 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1126 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1128 if (Token
.Status
!= EFI_TIMEOUT
) {
1133 if (!EFI_ERROR (Status
)) {
1139 Response
= Token
.ResponseList
;
1141 while (RepIndex
< Token
.ResponseCount
) {
1143 while (SrvIndex
< IpCount
) {
1145 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1149 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1156 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1163 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1166 if (RepIndex
< Token
.ResponseCount
) {
1168 if (Reply
!= NULL
) {
1169 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1173 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1174 Mode
->PxeDiscoverValid
= TRUE
;
1176 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1177 Mode
->PxeReplyReceived
= TRUE
;
1180 Status
= EFI_NOT_FOUND
;
1184 // free the responselist
1186 gBS
->FreePool (Token
.ResponseList
);
1189 // Free the dhcp packet
1191 gBS
->FreePool (Token
.Packet
);
1198 GC_NOTO: Add function description
1200 @param Buffer GC_NOTO: add argument description
1201 @param Length GC_NOTO: add argument description
1202 @param OptTag GC_NOTO: add argument description
1204 @return GC_NOTO: add return values
1207 EFI_DHCP4_PACKET_OPTION
*
1208 PxeBcParseExtendOptions (
1214 EFI_DHCP4_PACKET_OPTION
*Option
;
1217 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1220 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1222 if (Option
->OpCode
== OptTag
) {
1227 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1230 Offset
+= Option
->Length
+ 2;
1233 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1241 This function is to parse and check vendor options.
1243 @param Dhcp4Option Pointer to dhcp options
1244 @param VendorOption Pointer to vendor options
1246 @return TRUE : Valid vendor options
1247 @return FALSE : Invalid vendor options
1251 PxeBcParseVendorOptions (
1252 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1253 IN PXEBC_VENDOR_OPTION
*VendorOption
1257 UINT8 VendorOptionLen
;
1258 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1261 BitMap
= VendorOption
->BitMap
;
1262 VendorOptionLen
= Dhcp4Option
->Length
;
1263 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1266 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1268 // Parse every Vendor Option and set its BitMap
1270 switch (PxeOption
->OpCode
) {
1272 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1274 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1277 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1279 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1282 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1284 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1287 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1289 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1292 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1294 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1297 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1299 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1302 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1304 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1307 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1309 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1310 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1313 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1315 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1316 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1319 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1321 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1322 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1325 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1327 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1328 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1329 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1332 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1334 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1335 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1338 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1340 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1341 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1345 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1347 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1350 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1353 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1357 // FixMe, return falas if invalid of any vendor option
1365 GC_NOTO: Add function description
1367 @param Str GC_NOTO: add argument description
1368 @param Len GC_NOTO: add argument description
1370 @return GC_NOTO: add return values
1374 PxeBcDisplayBootItem (
1381 Len
= (UINT8
) MIN (70, Len
);
1384 AsciiPrint ("%a \n", Str
);
1390 GC_NOTO: Add function description
1392 @param Private GC_NOTO: add argument description
1394 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1395 @retval EFI_TIMEOUT GC_NOTO: Add description for return value
1399 PxeBcSelectBootPrompt (
1400 IN PXEBC_PRIVATE_DATA
*Private
1403 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1404 PXEBC_VENDOR_OPTION
*VendorOpt
;
1405 EFI_EVENT TimeoutEvent
;
1406 EFI_EVENT DescendEvent
;
1407 EFI_INPUT_KEY InputKey
;
1415 TimeoutEvent
= NULL
;
1416 DescendEvent
= NULL
;
1418 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1420 Packet
= &Private
->ProxyOffer
;
1423 Packet
= &Private
->Dhcp4Ack
;
1426 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1427 return EFI_NOT_FOUND
;
1430 VendorOpt
= &Packet
->PxeVendorOption
;
1432 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1436 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1437 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1438 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1444 if (Timeout
== 255) {
1448 Status
= gBS
->CreateEvent (
1456 if (EFI_ERROR (Status
)) {
1460 Status
= gBS
->SetTimer (
1463 Timeout
* TICKS_PER_SECOND
1466 if (EFI_ERROR (Status
)) {
1470 Status
= gBS
->CreateEvent (
1478 if (EFI_ERROR (Status
)) {
1482 Status
= gBS
->SetTimer (
1488 if (EFI_ERROR (Status
)) {
1492 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1493 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1495 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1497 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1498 AsciiPrint ("(%d) ", Timeout
--);
1500 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1502 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1503 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1504 AsciiPrint ("(%d) ", Timeout
--);
1507 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1509 gBS
->Stall (10 * TICKS_PER_MS
);
1513 if (InputKey
.ScanCode
== 0) {
1515 switch (InputKey
.UnicodeChar
) {
1517 Status
= EFI_ABORTED
;
1523 Status
= EFI_TIMEOUT
;
1531 switch (InputKey
.ScanCode
) {
1533 Status
= EFI_TIMEOUT
;
1537 Status
= EFI_ABORTED
;
1548 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1552 if (DescendEvent
!= NULL
) {
1553 gBS
->CloseEvent (DescendEvent
);
1556 if (TimeoutEvent
!= NULL
) {
1557 gBS
->CloseEvent (TimeoutEvent
);
1565 GC_NOTO: Add function description
1567 @param Private GC_NOTO: add argument description
1568 @param Type GC_NOTO: add argument description
1570 @retval EFI_ABORTED GC_NOTO: Add description for return value
1571 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1575 PxeBcSelectBootMenu (
1576 IN PXEBC_PRIVATE_DATA
*Private
,
1578 IN BOOLEAN UseDefaultItem
1581 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1582 PXEBC_VENDOR_OPTION
*VendorOpt
;
1583 EFI_INPUT_KEY InputKey
;
1592 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1593 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1600 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1602 Packet
= &Private
->ProxyOffer
;
1605 Packet
= &Private
->Dhcp4Ack
;
1608 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1610 VendorOpt
= &Packet
->PxeVendorOption
;
1612 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1616 SetMem (Blank
, sizeof(Blank
), ' ');
1618 MenuSize
= VendorOpt
->BootMenuLen
;
1619 MenuItem
= VendorOpt
->BootMenu
;
1621 while (MenuSize
> 0) {
1622 MenuArray
[Index
] = MenuItem
;
1623 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1624 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1628 if (UseDefaultItem
) {
1629 *Type
= NTOHS (MenuArray
[0]->Type
);
1635 for (Index
= 0; Index
< MenuNum
; Index
++) {
1636 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1639 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1643 // highlight selected row
1645 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1646 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1647 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1648 AsciiPrint ("%a\r", Blank
);
1649 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1650 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1651 LastSelect
= Select
;
1653 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1654 gBS
->Stall (10 * TICKS_PER_MS
);
1657 if (!InputKey
.ScanCode
) {
1658 switch (InputKey
.UnicodeChar
) {
1660 InputKey
.ScanCode
= SCAN_ESC
;
1663 case CTRL ('j'): /* linefeed */
1664 case CTRL ('m'): /* return */
1668 case CTRL ('i'): /* tab */
1672 InputKey
.ScanCode
= SCAN_DOWN
;
1675 case CTRL ('h'): /* backspace */
1678 InputKey
.ScanCode
= SCAN_UP
;
1682 InputKey
.ScanCode
= 0;
1686 switch (InputKey
.ScanCode
) {
1697 if (++Select
== MenuNum
) {
1708 case SCAN_PAGE_DOWN
:
1710 Select
= (UINT16
) (MenuNum
- 1);
1717 /* unhighlight last selected row */
1718 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1719 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1720 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1721 AsciiPrint ("%a\r", Blank
);
1722 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1723 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1727 // Swap the byte order
1729 *Type
= NTOHS (MenuArray
[Select
]->Type
);