2 Support for PxeBc dhcp functions.
4 Copyright (c) 2013, Red Hat, Inc.
5 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
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.
150 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
152 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
153 Options
[Index
] = PxeBcParseExtendOptions (
155 GET_OPTION_BUFFER_LEN (Offer
),
156 mInterestedDhcp4Tags
[Index
]
160 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
161 // If yes, try to parse options from the BootFileName field, then ServerName field.
163 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
164 if (Option
!= NULL
) {
165 if ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
) != 0) {
166 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
167 if (Options
[Index
] == NULL
) {
168 Options
[Index
] = PxeBcParseExtendOptions (
169 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
170 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
171 mInterestedDhcp4Tags
[Index
]
176 if ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME
) != 0) {
177 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
178 if (Options
[Index
] == NULL
) {
179 Options
[Index
] = PxeBcParseExtendOptions (
180 (UINT8
*) Offer
->Dhcp4
.Header
.ServerName
,
181 sizeof (Offer
->Dhcp4
.Header
.ServerName
),
182 mInterestedDhcp4Tags
[Index
]
190 // Check whether is an offer with PXEClient or not.
192 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
193 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
194 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
196 CachedPacket
->IsPxeOffer
= TRUE
;
200 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
202 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
203 if (CachedPacket
->IsPxeOffer
&& (Option
!= NULL
)) {
205 if (!PxeBcParseVendorOptions (Option
, &CachedPacket
->PxeVendorOption
)) {
212 // Parse PXE boot file name:
213 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
214 // Otherwise, read from boot file field in DHCP header.
216 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
218 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
219 // terminated string. So force to append null terminated character at the end of string.
221 Ptr8
= (UINT8
*)&Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
222 Ptr8
+= Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
223 if (*(Ptr8
- 1) != '\0') {
226 } else if (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0) {
228 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
229 // And do not count dhcp option header, or else will destroy the serverhostname.
231 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*) (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
232 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
237 // Determine offer type of the dhcp packet.
239 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
240 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
242 // It's a bootp offer
244 Option
= CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
245 if (Option
== NULL
) {
247 // bootp offer without bootfilename, discard it.
252 OfferType
= DHCP4_PACKET_TYPE_BOOTP
;
256 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
258 // It's a pxe10 offer with PXEClient and discover vendor option.
260 OfferType
= DHCP4_PACKET_TYPE_PXE10
;
261 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
263 // It's a wfm11a offer with PXEClient and mtftp vendor option, and
264 // return false since mtftp not supported currently.
269 // If the binl offer with only PXEClient.
271 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
275 CachedPacket
->OfferType
= OfferType
;
282 Offer dhcp service with a BINL dhcp offer.
284 @param Private Pointer to PxeBc private data.
285 @param Index Index of cached packets as complements of pxe mode data,
286 the index is maximum offer number.
288 @retval TRUE Offer the service successfully under priority BINL.
289 @retval FALSE Boot Service failed, parse cached dhcp packet failed or this
290 BINL ack cannot find options set or bootfile name specified.
295 IN PXEBC_PRIVATE_DATA
*Private
,
299 EFI_DHCP4_PACKET
*Offer
;
300 EFI_IP_ADDRESS ServerIp
;
302 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
303 EFI_DHCP4_PACKET
*Reply
;
305 ASSERT (Index
< PXEBC_MAX_OFFER_NUM
);
306 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
308 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
311 // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)
312 // in DHCPOFFER packet.
313 // (It does not comply with PXE Spec, Ver2.1)
315 if (EFI_IP4_EQUAL (&Offer
->Dhcp4
.Header
.ServerAddr
.Addr
, &mZeroIp4Addr
)) {
318 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
319 sizeof (EFI_IPv4_ADDRESS
)
324 &Offer
->Dhcp4
.Header
.ServerAddr
,
325 sizeof (EFI_IPv4_ADDRESS
)
328 if (ServerIp
.Addr
[0] == 0) {
332 CachedPacket
= &Private
->ProxyOffer
;
333 Reply
= &CachedPacket
->Packet
.Offer
;
335 Status
= PxeBcDiscvBootService (
346 if (EFI_ERROR (Status
)) {
350 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
354 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
355 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
357 // This BINL ack doesn't have discovery options set or bootfile name
363 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
364 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
371 Offer dhcp service for each proxy with a BINL dhcp offer.
373 @param Private Pointer to PxeBc private data
374 @param OfferIndex Pointer to the index of cached packets as complements of
375 pxe mode data, the index is maximum offer number.
377 @return If there is no service needed offer return FALSE, otherwise TRUE.
382 IN PXEBC_PRIVATE_DATA
*Private
,
383 OUT UINT32
*OfferIndex
388 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
390 *OfferIndex
= Private
->BinlIndex
[Index
];
392 // Try this BINL proxy offer
394 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
404 This function is to check the selected proxy offer (include BINL dhcp offer and
405 DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code
408 @param Private Pointer to PxeBc private data.
410 @retval EFI_SUCCESS Operational successful.
411 @retval EFI_NO_RESPONSE Offer dhcp service failed.
415 PxeBcCheckSelectedOffer (
416 IN PXEBC_PRIVATE_DATA
*Private
419 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
420 EFI_DHCP4_PACKET_OPTION
**Options
;
422 EFI_DHCP4_PACKET
*Offer
;
423 UINT32 ProxyOfferIndex
;
425 EFI_PXE_BASE_CODE_MODE
*Mode
;
426 EFI_DHCP4_PACKET
*Ack
;
428 ASSERT (Private
->SelectedOffer
!= 0);
430 Status
= EFI_SUCCESS
;
431 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
432 Options
= SelectedOffer
->Dhcp4Option
;
434 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
436 // The addresses are acquired from a BINL dhcp offer, try BINL to get
439 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
440 Status
= EFI_NO_RESPONSE
;
442 } else if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) {
444 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
445 // try proxy offers if there are some, othewise the bootfile name must be
446 // set in this DHCP only offer.
448 if (Private
->GotProxyOffer
) {
450 // Get rid of the compiler warning.
453 if (Private
->SortOffers
) {
455 // The offers are sorted before selecting, the proxy offer type must be
456 // already determined.
458 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
460 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
462 // We buffer all received BINL proxy offers, try them all one by one
464 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
465 Status
= EFI_NO_RESPONSE
;
469 // For other types, only one proxy offer is buffered.
471 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
475 // The proxy offer type is not determined, choose proxy offer in the
478 Status
= EFI_NO_RESPONSE
;
480 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
482 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
483 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
485 // Skip non proxy dhcp offers.
490 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
494 if (!PxeBcTryBinl (Private
, Index
)) {
496 // Failed, skip to the next offer
502 Private
->ProxyOfferType
= Private
->Dhcp4Offers
[Index
].OfferType
;
503 ProxyOfferIndex
= Index
;
504 Status
= EFI_SUCCESS
;
509 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
511 // Copy the proxy offer to Mode and set the flag
513 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
517 // No proxy offer is received, the bootfile name MUST be set.
519 ASSERT (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
523 if (!EFI_ERROR (Status
)) {
525 // Everything is OK, set the flag and copy the DHCP packets.
527 Mode
= Private
->PxeBc
.Mode
;
528 Offer
= &SelectedOffer
->Packet
.Offer
;
531 // The discover packet is already copied, just set flag here.
533 Mode
->DhcpDiscoverValid
= TRUE
;
535 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
536 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
538 // Other type of ACK is already cached. Bootp is special that we should
539 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
541 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
544 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
546 Mode
->DhcpAckReceived
= TRUE
;
549 // Copy the dhcp ack.
551 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
559 Cache the Dhcp4 packet offer, Parse and validate each option of the packet.
561 @param Private Pointer to PxeBc private data.
562 @param RcvdOffer Pointer to the received Dhcp proxy offer packet.
566 PxeBcCacheDhcpOffer (
567 IN PXEBC_PRIVATE_DATA
*Private
,
568 IN EFI_DHCP4_PACKET
*RcvdOffer
571 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
572 EFI_DHCP4_PACKET
*Offer
;
575 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
576 Offer
= &CachedOffer
->Packet
.Offer
;
579 // Cache the orignal dhcp packet
581 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
584 // Parse and validate the options (including dhcp option and vendor option)
586 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
590 OfferType
= CachedOffer
->OfferType
;
591 if (OfferType
>= DHCP4_PACKET_TYPE_MAX
) {
595 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
597 if (Private
->BootpIndex
!= 0) {
599 // Only cache the first bootp offer, discard others.
604 // Take as a dhcp only offer, but record index specifically.
606 Private
->BootpIndex
= Private
->NumOffers
+ 1;
610 if (IS_PROXY_DHCP_OFFER (Offer
)) {
612 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
614 Private
->GotProxyOffer
= TRUE
;
616 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
618 // Cache all binl offers.
620 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
621 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
622 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
624 // Only cache the first pxe10/wfm11a offers each, discard the others.
629 // Record index of the proxy dhcp offer with type other than binl.
631 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
635 // It's a dhcp offer with your address.
637 ASSERT (Private
->ServerCount
[OfferType
] < PXEBC_MAX_OFFER_NUM
);
638 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
639 Private
->ServerCount
[OfferType
]++;
644 // Count the accepted offers.
646 Private
->NumOffers
++;
651 Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.
652 If the proxy does not exist, try offers with bootfile.
654 @param Private Pointer to PxeBc private data.
659 IN PXEBC_PRIVATE_DATA
*Private
664 EFI_DHCP4_PACKET
*Offer
;
666 Private
->SelectedOffer
= 0;
668 if (Private
->SortOffers
) {
670 // Select offer according to the priority
672 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
676 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
678 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
682 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
684 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
685 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
688 // DHCP only and proxy DHCP with PXE10
690 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
691 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
693 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
694 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
697 // DHCP only and proxy DHCP with WfM
699 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
700 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
702 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
706 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
708 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
709 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
712 // DHCP only and proxy DHCP with BINL
714 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
715 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
719 // Try offers with bootfile
721 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
723 // Select the first DHCP only offer with bootfile
725 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
726 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
727 Private
->SelectedOffer
= OfferIndex
+ 1;
732 if (Private
->SelectedOffer
== 0) {
734 // Select the Bootp reply with bootfile if any
736 Private
->SelectedOffer
= Private
->BootpIndex
;
741 // Try the offers in the received order.
743 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
745 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
747 if (IS_PROXY_DHCP_OFFER (Offer
)) {
754 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
755 ((!Private
->GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
757 // DHCP only offer but no proxy offer received and no bootfile option in this offer
762 Private
->SelectedOffer
= Index
+ 1;
772 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
773 to intercept events that occurred in the configuration process. This structure
774 provides advanced control of each state transition of the DHCP process. The
775 returned status code determines the behavior of the EFI DHCPv4 Protocol driver.
776 There are three possible returned values, which are described in the following
779 @param This Pointer to the EFI DHCPv4 Protocol instance that is used to
780 configure this callback function.
781 @param Context Pointer to the context that is initialized by
782 EFI_DHCP4_PROTOCOL.Configure().
783 @param CurrentState The current operational state of the EFI DHCPv4 Protocol
785 @param Dhcp4Event The event that occurs in the current state, which usually means a
787 @param Packet The DHCP packet that is going to be sent or already received.
788 @param NewPacket The packet that is used to replace the above Packet.
790 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
791 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
792 driver will continue to wait for more DHCPOFFER packets until the retry
794 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and
795 return to the Dhcp4Init or Dhcp4InitReboot state.
801 IN EFI_DHCP4_PROTOCOL
* This
,
803 IN EFI_DHCP4_STATE CurrentState
,
804 IN EFI_DHCP4_EVENT Dhcp4Event
,
805 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
806 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
809 PXEBC_PRIVATE_DATA
*Private
;
810 EFI_PXE_BASE_CODE_MODE
*Mode
;
811 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
812 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
816 EFI_DHCP4_HEADER
*DhcpHeader
;
818 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
819 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
820 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
821 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
822 (Dhcp4Event
!= Dhcp4SendRequest
)) {
826 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
827 Mode
= Private
->PxeBc
.Mode
;
828 Callback
= Private
->PxeBcCallback
;
831 // Override the Maximum DHCP Message Size.
833 MaxMsgSize
= PxeBcParseExtendOptions (
834 Packet
->Dhcp4
.Option
,
835 GET_OPTION_BUFFER_LEN (Packet
),
836 PXEBC_DHCP4_TAG_MAXMSG
838 if (MaxMsgSize
!= NULL
) {
839 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
840 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
843 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
844 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
845 Status
= Callback
->Callback (
850 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
852 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
857 Status
= EFI_SUCCESS
;
859 switch (Dhcp4Event
) {
861 case Dhcp4SendDiscover
:
862 case Dhcp4SendRequest
:
863 if (Mode
->SendGUID
) {
865 // send the system GUID instead of the MAC address as the hardware address
866 // in the DHCP packet header.
868 DhcpHeader
= &Packet
->Dhcp4
.Header
;
870 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
))) {
872 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
873 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
874 // GUID not yet set - send all 0's to show not programable
876 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
879 DhcpHeader
->HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
882 if (Dhcp4Event
== Dhcp4SendDiscover
) {
884 // Cache the dhcp discover packet, of which some information will be used later.
886 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
892 Status
= EFI_NOT_READY
;
893 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
895 // Cache the dhcp offers in Private->Dhcp4Offers[]
897 PxeBcCacheDhcpOffer (Private
, Packet
);
902 case Dhcp4SelectOffer
:
904 // Select an offer, if succeeded, Private->SelectedOffer points to
905 // the index of the selected one.
907 PxeBcSelectOffer (Private
);
909 if (Private
->SelectedOffer
== 0) {
910 Status
= EFI_ABORTED
;
912 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
921 ASSERT (Private
->SelectedOffer
!= 0);
923 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
935 Initialize the DHCP options and build the option list.
937 @param Private Pointer to PxeBc private data.
938 @param OptList Pointer to a DHCP option list.
940 @param IsDhcpDiscover Discover dhcp option or not.
942 @return The index item number of the option list.
946 PxeBcBuildDhcpOptions (
947 IN PXEBC_PRIVATE_DATA
*Private
,
948 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
949 IN BOOLEAN IsDhcpDiscover
953 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
957 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
959 if (!IsDhcpDiscover
) {
961 // Append message type.
963 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
964 OptList
[Index
]->Length
= 1;
965 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
966 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
968 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
971 // Append max message size.
973 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
974 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
975 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
976 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
977 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
979 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
982 // Parameter request list option.
984 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
985 OptList
[Index
]->Length
= 35;
986 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
987 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
988 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
989 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
990 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
991 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
992 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
993 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
994 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
995 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
996 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
997 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
998 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
999 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
1000 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
1001 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
1002 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
1003 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
1004 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
1005 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
1006 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
1007 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
1008 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
1009 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
1010 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
1011 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
1012 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
1013 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
1014 OptEnt
.Para
->ParaList
[27] = 0x80;
1015 OptEnt
.Para
->ParaList
[28] = 0x81;
1016 OptEnt
.Para
->ParaList
[29] = 0x82;
1017 OptEnt
.Para
->ParaList
[30] = 0x83;
1018 OptEnt
.Para
->ParaList
[31] = 0x84;
1019 OptEnt
.Para
->ParaList
[32] = 0x85;
1020 OptEnt
.Para
->ParaList
[33] = 0x86;
1021 OptEnt
.Para
->ParaList
[34] = 0x87;
1023 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1026 // Append UUID/Guid-based client identifier option
1028 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
1029 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UUID
);
1030 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
1031 OptEnt
.Uuid
->Type
= 0;
1033 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1035 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) OptEnt
.Uuid
->Guid
))) {
1037 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
1038 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
1039 // GUID not yet set - send all 0's to show not programable
1041 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
1045 // Append client network device interface option
1047 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
1048 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UNDI
);
1049 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
1050 if (Private
->Nii
!= NULL
) {
1051 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
1052 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
1053 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
1055 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
1056 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
1057 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
1061 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1064 // Append client system architecture option
1066 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
1067 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1068 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1069 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
1070 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1072 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1075 // Append client system architecture option
1077 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
1078 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_CLID
);
1079 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1080 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1081 CvtNum (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1083 if (Private
->Nii
!= NULL
) {
1085 // If NII protocol exists, update DHCP option data
1087 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1088 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1089 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1099 Discover the boot of service and initialize the vendor option if exists.
1101 @param Private Pointer to PxeBc private data.
1102 @param Type PxeBc option boot item type
1103 @param Layer PxeBc option boot item layer
1104 @param UseBis Use BIS or not
1105 @param DestIp Ip address for server
1106 @param IpCount The total count of the server ip address
1107 @param SrvList Server list
1108 @param IsDiscv Discover the vendor or not
1109 @param Reply The dhcp4 packet of Pxe reply
1111 @retval EFI_SUCCESS Operation succeeds.
1112 @retval EFI_OUT_OF_RESOURCES Allocate memory pool failed.
1113 @retval EFI_NOT_FOUND There is no vendor option exists.
1114 @retval EFI_TIMEOUT Send Pxe Discover time out.
1118 PxeBcDiscvBootService (
1119 IN PXEBC_PRIVATE_DATA
* Private
,
1123 IN EFI_IP_ADDRESS
* DestIp
,
1125 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1127 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1130 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1131 EFI_PXE_BASE_CODE_MODE
*Mode
;
1132 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1133 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1139 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1140 EFI_DHCP4_PACKET
*Response
;
1141 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1143 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1144 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1146 EFI_DHCP4_HEADER
*DhcpHeader
;
1149 Mode
= Private
->PxeBc
.Mode
;
1150 Dhcp4
= Private
->Dhcp4
;
1151 Status
= EFI_SUCCESS
;
1153 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1155 if (DestIp
== NULL
) {
1156 Sport
= PXEBC_DHCP4_S_PORT
;
1159 Sport
= PXEBC_BS_DISCOVER_PORT
;
1163 if (!UseBis
&& Layer
!= NULL
) {
1164 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1167 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1170 ASSERT (Layer
!= NULL
);
1172 // Add vendor option of PXE_BOOT_ITEM
1174 VendorOptLen
= (UINT8
) ((sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1);
1175 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1176 if (OptList
[OptCount
] == NULL
) {
1177 return EFI_OUT_OF_RESOURCES
;
1180 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1181 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1182 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1183 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1184 PxeOpt
->Length
= (UINT8
) sizeof (PXEBC_OPTION_BOOT_ITEM
);
1185 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1186 PxeBootItem
->Type
= HTONS (Type
);
1187 PxeBootItem
->Layer
= HTONS (*Layer
);
1188 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1193 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1196 FreePool (OptList
[OptCount
- 1]);
1199 if (EFI_ERROR (Status
)) {
1203 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1204 if (Mode
->SendGUID
) {
1205 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
))) {
1207 // GUID not yet set - send all 0's to show not programable
1209 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1212 DhcpHeader
->HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
1215 Xid
= NET_RANDOM (NetRandomInitSeed ());
1216 Token
.Packet
->Dhcp4
.Header
.Xid
= HTONL(Xid
);
1217 Token
.Packet
->Dhcp4
.Header
.Reserved
= HTONS((UINT16
) ((IsBCast
) ? 0x8000 : 0));
1218 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1220 Token
.RemotePort
= Sport
;
1223 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1225 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1228 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1231 Token
.ListenPointCount
= 1;
1232 Token
.ListenPoints
= &ListenPoint
;
1233 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1234 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1235 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1238 // Send Pxe Discover
1240 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1242 Token
.TimeoutValue
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
);
1243 Token
.Packet
->Dhcp4
.Header
.Seconds
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* (TryIndex
- 1));
1245 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1247 if (Token
.Status
!= EFI_TIMEOUT
) {
1252 if (TryIndex
> PXEBC_BOOT_REQUEST_RETRIES
) {
1254 // No server response our PXE request
1256 Status
= EFI_TIMEOUT
;
1259 if (!EFI_ERROR (Status
)) {
1265 Response
= Token
.ResponseList
;
1267 while (RepIndex
< Token
.ResponseCount
) {
1269 while (SrvIndex
< IpCount
) {
1271 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1275 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1282 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1289 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1292 if (RepIndex
< Token
.ResponseCount
) {
1294 if (Reply
!= NULL
) {
1295 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1299 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1300 Mode
->PxeDiscoverValid
= TRUE
;
1302 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1303 Mode
->PxeReplyReceived
= TRUE
;
1306 Status
= EFI_NOT_FOUND
;
1310 // free the responselist
1312 if (Token
.ResponseList
!= NULL
) {
1313 FreePool (Token
.ResponseList
);
1317 // Free the dhcp packet
1319 FreePool (Token
.Packet
);
1326 Parse interested dhcp options.
1328 @param Buffer Pointer to the dhcp options packet.
1329 @param Length The length of the dhcp options.
1330 @param OptTag The option OpCode.
1332 @return NULL if the buffer length is 0 and OpCode is not
1333 PXEBC_DHCP4_TAG_EOP, or the pointer to the buffer.
1336 EFI_DHCP4_PACKET_OPTION
*
1337 PxeBcParseExtendOptions (
1343 EFI_DHCP4_PACKET_OPTION
*Option
;
1346 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1349 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1351 if (Option
->OpCode
== OptTag
) {
1356 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1359 Offset
+= Option
->Length
+ 2;
1362 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1370 This function is to parse and check vendor options.
1372 @param Dhcp4Option Pointer to dhcp options
1373 @param VendorOption Pointer to vendor options
1375 @return TRUE if valid for vendor options, or FALSE.
1379 PxeBcParseVendorOptions (
1380 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1381 IN PXEBC_VENDOR_OPTION
*VendorOption
1385 UINT8 VendorOptionLen
;
1386 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1389 BitMap
= VendorOption
->BitMap
;
1390 VendorOptionLen
= Dhcp4Option
->Length
;
1391 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1394 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1396 // Parse every Vendor Option and set its BitMap
1398 switch (PxeOption
->OpCode
) {
1400 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1402 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1405 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1407 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1410 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1412 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1415 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1417 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1420 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1422 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1425 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1427 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1430 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1432 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1435 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1437 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1438 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1441 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1443 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1444 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1447 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1449 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1450 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1453 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1455 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1456 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1457 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1460 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1462 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1463 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1466 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1468 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1469 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1473 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1475 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1478 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1481 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1485 // FixMe, return falas if invalid of any vendor option
1493 This function display boot item detail.
1495 If the length of the boot item string over 70 Char, just display 70 Char.
1497 @param Str Pointer to a string (boot item string).
1498 @param Len The length of string.
1502 PxeBcDisplayBootItem (
1509 Len
= (UINT8
) MIN (70, Len
);
1512 AsciiPrint ("%a \n", Str
);
1518 Choose the boot prompt.
1520 @param Private Pointer to PxeBc private data.
1522 @retval EFI_SUCCESS Select boot prompt done.
1523 @retval EFI_TIMEOUT Select boot prompt time out.
1524 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
1525 @retval EFI_ABORTED User cancel the operation.
1526 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1530 PxeBcSelectBootPrompt (
1531 IN PXEBC_PRIVATE_DATA
*Private
1534 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1535 PXEBC_VENDOR_OPTION
*VendorOpt
;
1536 EFI_EVENT TimeoutEvent
;
1537 EFI_EVENT DescendEvent
;
1538 EFI_INPUT_KEY InputKey
;
1546 TimeoutEvent
= NULL
;
1547 DescendEvent
= NULL
;
1549 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1551 Packet
= &Private
->ProxyOffer
;
1554 Packet
= &Private
->Dhcp4Ack
;
1557 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1558 return EFI_NOT_FOUND
;
1561 VendorOpt
= &Packet
->PxeVendorOption
;
1563 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options (Full
1564 // List), we must not consider a boot prompt or boot menu if all of the
1566 // - the PXE_DISCOVERY_CONTROL PXE tag is present inside the Vendor Options
1567 // (=43) DHCP tag, and
1568 // - the PXE_DISCOVERY_CONTROL PXE tag has bit 3 set, and
1569 // - a boot file name has been presented with DHCP option 67.
1571 if (IS_DISABLE_PROMPT_MENU (VendorOpt
->DiscoverCtrl
) &&
1572 Packet
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
1576 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1580 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1581 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1582 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1588 if (Timeout
== 255) {
1592 Status
= gBS
->CreateEvent (
1600 if (EFI_ERROR (Status
)) {
1604 Status
= gBS
->SetTimer (
1607 Timeout
* TICKS_PER_SECOND
1610 if (EFI_ERROR (Status
)) {
1614 Status
= gBS
->CreateEvent (
1622 if (EFI_ERROR (Status
)) {
1626 Status
= gBS
->SetTimer (
1632 if (EFI_ERROR (Status
)) {
1636 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1637 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1639 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1641 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1642 AsciiPrint ("(%d) ", Timeout
--);
1644 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1646 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1647 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1648 AsciiPrint ("(%d) ", Timeout
--);
1651 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1653 gBS
->Stall (10 * TICKS_PER_MS
);
1657 if (InputKey
.ScanCode
== 0) {
1659 switch (InputKey
.UnicodeChar
) {
1661 Status
= EFI_ABORTED
;
1667 Status
= EFI_TIMEOUT
;
1675 switch (InputKey
.ScanCode
) {
1677 Status
= EFI_TIMEOUT
;
1681 Status
= EFI_ABORTED
;
1692 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1696 if (DescendEvent
!= NULL
) {
1697 gBS
->CloseEvent (DescendEvent
);
1700 if (TimeoutEvent
!= NULL
) {
1701 gBS
->CloseEvent (TimeoutEvent
);
1709 Select the boot menu.
1711 @param Private Pointer to PxeBc private data.
1712 @param Type The type of the menu.
1713 @param UseDefaultItem Use default item or not.
1715 @retval EFI_ABORTED User cancel operation.
1716 @retval EFI_SUCCESS Select the boot menu success.
1717 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1721 PxeBcSelectBootMenu (
1722 IN PXEBC_PRIVATE_DATA
*Private
,
1724 IN BOOLEAN UseDefaultItem
1727 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1728 PXEBC_VENDOR_OPTION
*VendorOpt
;
1729 EFI_INPUT_KEY InputKey
;
1738 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1739 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1746 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1748 Packet
= &Private
->ProxyOffer
;
1751 Packet
= &Private
->Dhcp4Ack
;
1754 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1756 VendorOpt
= &Packet
->PxeVendorOption
;
1758 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1762 SetMem (Blank
, sizeof(Blank
), ' ');
1764 MenuSize
= VendorOpt
->BootMenuLen
;
1765 MenuItem
= VendorOpt
->BootMenu
;
1767 if (MenuSize
== 0) {
1768 return EFI_NOT_READY
;
1771 while (MenuSize
> 0) {
1772 MenuArray
[Index
++] = MenuItem
;
1773 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1774 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1775 if (Index
>= PXEBC_MAX_MENU_NUM
) {
1780 if (UseDefaultItem
) {
1781 *Type
= MenuArray
[0]->Type
;
1782 *Type
= NTOHS (*Type
);
1788 for (Index
= 0; Index
< MenuNum
; Index
++) {
1789 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1792 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1795 ASSERT (Select
< PXEBC_MAX_MENU_NUM
);
1797 // highlight selected row
1799 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1800 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1801 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1802 AsciiPrint ("%a\r", Blank
);
1803 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1804 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1805 LastSelect
= Select
;
1807 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1808 gBS
->Stall (10 * TICKS_PER_MS
);
1811 if (InputKey
.ScanCode
!= 0) {
1812 switch (InputKey
.UnicodeChar
) {
1814 InputKey
.ScanCode
= SCAN_ESC
;
1817 case CTRL ('j'): /* linefeed */
1818 case CTRL ('m'): /* return */
1822 case CTRL ('i'): /* tab */
1826 InputKey
.ScanCode
= SCAN_DOWN
;
1829 case CTRL ('h'): /* backspace */
1832 InputKey
.ScanCode
= SCAN_UP
;
1836 InputKey
.ScanCode
= 0;
1840 switch (InputKey
.ScanCode
) {
1851 if (++Select
== MenuNum
) {
1862 case SCAN_PAGE_DOWN
:
1864 Select
= (UINT16
) (MenuNum
- 1);
1871 /* unhighlight last selected row */
1872 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1873 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1874 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1875 AsciiPrint ("%a\r", Blank
);
1876 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1877 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1880 ASSERT (Select
< PXEBC_MAX_MENU_NUM
);
1883 // Swap the byte order
1885 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1886 *Type
= NTOHS (*Type
);