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
);
852 GC_NOTO: Add function description
854 @param Private GC_NOTO: add argument description
855 @param OptList GC_NOTO: add argument description
856 @param IsDhcpDiscover GC_NOTO: add argument description
858 @return GC_NOTO: add return values
862 PxeBcBuildDhcpOptions (
863 IN PXEBC_PRIVATE_DATA
*Private
,
864 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
865 IN BOOLEAN IsDhcpDiscover
869 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
871 CHAR8
*SystemSerialNumber
;
874 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
876 if (!IsDhcpDiscover
) {
878 // Append message type.
880 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
881 OptList
[Index
]->Length
= 1;
882 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
883 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
885 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
888 // Append max message size.
890 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
891 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
892 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
893 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
894 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
896 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
899 // Parameter request list option.
901 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
902 OptList
[Index
]->Length
= 35;
903 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
904 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
905 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
906 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
907 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
908 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
909 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
910 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
911 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
912 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
913 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
914 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
915 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
916 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
917 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
918 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
919 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
920 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
921 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
922 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
923 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
924 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
925 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
926 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
927 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
928 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
929 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
930 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
931 OptEnt
.Para
->ParaList
[27] = 0x80;
932 OptEnt
.Para
->ParaList
[28] = 0x81;
933 OptEnt
.Para
->ParaList
[29] = 0x82;
934 OptEnt
.Para
->ParaList
[30] = 0x83;
935 OptEnt
.Para
->ParaList
[31] = 0x84;
936 OptEnt
.Para
->ParaList
[32] = 0x85;
937 OptEnt
.Para
->ParaList
[33] = 0x86;
938 OptEnt
.Para
->ParaList
[34] = 0x87;
940 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
943 // Append UUID/Guid-based client identifier option
945 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
946 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
947 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
948 OptEnt
.Uuid
->Type
= 0;
950 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
952 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
954 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
955 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
956 // GUID not yet set - send all 0's to show not programable
958 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
962 // Append client network device interface option
964 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
965 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
966 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
967 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
968 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
969 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
972 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
975 // Append client system architecture option
977 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
978 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
979 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
980 Value
= HTONS (SYS_ARCH
);
981 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
983 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
986 // Append client system architecture option
988 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
989 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
990 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
991 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
992 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
993 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
994 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
995 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1003 GC_NOTO: Add function description
1005 @param Private GC_NOTO: add argument description
1006 @param Type GC_NOTO: add argument description
1007 @param Layer GC_NOTO: add argument description
1008 @param UseBis GC_NOTO: add argument description
1009 @param DestIp GC_NOTO: add argument description
1010 @param IpCount GC_NOTO: add argument description
1011 @param SrvList GC_NOTO: add argument description
1012 @param IsDiscv GC_NOTO: add argument description
1013 @param Reply GC_NOTO: add argument description
1015 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value
1019 PxeBcDiscvBootService (
1020 IN PXEBC_PRIVATE_DATA
* Private
,
1024 IN EFI_IP_ADDRESS
* DestIp
,
1026 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1028 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1031 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1032 EFI_PXE_BASE_CODE_MODE
*Mode
;
1033 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1034 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1040 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1041 EFI_DHCP4_PACKET
*Response
;
1042 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1044 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1045 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1048 Mode
= Private
->PxeBc
.Mode
;
1049 Dhcp4
= Private
->Dhcp4
;
1050 Status
= EFI_SUCCESS
;
1052 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1054 if (DestIp
== NULL
) {
1055 Sport
= PXEBC_DHCP4_S_PORT
;
1058 Sport
= PXEBC_BS_DISCOVER_PORT
;
1062 if (!UseBis
&& Layer
!= NULL
) {
1063 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1066 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1070 // Add vendor option of PXE_BOOT_ITEM
1072 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1073 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1074 if (OptList
[OptCount
] == NULL
) {
1075 return EFI_OUT_OF_RESOURCES
;
1078 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1079 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1080 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1081 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1082 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1083 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1084 PxeBootItem
->Type
= HTONS (Type
);
1085 PxeBootItem
->Layer
= HTONS (*Layer
);
1086 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1091 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1094 gBS
->FreePool (OptList
[OptCount
- 1]);
1097 if (EFI_ERROR (Status
)) {
1101 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1102 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1103 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1105 Token
.RemotePort
= Sport
;
1107 if (DestIp
== NULL
) {
1108 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1110 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1113 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1116 Token
.ListenPointCount
= 1;
1117 Token
.ListenPoints
= &ListenPoint
;
1118 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1119 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1120 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1123 // Send Pxe Discover
1125 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1127 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1129 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1131 if (Token
.Status
!= EFI_TIMEOUT
) {
1136 if (!EFI_ERROR (Status
)) {
1142 Response
= Token
.ResponseList
;
1144 while (RepIndex
< Token
.ResponseCount
) {
1146 while (SrvIndex
< IpCount
) {
1148 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1152 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1159 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1166 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1169 if (RepIndex
< Token
.ResponseCount
) {
1171 if (Reply
!= NULL
) {
1172 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1176 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1177 Mode
->PxeDiscoverValid
= TRUE
;
1179 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1180 Mode
->PxeReplyReceived
= TRUE
;
1183 Status
= EFI_NOT_FOUND
;
1187 // free the responselist
1189 gBS
->FreePool (Token
.ResponseList
);
1192 // Free the dhcp packet
1194 gBS
->FreePool (Token
.Packet
);
1201 GC_NOTO: Add function description
1203 @param Buffer GC_NOTO: add argument description
1204 @param Length GC_NOTO: add argument description
1205 @param OptTag GC_NOTO: add argument description
1207 @return GC_NOTO: add return values
1210 EFI_DHCP4_PACKET_OPTION
*
1211 PxeBcParseExtendOptions (
1217 EFI_DHCP4_PACKET_OPTION
*Option
;
1220 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1223 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1225 if (Option
->OpCode
== OptTag
) {
1230 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1233 Offset
+= Option
->Length
+ 2;
1236 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1244 This function is to parse and check vendor options.
1246 @param Dhcp4Option Pointer to dhcp options
1247 @param VendorOption Pointer to vendor options
1249 @return TRUE : Valid vendor options
1250 @return FALSE : Invalid vendor options
1254 PxeBcParseVendorOptions (
1255 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1256 IN PXEBC_VENDOR_OPTION
*VendorOption
1260 UINT8 VendorOptionLen
;
1261 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1264 BitMap
= VendorOption
->BitMap
;
1265 VendorOptionLen
= Dhcp4Option
->Length
;
1266 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1269 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1271 // Parse every Vendor Option and set its BitMap
1273 switch (PxeOption
->OpCode
) {
1275 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1277 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1280 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1282 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1285 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1287 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1290 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1292 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1295 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1297 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1300 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1302 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1305 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1307 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1310 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1312 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1313 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1316 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1318 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1319 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1322 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1324 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1325 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1328 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1330 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1331 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1332 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1335 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1337 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1338 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1341 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1343 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1344 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1348 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1350 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1353 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1356 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1360 // FixMe, return falas if invalid of any vendor option
1368 GC_NOTO: Add function description
1370 @param Str GC_NOTO: add argument description
1371 @param Len GC_NOTO: add argument description
1373 @return GC_NOTO: add return values
1377 PxeBcDisplayBootItem (
1384 Len
= (UINT8
) MIN (70, Len
);
1387 AsciiPrint ("%a \n", Str
);
1393 GC_NOTO: Add function description
1395 @param Private GC_NOTO: add argument description
1397 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1398 @retval EFI_TIMEOUT GC_NOTO: Add description for return value
1402 PxeBcSelectBootPrompt (
1403 IN PXEBC_PRIVATE_DATA
*Private
1406 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1407 PXEBC_VENDOR_OPTION
*VendorOpt
;
1408 EFI_EVENT TimeoutEvent
;
1409 EFI_EVENT DescendEvent
;
1410 EFI_INPUT_KEY InputKey
;
1418 TimeoutEvent
= NULL
;
1419 DescendEvent
= NULL
;
1421 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1423 Packet
= &Private
->ProxyOffer
;
1426 Packet
= &Private
->Dhcp4Ack
;
1429 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1430 return EFI_NOT_FOUND
;
1433 VendorOpt
= &Packet
->PxeVendorOption
;
1435 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1439 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1440 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1441 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1447 if (Timeout
== 255) {
1451 Status
= gBS
->CreateEvent (
1459 if (EFI_ERROR (Status
)) {
1463 Status
= gBS
->SetTimer (
1466 Timeout
* TICKS_PER_SECOND
1469 if (EFI_ERROR (Status
)) {
1473 Status
= gBS
->CreateEvent (
1481 if (EFI_ERROR (Status
)) {
1485 Status
= gBS
->SetTimer (
1491 if (EFI_ERROR (Status
)) {
1495 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1496 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1498 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1500 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1501 AsciiPrint ("(%d) ", Timeout
--);
1503 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1505 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1506 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1507 AsciiPrint ("(%d) ", Timeout
--);
1510 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1512 gBS
->Stall (10 * TICKS_PER_MS
);
1516 if (InputKey
.ScanCode
== 0) {
1518 switch (InputKey
.UnicodeChar
) {
1520 Status
= EFI_ABORTED
;
1526 Status
= EFI_TIMEOUT
;
1534 switch (InputKey
.ScanCode
) {
1536 Status
= EFI_TIMEOUT
;
1540 Status
= EFI_ABORTED
;
1551 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1555 if (DescendEvent
!= NULL
) {
1556 gBS
->CloseEvent (DescendEvent
);
1559 if (TimeoutEvent
!= NULL
) {
1560 gBS
->CloseEvent (TimeoutEvent
);
1568 GC_NOTO: Add function description
1570 @param Private GC_NOTO: add argument description
1571 @param Type GC_NOTO: add argument description
1573 @retval EFI_ABORTED GC_NOTO: Add description for return value
1574 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1578 PxeBcSelectBootMenu (
1579 IN PXEBC_PRIVATE_DATA
*Private
,
1581 IN BOOLEAN UseDefaultItem
1584 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1585 PXEBC_VENDOR_OPTION
*VendorOpt
;
1586 EFI_INPUT_KEY InputKey
;
1595 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1596 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1603 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1605 Packet
= &Private
->ProxyOffer
;
1608 Packet
= &Private
->Dhcp4Ack
;
1611 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1613 VendorOpt
= &Packet
->PxeVendorOption
;
1615 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1619 SetMem (Blank
, sizeof(Blank
), ' ');
1621 MenuSize
= VendorOpt
->BootMenuLen
;
1622 MenuItem
= VendorOpt
->BootMenu
;
1624 while (MenuSize
> 0) {
1625 MenuArray
[Index
] = MenuItem
;
1626 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1627 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1631 if (UseDefaultItem
) {
1632 *Type
= NTOHS (MenuArray
[0]->Type
);
1638 for (Index
= 0; Index
< MenuNum
; Index
++) {
1639 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1642 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1646 // highlight selected row
1648 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1649 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1650 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1651 AsciiPrint ("%a\r", Blank
);
1652 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1653 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1654 LastSelect
= Select
;
1656 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1657 gBS
->Stall (10 * TICKS_PER_MS
);
1660 if (!InputKey
.ScanCode
) {
1661 switch (InputKey
.UnicodeChar
) {
1663 InputKey
.ScanCode
= SCAN_ESC
;
1666 case CTRL ('j'): /* linefeed */
1667 case CTRL ('m'): /* return */
1671 case CTRL ('i'): /* tab */
1675 InputKey
.ScanCode
= SCAN_DOWN
;
1678 case CTRL ('h'): /* backspace */
1681 InputKey
.ScanCode
= SCAN_UP
;
1685 InputKey
.ScanCode
= 0;
1689 switch (InputKey
.ScanCode
) {
1700 if (++Select
== MenuNum
) {
1711 case SCAN_PAGE_DOWN
:
1713 Select
= (UINT16
) (MenuNum
- 1);
1720 /* unhighlight last selected row */
1721 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1722 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1723 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1724 AsciiPrint ("%a\r", Blank
);
1725 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1726 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1730 // Swap the byte order
1732 *Type
= NTOHS (MenuArray
[Select
]->Type
);