2 Support for PxeBc dhcp functions.
4 Copyright (c) 2013, Red Hat, Inc.
5 Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "PxeBcImpl.h"
20 // This is a map from the interested DHCP4 option tags' index to the tag value.
22 UINT8 mInterestedDhcp4Tags
[PXEBC_DHCP4_TAG_INDEX_MAX
] = {
23 PXEBC_DHCP4_TAG_BOOTFILE_LEN
,
24 PXEBC_DHCP4_TAG_VENDOR
,
25 PXEBC_DHCP4_TAG_OVERLOAD
,
26 PXEBC_DHCP4_TAG_MSG_TYPE
,
27 PXEBC_DHCP4_TAG_SERVER_ID
,
28 PXEBC_DHCP4_TAG_CLASS_ID
,
29 PXEBC_DHCP4_TAG_BOOTFILE
34 This function initialize the DHCP4 message instance.
36 This function will pad each item of dhcp4 message packet.
38 @param Seed Pointer to the message instance of the DHCP4 packet.
39 @param Udp4 Pointer to the EFI_UDP4_PROTOCOL instance.
44 IN EFI_DHCP4_PACKET
*Seed
,
45 IN EFI_UDP4_PROTOCOL
*Udp4
48 EFI_SIMPLE_NETWORK_MODE Mode
;
49 EFI_DHCP4_HEADER
*Header
;
51 Udp4
->GetModeData (Udp4
, NULL
, NULL
, NULL
, &Mode
);
53 Seed
->Size
= sizeof (EFI_DHCP4_PACKET
);
54 Seed
->Length
= sizeof (Seed
->Dhcp4
);
56 Header
= &Seed
->Dhcp4
.Header
;
58 ZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
59 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
60 Header
->HwType
= Mode
.IfType
;
61 Header
->HwAddrLen
= (UINT8
) Mode
.HwAddressSize
;
62 CopyMem (Header
->ClientHwAddr
, &Mode
.CurrentAddress
, Header
->HwAddrLen
);
64 Seed
->Dhcp4
.Magik
= PXEBC_DHCP4_MAGIC
;
65 Seed
->Dhcp4
.Option
[0] = PXEBC_DHCP4_TAG_EOP
;
70 Copy the DCHP4 packet from srouce to destination.
72 @param Dst Pointer to the EFI_DHCP4_PROTOCOL instance.
73 @param Src Pointer to the EFI_DHCP4_PROTOCOL instance.
77 PxeBcCopyEfiDhcp4Packet (
78 IN EFI_DHCP4_PACKET
*Dst
,
79 IN EFI_DHCP4_PACKET
*Src
82 ASSERT (Dst
->Size
>= Src
->Length
);
84 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
85 Dst
->Length
= Src
->Length
;
90 Copy the dhcp4 packet to the PxeBc private data and parse the dhcp4 packet.
92 @param Private Pointer to PxeBc private data.
93 @param OfferIndex Index of cached packets as complements of pxe mode data,
94 the index is maximum offer number.
99 IN PXEBC_PRIVATE_DATA
*Private
,
103 EFI_PXE_BASE_CODE_MODE
*Mode
;
104 EFI_DHCP4_PACKET
*Offer
;
106 ASSERT (OfferIndex
< Private
->NumOffers
);
107 ASSERT (OfferIndex
< PXEBC_MAX_OFFER_NUM
);
109 Mode
= Private
->PxeBc
.Mode
;
110 Offer
= &Private
->Dhcp4Offers
[OfferIndex
].Packet
.Offer
;
112 PxeBcCopyEfiDhcp4Packet (&Private
->ProxyOffer
.Packet
.Offer
, Offer
);
113 CopyMem (&Mode
->ProxyOffer
, &Offer
->Dhcp4
, Offer
->Length
);
114 Mode
->ProxyOfferReceived
= TRUE
;
116 PxeBcParseCachedDhcpPacket (&Private
->ProxyOffer
);
121 Parse the cached dhcp packet.
123 @param CachedPacket Pointer to cached dhcp packet.
125 @retval TRUE Succeed to parse and validation.
126 @retval FALSE Fail to parse or validation.
130 PxeBcParseCachedDhcpPacket (
131 IN PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
134 EFI_DHCP4_PACKET
*Offer
;
135 EFI_DHCP4_PACKET_OPTION
**Options
;
136 EFI_DHCP4_PACKET_OPTION
*Option
;
141 CachedPacket
->IsPxeOffer
= FALSE
;
142 ZeroMem (CachedPacket
->Dhcp4Option
, sizeof (CachedPacket
->Dhcp4Option
));
143 ZeroMem (&CachedPacket
->PxeVendorOption
, sizeof (CachedPacket
->PxeVendorOption
));
145 Offer
= &CachedPacket
->Packet
.Offer
;
146 Options
= CachedPacket
->Dhcp4Option
;
149 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.
151 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
152 Options
[Index
] = PxeBcParseExtendOptions (
154 GET_OPTION_BUFFER_LEN (Offer
),
155 mInterestedDhcp4Tags
[Index
]
160 // Check whether is an offer with PXEClient or not.
162 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
163 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
164 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
166 CachedPacket
->IsPxeOffer
= TRUE
;
170 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
172 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
173 if (CachedPacket
->IsPxeOffer
&& (Option
!= NULL
)) {
175 if (!PxeBcParseVendorOptions (Option
, &CachedPacket
->PxeVendorOption
)) {
181 // Check whether bootfilename/serverhostname overloaded (See details in dhcp spec).
182 // If overloaded, parse this buffer as nested dhcp options, or just parse bootfilename/
183 // serverhostname option.
185 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
186 if ((Option
!= NULL
) && ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
) != 0)) {
188 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = PxeBcParseExtendOptions (
189 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
190 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
191 PXEBC_DHCP4_TAG_BOOTFILE
194 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
195 // terminated string. So force to append null terminated character at the end of string.
197 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
198 Ptr8
= (UINT8
*)&Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
199 Ptr8
+= Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
203 } else if ((Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) &&
204 (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
206 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
207 // And do not count dhcp option header, or else will destroy the serverhostname.
209 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*) (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
210 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
215 // Determine offer type of the dhcp packet.
217 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
218 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
220 // It's a bootp offer
222 Option
= CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
223 if (Option
== NULL
) {
225 // bootp offer without bootfilename, discard it.
230 OfferType
= DHCP4_PACKET_TYPE_BOOTP
;
234 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
236 // It's a pxe10 offer with PXEClient and discover vendor option.
238 OfferType
= DHCP4_PACKET_TYPE_PXE10
;
239 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
241 // It's a wfm11a offer with PXEClient and mtftp vendor option, and
242 // return false since mtftp not supported currently.
247 // If the binl offer with only PXEClient.
249 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
253 CachedPacket
->OfferType
= OfferType
;
260 Offer dhcp service with a BINL dhcp offer.
262 @param Private Pointer to PxeBc private data.
263 @param Index Index of cached packets as complements of pxe mode data,
264 the index is maximum offer number.
266 @retval TRUE Offer the service successfully under priority BINL.
267 @retval FALSE Boot Service failed, parse cached dhcp packet failed or this
268 BINL ack cannot find options set or bootfile name specified.
273 IN PXEBC_PRIVATE_DATA
*Private
,
277 EFI_DHCP4_PACKET
*Offer
;
278 EFI_IP_ADDRESS ServerIp
;
280 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
281 EFI_DHCP4_PACKET
*Reply
;
283 ASSERT (Index
< PXEBC_MAX_OFFER_NUM
);
284 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
286 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
289 // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)
290 // in DHCPOFFER packet.
291 // (It does not comply with PXE Spec, Ver2.1)
293 if (EFI_IP4_EQUAL (&Offer
->Dhcp4
.Header
.ServerAddr
.Addr
, &mZeroIp4Addr
)) {
296 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
297 sizeof (EFI_IPv4_ADDRESS
)
302 &Offer
->Dhcp4
.Header
.ServerAddr
,
303 sizeof (EFI_IPv4_ADDRESS
)
306 if (ServerIp
.Addr
[0] == 0) {
310 CachedPacket
= &Private
->ProxyOffer
;
311 Reply
= &CachedPacket
->Packet
.Offer
;
313 Status
= PxeBcDiscvBootService (
324 if (EFI_ERROR (Status
)) {
328 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
332 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
333 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
335 // This BINL ack doesn't have discovery options set or bootfile name
341 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
342 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
349 Offer dhcp service for each proxy with a BINL dhcp offer.
351 @param Private Pointer to PxeBc private data
352 @param OfferIndex Pointer to the index of cached packets as complements of
353 pxe mode data, the index is maximum offer number.
355 @return If there is no service needed offer return FALSE, otherwise TRUE.
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 This function is to check the selected proxy offer (include BINL dhcp offer and
383 DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code
386 @param Private Pointer to PxeBc private data.
388 @retval EFI_SUCCESS Operational successful.
389 @retval EFI_NO_RESPONSE Offer dhcp service failed.
393 PxeBcCheckSelectedOffer (
394 IN PXEBC_PRIVATE_DATA
*Private
397 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
398 EFI_DHCP4_PACKET_OPTION
**Options
;
400 EFI_DHCP4_PACKET
*Offer
;
401 UINT32 ProxyOfferIndex
;
403 EFI_PXE_BASE_CODE_MODE
*Mode
;
404 EFI_DHCP4_PACKET
*Ack
;
406 ASSERT (Private
->SelectedOffer
!= 0);
408 Status
= EFI_SUCCESS
;
409 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
410 Options
= SelectedOffer
->Dhcp4Option
;
412 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
414 // The addresses are acquired from a BINL dhcp offer, try BINL to get
417 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
418 Status
= EFI_NO_RESPONSE
;
420 } else if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) {
422 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
423 // try proxy offers if there are some, othewise the bootfile name must be
424 // set in this DHCP only offer.
426 if (Private
->GotProxyOffer
) {
428 // Get rid of the compiler warning.
431 if (Private
->SortOffers
) {
433 // The offers are sorted before selecting, the proxy offer type must be
434 // already determined.
436 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
438 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
440 // We buffer all received BINL proxy offers, try them all one by one
442 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
443 Status
= EFI_NO_RESPONSE
;
447 // For other types, only one proxy offer is buffered.
449 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
453 // The proxy offer type is not determined, choose proxy offer in the
456 Status
= EFI_NO_RESPONSE
;
458 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
460 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
461 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
463 // Skip non proxy dhcp offers.
468 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
472 if (!PxeBcTryBinl (Private
, Index
)) {
474 // Failed, skip to the next offer
480 Private
->ProxyOfferType
= Private
->Dhcp4Offers
[Index
].OfferType
;
481 ProxyOfferIndex
= Index
;
482 Status
= EFI_SUCCESS
;
487 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
489 // Copy the proxy offer to Mode and set the flag
491 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
495 // No proxy offer is received, the bootfile name MUST be set.
497 ASSERT (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
501 if (!EFI_ERROR (Status
)) {
503 // Everything is OK, set the flag and copy the DHCP packets.
505 Mode
= Private
->PxeBc
.Mode
;
506 Offer
= &SelectedOffer
->Packet
.Offer
;
509 // The discover packet is already copied, just set flag here.
511 Mode
->DhcpDiscoverValid
= TRUE
;
513 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
514 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
516 // Other type of ACK is already cached. Bootp is special that we should
517 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
519 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
522 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
524 Mode
->DhcpAckReceived
= TRUE
;
527 // Copy the dhcp ack.
529 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
537 Cache the Dhcp4 packet offer, Parse and validate each option of the packet.
539 @param Private Pointer to PxeBc private data.
540 @param RcvdOffer Pointer to the received Dhcp proxy offer packet.
544 PxeBcCacheDhcpOffer (
545 IN PXEBC_PRIVATE_DATA
*Private
,
546 IN EFI_DHCP4_PACKET
*RcvdOffer
549 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
550 EFI_DHCP4_PACKET
*Offer
;
553 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
554 Offer
= &CachedOffer
->Packet
.Offer
;
557 // Cache the orignal dhcp packet
559 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
562 // Parse and validate the options (including dhcp option and vendor option)
564 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
568 OfferType
= CachedOffer
->OfferType
;
569 if (OfferType
>= DHCP4_PACKET_TYPE_MAX
) {
573 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
575 if (Private
->BootpIndex
!= 0) {
577 // Only cache the first bootp offer, discard others.
582 // Take as a dhcp only offer, but record index specifically.
584 Private
->BootpIndex
= Private
->NumOffers
+ 1;
588 if (IS_PROXY_DHCP_OFFER (Offer
)) {
590 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
592 Private
->GotProxyOffer
= TRUE
;
594 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
596 // Cache all binl offers.
598 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
599 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
600 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
602 // Only cache the first pxe10/wfm11a offers each, discard the others.
607 // Record index of the proxy dhcp offer with type other than binl.
609 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
613 // It's a dhcp offer with your address.
615 ASSERT (Private
->ServerCount
[OfferType
] < PXEBC_MAX_OFFER_NUM
);
616 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
617 Private
->ServerCount
[OfferType
]++;
622 // Count the accepted offers.
624 Private
->NumOffers
++;
629 Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.
630 If the proxy does not exist, try offers with bootfile.
632 @param Private Pointer to PxeBc private data.
637 IN PXEBC_PRIVATE_DATA
*Private
642 EFI_DHCP4_PACKET
*Offer
;
644 Private
->SelectedOffer
= 0;
646 if (Private
->SortOffers
) {
648 // Select offer according to the priority
650 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
654 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
656 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
660 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
662 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
663 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
666 // DHCP only and proxy DHCP with PXE10
668 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
669 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
671 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
672 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
675 // DHCP only and proxy DHCP with WfM
677 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
678 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
680 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
684 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
686 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
687 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
690 // DHCP only and proxy DHCP with BINL
692 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
693 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
697 // Try offers with bootfile
699 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
701 // Select the first DHCP only offer with bootfile
703 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
704 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
705 Private
->SelectedOffer
= OfferIndex
+ 1;
710 if (Private
->SelectedOffer
== 0) {
712 // Select the Bootp reply with bootfile if any
714 Private
->SelectedOffer
= Private
->BootpIndex
;
719 // Try the offers in the received order.
721 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
723 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
725 if (IS_PROXY_DHCP_OFFER (Offer
)) {
732 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
733 ((!Private
->GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
735 // DHCP only offer but no proxy offer received and no bootfile option in this offer
740 Private
->SelectedOffer
= Index
+ 1;
750 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
751 to intercept events that occurred in the configuration process. This structure
752 provides advanced control of each state transition of the DHCP process. The
753 returned status code determines the behavior of the EFI DHCPv4 Protocol driver.
754 There are three possible returned values, which are described in the following
757 @param This Pointer to the EFI DHCPv4 Protocol instance that is used to
758 configure this callback function.
759 @param Context Pointer to the context that is initialized by
760 EFI_DHCP4_PROTOCOL.Configure().
761 @param CurrentState The current operational state of the EFI DHCPv4 Protocol
763 @param Dhcp4Event The event that occurs in the current state, which usually means a
765 @param Packet The DHCP packet that is going to be sent or already received.
766 @param NewPacket The packet that is used to replace the above Packet.
768 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
769 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
770 driver will continue to wait for more DHCPOFFER packets until the retry
772 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and
773 return to the Dhcp4Init or Dhcp4InitReboot state.
779 IN EFI_DHCP4_PROTOCOL
* This
,
781 IN EFI_DHCP4_STATE CurrentState
,
782 IN EFI_DHCP4_EVENT Dhcp4Event
,
783 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
784 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
787 PXEBC_PRIVATE_DATA
*Private
;
788 EFI_PXE_BASE_CODE_MODE
*Mode
;
789 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
790 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
794 EFI_DHCP4_HEADER
*DhcpHeader
;
796 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
797 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
798 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
799 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
800 (Dhcp4Event
!= Dhcp4SendRequest
)) {
804 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
805 Mode
= Private
->PxeBc
.Mode
;
806 Callback
= Private
->PxeBcCallback
;
809 // Override the Maximum DHCP Message Size.
811 MaxMsgSize
= PxeBcParseExtendOptions (
812 Packet
->Dhcp4
.Option
,
813 GET_OPTION_BUFFER_LEN (Packet
),
814 PXEBC_DHCP4_TAG_MAXMSG
816 if (MaxMsgSize
!= NULL
) {
817 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
818 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
821 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
822 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
823 Status
= Callback
->Callback (
828 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
830 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
835 Status
= EFI_SUCCESS
;
837 switch (Dhcp4Event
) {
839 case Dhcp4SendDiscover
:
840 case Dhcp4SendRequest
:
841 if (Mode
->SendGUID
) {
843 // send the system GUID instead of the MAC address as the hardware address
844 // in the DHCP packet header.
846 DhcpHeader
= &Packet
->Dhcp4
.Header
;
848 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
))) {
850 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
851 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
852 // GUID not yet set - send all 0's to show not programable
854 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
857 DhcpHeader
->HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
860 if (Dhcp4Event
== Dhcp4SendDiscover
) {
862 // Cache the dhcp discover packet, of which some information will be used later.
864 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
870 Status
= EFI_NOT_READY
;
871 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
873 // Cache the dhcp offers in Private->Dhcp4Offers[]
875 PxeBcCacheDhcpOffer (Private
, Packet
);
880 case Dhcp4SelectOffer
:
882 // Select an offer, if succeeded, Private->SelectedOffer points to
883 // the index of the selected one.
885 PxeBcSelectOffer (Private
);
887 if (Private
->SelectedOffer
== 0) {
888 Status
= EFI_ABORTED
;
890 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
899 ASSERT (Private
->SelectedOffer
!= 0);
901 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
913 Initialize the DHCP options and build the option list.
915 @param Private Pointer to PxeBc private data.
916 @param OptList Pointer to a DHCP option list.
918 @param IsDhcpDiscover Discover dhcp option or not.
920 @return The index item number of the option list.
924 PxeBcBuildDhcpOptions (
925 IN PXEBC_PRIVATE_DATA
*Private
,
926 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
927 IN BOOLEAN IsDhcpDiscover
931 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
935 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
937 if (!IsDhcpDiscover
) {
939 // Append message type.
941 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
942 OptList
[Index
]->Length
= 1;
943 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
944 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
946 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
949 // Append max message size.
951 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
952 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
953 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
954 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
955 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
957 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
960 // Parameter request list option.
962 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
963 OptList
[Index
]->Length
= 35;
964 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
965 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
966 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
967 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
968 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
969 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
970 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
971 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
972 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
973 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
974 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
975 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
976 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
977 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
978 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
979 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
980 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
981 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
982 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
983 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
984 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
985 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
986 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
987 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
988 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
989 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
990 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
991 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
992 OptEnt
.Para
->ParaList
[27] = 0x80;
993 OptEnt
.Para
->ParaList
[28] = 0x81;
994 OptEnt
.Para
->ParaList
[29] = 0x82;
995 OptEnt
.Para
->ParaList
[30] = 0x83;
996 OptEnt
.Para
->ParaList
[31] = 0x84;
997 OptEnt
.Para
->ParaList
[32] = 0x85;
998 OptEnt
.Para
->ParaList
[33] = 0x86;
999 OptEnt
.Para
->ParaList
[34] = 0x87;
1001 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1004 // Append UUID/Guid-based client identifier option
1006 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
1007 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UUID
);
1008 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
1009 OptEnt
.Uuid
->Type
= 0;
1011 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1013 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) OptEnt
.Uuid
->Guid
))) {
1015 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
1016 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
1017 // GUID not yet set - send all 0's to show not programable
1019 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
1023 // Append client network device interface option
1025 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
1026 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UNDI
);
1027 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
1028 if (Private
->Nii
!= NULL
) {
1029 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
1030 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
1031 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
1033 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
1034 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
1035 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
1039 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1042 // Append client system architecture option
1044 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
1045 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1046 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1047 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
1048 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1050 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1053 // Append client system architecture option
1055 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
1056 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_CLID
);
1057 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1058 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1059 CvtNum (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1061 if (Private
->Nii
!= NULL
) {
1063 // If NII protocol exists, update DHCP option data
1065 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1066 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1067 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1077 Discover the boot of service and initialize the vendor option if exists.
1079 @param Private Pointer to PxeBc private data.
1080 @param Type PxeBc option boot item type
1081 @param Layer PxeBc option boot item layer
1082 @param UseBis Use BIS or not
1083 @param DestIp Ip address for server
1084 @param IpCount The total count of the server ip address
1085 @param SrvList Server list
1086 @param IsDiscv Discover the vendor or not
1087 @param Reply The dhcp4 packet of Pxe reply
1089 @retval EFI_SUCCESS Operation succeeds.
1090 @retval EFI_OUT_OF_RESOURCES Allocate memory pool failed.
1091 @retval EFI_NOT_FOUND There is no vendor option exists.
1092 @retval EFI_TIMEOUT Send Pxe Discover time out.
1096 PxeBcDiscvBootService (
1097 IN PXEBC_PRIVATE_DATA
* Private
,
1101 IN EFI_IP_ADDRESS
* DestIp
,
1103 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1105 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1108 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1109 EFI_PXE_BASE_CODE_MODE
*Mode
;
1110 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1111 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1117 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1118 EFI_DHCP4_PACKET
*Response
;
1119 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1121 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1122 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1124 EFI_DHCP4_HEADER
*DhcpHeader
;
1127 Mode
= Private
->PxeBc
.Mode
;
1128 Dhcp4
= Private
->Dhcp4
;
1129 Status
= EFI_SUCCESS
;
1131 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1133 if (DestIp
== NULL
) {
1134 Sport
= PXEBC_DHCP4_S_PORT
;
1137 Sport
= PXEBC_BS_DISCOVER_PORT
;
1141 if (!UseBis
&& Layer
!= NULL
) {
1142 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1145 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1148 ASSERT (Layer
!= NULL
);
1150 // Add vendor option of PXE_BOOT_ITEM
1152 VendorOptLen
= (UINT8
) ((sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1);
1153 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1154 if (OptList
[OptCount
] == NULL
) {
1155 return EFI_OUT_OF_RESOURCES
;
1158 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1159 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1160 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1161 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1162 PxeOpt
->Length
= (UINT8
) sizeof (PXEBC_OPTION_BOOT_ITEM
);
1163 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1164 PxeBootItem
->Type
= HTONS (Type
);
1165 PxeBootItem
->Layer
= HTONS (*Layer
);
1166 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1171 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1174 FreePool (OptList
[OptCount
- 1]);
1177 if (EFI_ERROR (Status
)) {
1181 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1182 if (Mode
->SendGUID
) {
1183 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
))) {
1185 // GUID not yet set - send all 0's to show not programable
1187 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1190 DhcpHeader
->HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
1193 Xid
= NET_RANDOM (NetRandomInitSeed ());
1194 Token
.Packet
->Dhcp4
.Header
.Xid
= HTONL(Xid
);
1195 Token
.Packet
->Dhcp4
.Header
.Reserved
= HTONS((UINT16
) ((IsBCast
) ? 0x8000 : 0));
1196 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1198 Token
.RemotePort
= Sport
;
1201 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1203 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1206 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1209 Token
.ListenPointCount
= 1;
1210 Token
.ListenPoints
= &ListenPoint
;
1211 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1212 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1213 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1216 // Send Pxe Discover
1218 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1220 Token
.TimeoutValue
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
);
1221 Token
.Packet
->Dhcp4
.Header
.Seconds
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* (TryIndex
- 1));
1223 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1225 if (Token
.Status
!= EFI_TIMEOUT
) {
1230 if (TryIndex
> PXEBC_BOOT_REQUEST_RETRIES
) {
1232 // No server response our PXE request
1234 Status
= EFI_TIMEOUT
;
1237 if (!EFI_ERROR (Status
)) {
1243 Response
= Token
.ResponseList
;
1245 while (RepIndex
< Token
.ResponseCount
) {
1247 while (SrvIndex
< IpCount
) {
1249 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1253 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1260 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1267 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1270 if (RepIndex
< Token
.ResponseCount
) {
1272 if (Reply
!= NULL
) {
1273 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1277 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1278 Mode
->PxeDiscoverValid
= TRUE
;
1280 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1281 Mode
->PxeReplyReceived
= TRUE
;
1284 Status
= EFI_NOT_FOUND
;
1288 // free the responselist
1290 if (Token
.ResponseList
!= NULL
) {
1291 FreePool (Token
.ResponseList
);
1295 // Free the dhcp packet
1297 FreePool (Token
.Packet
);
1304 Parse interested dhcp options.
1306 @param Buffer Pointer to the dhcp options packet.
1307 @param Length The length of the dhcp options.
1308 @param OptTag The option OpCode.
1310 @return NULL if the buffer length is 0 and OpCode is not
1311 PXEBC_DHCP4_TAG_EOP, or the pointer to the buffer.
1314 EFI_DHCP4_PACKET_OPTION
*
1315 PxeBcParseExtendOptions (
1321 EFI_DHCP4_PACKET_OPTION
*Option
;
1324 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1327 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1329 if (Option
->OpCode
== OptTag
) {
1334 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1337 Offset
+= Option
->Length
+ 2;
1340 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1348 This function is to parse and check vendor options.
1350 @param Dhcp4Option Pointer to dhcp options
1351 @param VendorOption Pointer to vendor options
1353 @return TRUE if valid for vendor options, or FALSE.
1357 PxeBcParseVendorOptions (
1358 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1359 IN PXEBC_VENDOR_OPTION
*VendorOption
1363 UINT8 VendorOptionLen
;
1364 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1367 BitMap
= VendorOption
->BitMap
;
1368 VendorOptionLen
= Dhcp4Option
->Length
;
1369 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1372 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1374 // Parse every Vendor Option and set its BitMap
1376 switch (PxeOption
->OpCode
) {
1378 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1380 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1383 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1385 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1388 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1390 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1393 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1395 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1398 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1400 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1403 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1405 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1408 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1410 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1413 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1415 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1416 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1419 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1421 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1422 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1425 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1427 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1428 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1431 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1433 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1434 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1435 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1438 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1440 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1441 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1444 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1446 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1447 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1451 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1453 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1456 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1459 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1463 // FixMe, return falas if invalid of any vendor option
1471 This function display boot item detail.
1473 If the length of the boot item string over 70 Char, just display 70 Char.
1475 @param Str Pointer to a string (boot item string).
1476 @param Len The length of string.
1480 PxeBcDisplayBootItem (
1487 Len
= (UINT8
) MIN (70, Len
);
1490 AsciiPrint ("%a \n", Str
);
1496 Choose the boot prompt.
1498 @param Private Pointer to PxeBc private data.
1500 @retval EFI_SUCCESS Select boot prompt done.
1501 @retval EFI_TIMEOUT Select boot prompt time out.
1502 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
1503 @retval EFI_ABORTED User cancel the operation.
1504 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1508 PxeBcSelectBootPrompt (
1509 IN PXEBC_PRIVATE_DATA
*Private
1512 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1513 PXEBC_VENDOR_OPTION
*VendorOpt
;
1514 EFI_EVENT TimeoutEvent
;
1515 EFI_EVENT DescendEvent
;
1516 EFI_INPUT_KEY InputKey
;
1524 TimeoutEvent
= NULL
;
1525 DescendEvent
= NULL
;
1527 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1529 Packet
= &Private
->ProxyOffer
;
1532 Packet
= &Private
->Dhcp4Ack
;
1535 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1536 return EFI_NOT_FOUND
;
1539 VendorOpt
= &Packet
->PxeVendorOption
;
1541 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options (Full
1542 // List), we must not consider a boot prompt or boot menu if all of the
1544 // - the PXE_DISCOVERY_CONTROL PXE tag is present inside the Vendor Options
1545 // (=43) DHCP tag, and
1546 // - the PXE_DISCOVERY_CONTROL PXE tag has bit 3 set, and
1547 // - a boot file name has been presented with DHCP option 67.
1549 if (IS_DISABLE_PROMPT_MENU (VendorOpt
->DiscoverCtrl
) &&
1550 Packet
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
1554 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1558 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1559 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1560 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1566 if (Timeout
== 255) {
1570 Status
= gBS
->CreateEvent (
1578 if (EFI_ERROR (Status
)) {
1582 Status
= gBS
->SetTimer (
1585 Timeout
* TICKS_PER_SECOND
1588 if (EFI_ERROR (Status
)) {
1592 Status
= gBS
->CreateEvent (
1600 if (EFI_ERROR (Status
)) {
1604 Status
= gBS
->SetTimer (
1610 if (EFI_ERROR (Status
)) {
1614 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1615 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1617 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1619 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1620 AsciiPrint ("(%d) ", Timeout
--);
1622 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1624 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1625 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1626 AsciiPrint ("(%d) ", Timeout
--);
1629 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1631 gBS
->Stall (10 * TICKS_PER_MS
);
1635 if (InputKey
.ScanCode
== 0) {
1637 switch (InputKey
.UnicodeChar
) {
1639 Status
= EFI_ABORTED
;
1645 Status
= EFI_TIMEOUT
;
1653 switch (InputKey
.ScanCode
) {
1655 Status
= EFI_TIMEOUT
;
1659 Status
= EFI_ABORTED
;
1670 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1674 if (DescendEvent
!= NULL
) {
1675 gBS
->CloseEvent (DescendEvent
);
1678 if (TimeoutEvent
!= NULL
) {
1679 gBS
->CloseEvent (TimeoutEvent
);
1687 Select the boot menu.
1689 @param Private Pointer to PxeBc private data.
1690 @param Type The type of the menu.
1691 @param UseDefaultItem Use default item or not.
1693 @retval EFI_ABORTED User cancel operation.
1694 @retval EFI_SUCCESS Select the boot menu success.
1695 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1699 PxeBcSelectBootMenu (
1700 IN PXEBC_PRIVATE_DATA
*Private
,
1702 IN BOOLEAN UseDefaultItem
1705 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1706 PXEBC_VENDOR_OPTION
*VendorOpt
;
1707 EFI_INPUT_KEY InputKey
;
1716 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1717 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1724 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1726 Packet
= &Private
->ProxyOffer
;
1729 Packet
= &Private
->Dhcp4Ack
;
1732 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1734 VendorOpt
= &Packet
->PxeVendorOption
;
1736 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1740 SetMem (Blank
, sizeof(Blank
), ' ');
1742 MenuSize
= VendorOpt
->BootMenuLen
;
1743 MenuItem
= VendorOpt
->BootMenu
;
1745 if (MenuSize
== 0) {
1746 return EFI_NOT_READY
;
1749 while (MenuSize
> 0) {
1750 MenuArray
[Index
++] = MenuItem
;
1751 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1752 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1753 if (Index
>= PXEBC_MAX_MENU_NUM
) {
1758 if (UseDefaultItem
) {
1759 *Type
= MenuArray
[0]->Type
;
1760 *Type
= NTOHS (*Type
);
1766 for (Index
= 0; Index
< MenuNum
; Index
++) {
1767 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1770 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1773 ASSERT (Select
< PXEBC_MAX_MENU_NUM
);
1775 // highlight selected row
1777 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1778 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1779 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1780 AsciiPrint ("%a\r", Blank
);
1781 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1782 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1783 LastSelect
= Select
;
1785 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1786 gBS
->Stall (10 * TICKS_PER_MS
);
1789 if (InputKey
.ScanCode
!= 0) {
1790 switch (InputKey
.UnicodeChar
) {
1792 InputKey
.ScanCode
= SCAN_ESC
;
1795 case CTRL ('j'): /* linefeed */
1796 case CTRL ('m'): /* return */
1800 case CTRL ('i'): /* tab */
1804 InputKey
.ScanCode
= SCAN_DOWN
;
1807 case CTRL ('h'): /* backspace */
1810 InputKey
.ScanCode
= SCAN_UP
;
1814 InputKey
.ScanCode
= 0;
1818 switch (InputKey
.ScanCode
) {
1829 if (++Select
== MenuNum
) {
1840 case SCAN_PAGE_DOWN
:
1842 Select
= (UINT16
) (MenuNum
- 1);
1849 /* unhighlight last selected row */
1850 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1851 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1852 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1853 AsciiPrint ("%a\r", Blank
);
1854 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1855 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1858 ASSERT (Select
< PXEBC_MAX_MENU_NUM
);
1861 // Swap the byte order
1863 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1864 *Type
= NTOHS (*Type
);