2 Support for PxeBc dhcp functions.
4 Copyright (c) 2013, Red Hat, Inc.
5 Copyright (c) 2007 - 2017, 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 DHCP4_TAG_BOOTFILE_LEN
,
28 DHCP4_TAG_VENDOR_CLASS_ID
,
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] = DHCP4_TAG_EOP
;
70 Copy the DCHP4 packet from srouce to destination.
72 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
73 @param[in] Src Pointer to the DHCPv4 packet to be cached.
75 @retval EFI_SUCCESS Packet is copied.
76 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
80 PxeBcCopyEfiDhcp4Packet (
81 IN EFI_DHCP4_PACKET
*Dst
,
82 IN EFI_DHCP4_PACKET
*Src
85 if (Dst
->Size
< Src
->Length
) {
86 return EFI_BUFFER_TOO_SMALL
;
89 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
90 Dst
->Length
= Src
->Length
;
96 Copy the dhcp4 packet to the PxeBc private data and parse the dhcp4 packet.
98 @param Private Pointer to PxeBc private data.
99 @param OfferIndex Index of cached packets as complements of pxe mode data,
100 the index is maximum offer number.
102 @retval EFI_SUCCESS Cache and parse the packet successfully.
103 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
107 PxeBcCopyProxyOffer (
108 IN PXEBC_PRIVATE_DATA
*Private
,
112 EFI_PXE_BASE_CODE_MODE
*Mode
;
113 EFI_DHCP4_PACKET
*Offer
;
116 ASSERT (OfferIndex
< Private
->NumOffers
);
117 ASSERT (OfferIndex
< PXEBC_MAX_OFFER_NUM
);
119 Mode
= Private
->PxeBc
.Mode
;
120 Offer
= &Private
->Dhcp4Offers
[OfferIndex
].Packet
.Offer
;
122 Status
= PxeBcCopyEfiDhcp4Packet (&Private
->ProxyOffer
.Packet
.Offer
, Offer
);
123 if (EFI_ERROR(Status
)) {
126 CopyMem (&Mode
->ProxyOffer
, &Offer
->Dhcp4
, Offer
->Length
);
127 Mode
->ProxyOfferReceived
= TRUE
;
129 PxeBcParseCachedDhcpPacket (&Private
->ProxyOffer
);
135 Parse the cached dhcp packet.
137 @param CachedPacket Pointer to cached dhcp packet.
139 @retval TRUE Succeed to parse and validation.
140 @retval FALSE Fail to parse or validation.
144 PxeBcParseCachedDhcpPacket (
145 IN PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
148 EFI_DHCP4_PACKET
*Offer
;
149 EFI_DHCP4_PACKET_OPTION
**Options
;
150 EFI_DHCP4_PACKET_OPTION
*Option
;
155 CachedPacket
->IsPxeOffer
= FALSE
;
156 ZeroMem (CachedPacket
->Dhcp4Option
, sizeof (CachedPacket
->Dhcp4Option
));
157 ZeroMem (&CachedPacket
->PxeVendorOption
, sizeof (CachedPacket
->PxeVendorOption
));
159 Offer
= &CachedPacket
->Packet
.Offer
;
160 Options
= CachedPacket
->Dhcp4Option
;
163 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.
164 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
166 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
167 Options
[Index
] = PxeBcParseExtendOptions (
169 GET_OPTION_BUFFER_LEN (Offer
),
170 mInterestedDhcp4Tags
[Index
]
174 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
175 // If yes, try to parse options from the BootFileName field, then ServerName field.
177 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
178 if (Option
!= NULL
) {
179 if ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
) != 0) {
180 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
181 if (Options
[Index
] == NULL
) {
182 Options
[Index
] = PxeBcParseExtendOptions (
183 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
184 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
185 mInterestedDhcp4Tags
[Index
]
190 if ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME
) != 0) {
191 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
192 if (Options
[Index
] == NULL
) {
193 Options
[Index
] = PxeBcParseExtendOptions (
194 (UINT8
*) Offer
->Dhcp4
.Header
.ServerName
,
195 sizeof (Offer
->Dhcp4
.Header
.ServerName
),
196 mInterestedDhcp4Tags
[Index
]
204 // Check whether is an offer with PXEClient or not.
206 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
207 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
208 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
210 CachedPacket
->IsPxeOffer
= TRUE
;
214 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
216 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
217 if (CachedPacket
->IsPxeOffer
&& (Option
!= NULL
)) {
219 if (!PxeBcParseVendorOptions (Option
, &CachedPacket
->PxeVendorOption
)) {
226 // Parse PXE boot file name:
227 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
228 // Otherwise, read from boot file field in DHCP header.
230 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
232 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
233 // terminated string. So force to append null terminated character at the end of string.
235 Ptr8
= (UINT8
*)&Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
236 Ptr8
+= Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
237 if (*(Ptr8
- 1) != '\0') {
240 } else if (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0) {
242 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
243 // And do not count dhcp option header, or else will destroy the serverhostname.
245 // Make sure "BootFileName" is not overloaded.
247 if (Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
] == NULL
||
248 (Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
]->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
) == 0) {
249 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*) (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
250 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
255 // Determine offer type of the dhcp packet.
257 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
258 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
260 // It's a bootp offer
262 Option
= CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
263 if (Option
== NULL
) {
265 // bootp offer without bootfilename, discard it.
270 OfferType
= DHCP4_PACKET_TYPE_BOOTP
;
274 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
276 // It's a pxe10 offer with PXEClient and discover vendor option.
278 OfferType
= DHCP4_PACKET_TYPE_PXE10
;
279 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
281 // It's a wfm11a offer with PXEClient and mtftp vendor option, and
282 // return false since mtftp not supported currently.
287 // If the binl offer with only PXEClient.
289 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
293 CachedPacket
->OfferType
= OfferType
;
300 Offer dhcp service with a BINL dhcp offer.
302 @param Private Pointer to PxeBc private data.
303 @param Index Index of cached packets as complements of pxe mode data,
304 the index is maximum offer number.
306 @retval TRUE Offer the service successfully under priority BINL.
307 @retval FALSE Boot Service failed, parse cached dhcp packet failed or this
308 BINL ack cannot find options set or bootfile name specified.
313 IN PXEBC_PRIVATE_DATA
*Private
,
317 EFI_DHCP4_PACKET
*Offer
;
318 EFI_IP_ADDRESS ServerIp
;
320 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
321 EFI_DHCP4_PACKET
*Reply
;
323 ASSERT (Index
< PXEBC_MAX_OFFER_NUM
);
324 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
326 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
329 // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)
330 // in DHCPOFFER packet.
331 // (It does not comply with PXE Spec, Ver2.1)
333 if (EFI_IP4_EQUAL (&Offer
->Dhcp4
.Header
.ServerAddr
.Addr
, &mZeroIp4Addr
)) {
336 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
337 sizeof (EFI_IPv4_ADDRESS
)
342 &Offer
->Dhcp4
.Header
.ServerAddr
,
343 sizeof (EFI_IPv4_ADDRESS
)
346 if (ServerIp
.Addr
[0] == 0) {
350 CachedPacket
= &Private
->ProxyOffer
;
351 Reply
= &CachedPacket
->Packet
.Offer
;
353 Status
= PxeBcDiscvBootService (
364 if (EFI_ERROR (Status
)) {
368 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
372 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
373 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
375 // This BINL ack doesn't have discovery options set or bootfile name
381 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
382 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
389 Offer dhcp service for each proxy with a BINL dhcp offer.
391 @param Private Pointer to PxeBc private data
392 @param OfferIndex Pointer to the index of cached packets as complements of
393 pxe mode data, the index is maximum offer number.
395 @return If there is no service needed offer return FALSE, otherwise TRUE.
400 IN PXEBC_PRIVATE_DATA
*Private
,
401 OUT UINT32
*OfferIndex
406 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
408 *OfferIndex
= Private
->BinlIndex
[Index
];
410 // Try this BINL proxy offer
412 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
422 This function is to check the selected proxy offer (include BINL dhcp offer and
423 DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code
426 @param Private Pointer to PxeBc private data.
428 @retval EFI_SUCCESS Operational successful.
429 @retval EFI_NO_RESPONSE Offer dhcp service failed.
430 @retval EFI_BUFFER_TOO_SMALL Failed to copy the packet to Pxe base code mode.
434 PxeBcCheckSelectedOffer (
435 IN PXEBC_PRIVATE_DATA
*Private
438 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
439 EFI_DHCP4_PACKET_OPTION
**Options
;
441 EFI_DHCP4_PACKET
*Offer
;
442 UINT32 ProxyOfferIndex
;
444 EFI_PXE_BASE_CODE_MODE
*Mode
;
445 EFI_DHCP4_PACKET
*Ack
;
447 ASSERT (Private
->SelectedOffer
!= 0);
449 Status
= EFI_SUCCESS
;
450 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
451 Options
= SelectedOffer
->Dhcp4Option
;
453 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
455 // The addresses are acquired from a BINL dhcp offer, try BINL to get
458 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
459 Status
= EFI_NO_RESPONSE
;
461 } else if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) {
463 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
464 // try proxy offers if there are some, othewise the bootfile name must be
465 // set in this DHCP only offer.
467 if (Private
->GotProxyOffer
) {
469 // Get rid of the compiler warning.
472 if (Private
->SortOffers
) {
474 // The offers are sorted before selecting, the proxy offer type must be
475 // already determined.
477 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
479 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
481 // We buffer all received BINL proxy offers, try them all one by one
483 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
484 Status
= EFI_NO_RESPONSE
;
488 // For other types, only one proxy offer is buffered.
490 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
494 // The proxy offer type is not determined, choose proxy offer in the
497 Status
= EFI_NO_RESPONSE
;
499 ASSERT (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
);
500 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
502 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
503 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
505 // Skip non proxy dhcp offers.
510 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
514 if (!PxeBcTryBinl (Private
, Index
)) {
516 // Failed, skip to the next offer
522 Private
->ProxyOfferType
= Private
->Dhcp4Offers
[Index
].OfferType
;
523 ProxyOfferIndex
= Index
;
524 Status
= EFI_SUCCESS
;
529 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
531 // Copy the proxy offer to Mode and set the flag
533 Status
= PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
537 // No proxy offer is received, the bootfile name MUST be set.
539 ASSERT (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
543 if (!EFI_ERROR (Status
)) {
545 // Everything is OK, set the flag and copy the DHCP packets.
547 Mode
= Private
->PxeBc
.Mode
;
548 Offer
= &SelectedOffer
->Packet
.Offer
;
551 // The discover packet is already copied, just set flag here.
553 Mode
->DhcpDiscoverValid
= TRUE
;
555 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
556 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
558 // Other type of ACK is already cached. Bootp is special that we should
559 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
561 Status
= PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
564 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
566 Mode
->DhcpAckReceived
= TRUE
;
569 // Copy the dhcp ack.
571 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
579 Cache the Dhcp4 packet offer, Parse and validate each option of the packet.
581 @param Private Pointer to PxeBc private data.
582 @param RcvdOffer Pointer to the received Dhcp proxy offer packet.
584 @retval EFI_SUCCESS Cache and parse the packet successfully.
585 @retval Others Operation failed.
589 PxeBcCacheDhcpOffer (
590 IN PXEBC_PRIVATE_DATA
*Private
,
591 IN EFI_DHCP4_PACKET
*RcvdOffer
594 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
595 EFI_DHCP4_PACKET
*Offer
;
599 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
600 Offer
= &CachedOffer
->Packet
.Offer
;
603 // Cache the orignal dhcp packet
605 Status
= PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
606 if (EFI_ERROR(Status
)) {
611 // Parse and validate the options (including dhcp option and vendor option)
613 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
617 OfferType
= CachedOffer
->OfferType
;
618 if (OfferType
>= DHCP4_PACKET_TYPE_MAX
) {
622 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
624 if (Private
->BootpIndex
!= 0) {
626 // Only cache the first bootp offer, discard others.
631 // Take as a dhcp only offer, but record index specifically.
633 Private
->BootpIndex
= Private
->NumOffers
+ 1;
637 if (IS_PROXY_DHCP_OFFER (Offer
)) {
639 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
641 Private
->GotProxyOffer
= TRUE
;
643 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
645 // Cache all binl offers.
647 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
648 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
649 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
651 // Only cache the first pxe10/wfm11a offers each, discard the others.
656 // Record index of the proxy dhcp offer with type other than binl.
658 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
662 // It's a dhcp offer with your address.
664 ASSERT (Private
->ServerCount
[OfferType
] < PXEBC_MAX_OFFER_NUM
);
665 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
666 Private
->ServerCount
[OfferType
]++;
671 // Count the accepted offers.
673 Private
->NumOffers
++;
679 Switch the Ip4 policy to static.
681 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
683 @retval EFI_SUCCESS The policy is already configured to static.
684 @retval Others Other error as indicated..
689 IN PXEBC_PRIVATE_DATA
*Private
693 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
694 EFI_IP4_CONFIG2_POLICY Policy
;
697 Ip4Config2
= Private
->Ip4Config2
;
698 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
699 Status
= Ip4Config2
->GetData (
701 Ip4Config2DataTypePolicy
,
705 if (EFI_ERROR (Status
)) {
709 if (Policy
!= Ip4Config2PolicyStatic
) {
710 Policy
= Ip4Config2PolicyStatic
;
711 Status
= Ip4Config2
->SetData (
713 Ip4Config2DataTypePolicy
,
714 sizeof (EFI_IP4_CONFIG2_POLICY
),
717 if (EFI_ERROR (Status
)) {
727 Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.
728 If the proxy does not exist, try offers with bootfile.
730 @param Private Pointer to PxeBc private data.
735 IN PXEBC_PRIVATE_DATA
*Private
740 EFI_DHCP4_PACKET
*Offer
;
742 Private
->SelectedOffer
= 0;
744 if (Private
->SortOffers
) {
746 // Select offer according to the priority
748 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
752 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
754 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
758 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
760 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
761 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
764 // DHCP only and proxy DHCP with PXE10
766 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
767 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
769 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
770 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
773 // DHCP only and proxy DHCP with WfM
775 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
776 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
778 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
782 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
784 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
785 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
788 // DHCP only and proxy DHCP with BINL
790 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
791 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
795 // Try offers with bootfile
797 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
799 // Select the first DHCP only offer with bootfile
801 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
802 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
803 Private
->SelectedOffer
= OfferIndex
+ 1;
808 if (Private
->SelectedOffer
== 0) {
810 // Select the Bootp reply with bootfile if any
812 Private
->SelectedOffer
= Private
->BootpIndex
;
817 // Try the offers in the received order.
819 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
821 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
823 if (IS_PROXY_DHCP_OFFER (Offer
)) {
830 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
831 ((!Private
->GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
833 // DHCP only offer but no proxy offer received and no bootfile option in this offer
838 Private
->SelectedOffer
= Index
+ 1;
848 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
849 to intercept events that occurred in the configuration process. This structure
850 provides advanced control of each state transition of the DHCP process. The
851 returned status code determines the behavior of the EFI DHCPv4 Protocol driver.
852 There are three possible returned values, which are described in the following
855 @param This Pointer to the EFI DHCPv4 Protocol instance that is used to
856 configure this callback function.
857 @param Context Pointer to the context that is initialized by
858 EFI_DHCP4_PROTOCOL.Configure().
859 @param CurrentState The current operational state of the EFI DHCPv4 Protocol
861 @param Dhcp4Event The event that occurs in the current state, which usually means a
863 @param Packet The DHCP packet that is going to be sent or already received.
864 @param NewPacket The packet that is used to replace the above Packet.
866 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
867 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
868 driver will continue to wait for more DHCPOFFER packets until the retry
870 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and
871 return to the Dhcp4Init or Dhcp4InitReboot state.
877 IN EFI_DHCP4_PROTOCOL
* This
,
879 IN EFI_DHCP4_STATE CurrentState
,
880 IN EFI_DHCP4_EVENT Dhcp4Event
,
881 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
882 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
885 PXEBC_PRIVATE_DATA
*Private
;
886 EFI_PXE_BASE_CODE_MODE
*Mode
;
887 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
888 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
892 EFI_DHCP4_HEADER
*DhcpHeader
;
894 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
895 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
896 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
897 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
898 (Dhcp4Event
!= Dhcp4SendRequest
)) {
902 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
903 Mode
= Private
->PxeBc
.Mode
;
904 Callback
= Private
->PxeBcCallback
;
907 // Override the Maximum DHCP Message Size.
909 MaxMsgSize
= PxeBcParseExtendOptions (
910 Packet
->Dhcp4
.Option
,
911 GET_OPTION_BUFFER_LEN (Packet
),
914 if (MaxMsgSize
!= NULL
) {
915 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
916 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
919 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
920 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
921 Status
= Callback
->Callback (
926 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
928 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
933 Status
= EFI_SUCCESS
;
935 switch (Dhcp4Event
) {
937 case Dhcp4SendDiscover
:
938 case Dhcp4SendRequest
:
939 if (Packet
->Length
> PXEBC_DHCP4_MAX_PACKET_SIZE
) {
941 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
943 Status
= EFI_ABORTED
;
947 if (Mode
->SendGUID
) {
949 // send the system GUID instead of the MAC address as the hardware address
950 // in the DHCP packet header.
952 DhcpHeader
= &Packet
->Dhcp4
.Header
;
954 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
))) {
956 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
957 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
958 // GUID not yet set - send all 0's to show not programable
960 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
963 DhcpHeader
->HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
966 if (Dhcp4Event
== Dhcp4SendDiscover
) {
968 // Cache the dhcp discover packet, of which some information will be used later.
970 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
976 Status
= EFI_NOT_READY
;
977 if (Packet
->Length
> PXEBC_DHCP4_MAX_PACKET_SIZE
) {
979 // Ignore the incoming Offers which exceed the maximum length.
984 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
986 // Cache the dhcp offers in Private->Dhcp4Offers[]
987 // If error happens, just ignore this packet and continue to wait more offer.
989 PxeBcCacheDhcpOffer (Private
, Packet
);
994 case Dhcp4SelectOffer
:
996 // Select an offer, if succeeded, Private->SelectedOffer points to
997 // the index of the selected one.
999 PxeBcSelectOffer (Private
);
1001 if (Private
->SelectedOffer
== 0) {
1002 Status
= EFI_ABORTED
;
1004 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
1013 ASSERT (Private
->SelectedOffer
!= 0);
1015 Status
= PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
1016 if (EFI_ERROR (Status
)) {
1030 Initialize the DHCP options and build the option list.
1032 @param Private Pointer to PxeBc private data.
1033 @param OptList Pointer to a DHCP option list.
1035 @param IsDhcpDiscover Discover dhcp option or not.
1037 @return The index item number of the option list.
1041 PxeBcBuildDhcpOptions (
1042 IN PXEBC_PRIVATE_DATA
*Private
,
1043 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
1044 IN BOOLEAN IsDhcpDiscover
1048 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
1052 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
1054 if (!IsDhcpDiscover
) {
1056 // Append message type.
1058 OptList
[Index
]->OpCode
= DHCP4_TAG_MSG_TYPE
;
1059 OptList
[Index
]->Length
= 1;
1060 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
1061 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
1063 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1066 // Append max message size.
1068 OptList
[Index
]->OpCode
= DHCP4_TAG_MAXMSG
;
1069 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
1070 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
1071 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
1072 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
1074 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1077 // Parameter request list option.
1079 OptList
[Index
]->OpCode
= DHCP4_TAG_PARA_LIST
;
1080 OptList
[Index
]->Length
= 35;
1081 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
1082 OptEnt
.Para
->ParaList
[0] = DHCP4_TAG_NETMASK
;
1083 OptEnt
.Para
->ParaList
[1] = DHCP4_TAG_TIME_OFFSET
;
1084 OptEnt
.Para
->ParaList
[2] = DHCP4_TAG_ROUTER
;
1085 OptEnt
.Para
->ParaList
[3] = DHCP4_TAG_TIME_SERVER
;
1086 OptEnt
.Para
->ParaList
[4] = DHCP4_TAG_NAME_SERVER
;
1087 OptEnt
.Para
->ParaList
[5] = DHCP4_TAG_DNS_SERVER
;
1088 OptEnt
.Para
->ParaList
[6] = DHCP4_TAG_HOSTNAME
;
1089 OptEnt
.Para
->ParaList
[7] = DHCP4_TAG_BOOTFILE_LEN
;
1090 OptEnt
.Para
->ParaList
[8] = DHCP4_TAG_DOMAINNAME
;
1091 OptEnt
.Para
->ParaList
[9] = DHCP4_TAG_ROOTPATH
;
1092 OptEnt
.Para
->ParaList
[10] = DHCP4_TAG_EXTEND_PATH
;
1093 OptEnt
.Para
->ParaList
[11] = DHCP4_TAG_EMTU
;
1094 OptEnt
.Para
->ParaList
[12] = DHCP4_TAG_TTL
;
1095 OptEnt
.Para
->ParaList
[13] = DHCP4_TAG_BROADCAST
;
1096 OptEnt
.Para
->ParaList
[14] = DHCP4_TAG_NIS_DOMAIN
;
1097 OptEnt
.Para
->ParaList
[15] = DHCP4_TAG_NIS_SERVER
;
1098 OptEnt
.Para
->ParaList
[16] = DHCP4_TAG_NTP_SERVER
;
1099 OptEnt
.Para
->ParaList
[17] = DHCP4_TAG_VENDOR
;
1100 OptEnt
.Para
->ParaList
[18] = DHCP4_TAG_REQUEST_IP
;
1101 OptEnt
.Para
->ParaList
[19] = DHCP4_TAG_LEASE
;
1102 OptEnt
.Para
->ParaList
[20] = DHCP4_TAG_SERVER_ID
;
1103 OptEnt
.Para
->ParaList
[21] = DHCP4_TAG_T1
;
1104 OptEnt
.Para
->ParaList
[22] = DHCP4_TAG_T2
;
1105 OptEnt
.Para
->ParaList
[23] = DHCP4_TAG_VENDOR_CLASS_ID
;
1106 OptEnt
.Para
->ParaList
[24] = DHCP4_TAG_TFTP
;
1107 OptEnt
.Para
->ParaList
[25] = DHCP4_TAG_BOOTFILE
;
1108 OptEnt
.Para
->ParaList
[26] = DHCP4_TAG_UUID
;
1109 OptEnt
.Para
->ParaList
[27] = 0x80;
1110 OptEnt
.Para
->ParaList
[28] = 0x81;
1111 OptEnt
.Para
->ParaList
[29] = 0x82;
1112 OptEnt
.Para
->ParaList
[30] = 0x83;
1113 OptEnt
.Para
->ParaList
[31] = 0x84;
1114 OptEnt
.Para
->ParaList
[32] = 0x85;
1115 OptEnt
.Para
->ParaList
[33] = 0x86;
1116 OptEnt
.Para
->ParaList
[34] = 0x87;
1118 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1121 // Append UUID/Guid-based client identifier option
1123 OptList
[Index
]->OpCode
= DHCP4_TAG_UUID
;
1124 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UUID
);
1125 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
1126 OptEnt
.Uuid
->Type
= 0;
1128 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1130 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) OptEnt
.Uuid
->Guid
))) {
1132 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
1133 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
1134 // GUID not yet set - send all 0's to show not programable
1136 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
1140 // Append client network device interface option
1142 OptList
[Index
]->OpCode
= DHCP4_TAG_UNDI
;
1143 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UNDI
);
1144 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
1145 if (Private
->Nii
!= NULL
) {
1146 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
1147 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
1148 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
1150 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
1151 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
1152 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
1156 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1159 // Append client system architecture option
1161 OptList
[Index
]->OpCode
= DHCP4_TAG_ARCH
;
1162 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1163 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1164 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
1165 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1167 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1170 // Append client system architecture option
1172 OptList
[Index
]->OpCode
= DHCP4_TAG_VENDOR_CLASS_ID
;
1173 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_CLID
);
1174 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1175 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1176 CvtNum (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1178 if (Private
->Nii
!= NULL
) {
1180 // If NII protocol exists, update DHCP option data
1182 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1183 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1184 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1194 Discover the boot of service and initialize the vendor option if exists.
1196 @param Private Pointer to PxeBc private data.
1197 @param Type PxeBc option boot item type
1198 @param Layer PxeBc option boot item layer
1199 @param UseBis Use BIS or not
1200 @param DestIp Ip address for server
1201 @param IpCount The total count of the server ip address
1202 @param SrvList Server list
1203 @param IsDiscv Discover the vendor or not
1204 @param Reply The dhcp4 packet of Pxe reply
1206 @retval EFI_SUCCESS Operation succeeds.
1207 @retval EFI_OUT_OF_RESOURCES Allocate memory pool failed.
1208 @retval EFI_NOT_FOUND There is no vendor option exists.
1209 @retval EFI_TIMEOUT Send Pxe Discover time out.
1213 PxeBcDiscvBootService (
1214 IN PXEBC_PRIVATE_DATA
* Private
,
1218 IN EFI_IP_ADDRESS
* DestIp
,
1220 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1222 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1225 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1226 EFI_PXE_BASE_CODE_MODE
*Mode
;
1227 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1228 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1234 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1235 EFI_DHCP4_PACKET
*Response
;
1236 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1238 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1239 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1241 EFI_DHCP4_HEADER
*DhcpHeader
;
1244 Mode
= Private
->PxeBc
.Mode
;
1245 Dhcp4
= Private
->Dhcp4
;
1246 Status
= EFI_SUCCESS
;
1248 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1250 if (DestIp
== NULL
) {
1251 Sport
= PXEBC_DHCP4_S_PORT
;
1254 Sport
= PXEBC_BS_DISCOVER_PORT
;
1258 if (!UseBis
&& Layer
!= NULL
) {
1259 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1262 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1265 ASSERT (Layer
!= NULL
);
1267 // Add vendor option of PXE_BOOT_ITEM
1269 VendorOptLen
= (UINT8
) ((sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1);
1270 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1271 if (OptList
[OptCount
] == NULL
) {
1272 return EFI_OUT_OF_RESOURCES
;
1275 OptList
[OptCount
]->OpCode
= DHCP4_TAG_VENDOR
;
1276 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1277 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1278 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1279 PxeOpt
->Length
= (UINT8
) sizeof (PXEBC_OPTION_BOOT_ITEM
);
1280 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1281 PxeBootItem
->Type
= HTONS (Type
);
1282 PxeBootItem
->Layer
= HTONS (*Layer
);
1283 PxeOpt
->Data
[PxeOpt
->Length
] = DHCP4_TAG_EOP
;
1288 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1291 FreePool (OptList
[OptCount
- 1]);
1294 if (EFI_ERROR (Status
)) {
1298 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1299 if (Mode
->SendGUID
) {
1300 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
))) {
1302 // GUID not yet set - send all 0's to show not programable
1304 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1307 DhcpHeader
->HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
1310 Xid
= NET_RANDOM (NetRandomInitSeed ());
1311 Token
.Packet
->Dhcp4
.Header
.Xid
= HTONL(Xid
);
1312 Token
.Packet
->Dhcp4
.Header
.Reserved
= HTONS((UINT16
) ((IsBCast
) ? 0x8000 : 0));
1313 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1315 Token
.RemotePort
= Sport
;
1318 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1320 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1323 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1326 Token
.ListenPointCount
= 1;
1327 Token
.ListenPoints
= &ListenPoint
;
1328 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1329 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1330 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1333 // Send Pxe Discover
1335 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1337 Token
.TimeoutValue
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
);
1338 Token
.Packet
->Dhcp4
.Header
.Seconds
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* (TryIndex
- 1));
1340 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1342 if (Token
.Status
!= EFI_TIMEOUT
) {
1347 if (TryIndex
> PXEBC_BOOT_REQUEST_RETRIES
) {
1349 // No server response our PXE request
1351 Status
= EFI_TIMEOUT
;
1354 if (!EFI_ERROR (Status
)) {
1360 Response
= Token
.ResponseList
;
1362 while (RepIndex
< Token
.ResponseCount
) {
1363 if (Response
->Length
> PXEBC_DHCP4_MAX_PACKET_SIZE
) {
1366 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1370 while (SrvIndex
< IpCount
) {
1372 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1376 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1383 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1389 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1392 if (RepIndex
< Token
.ResponseCount
) {
1394 if (Reply
!= NULL
) {
1395 Status
= PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1396 if (EFI_ERROR(Status
)) {
1402 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1403 Mode
->PxeDiscoverValid
= TRUE
;
1405 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1406 Mode
->PxeReplyReceived
= TRUE
;
1409 Status
= EFI_NOT_FOUND
;
1415 // free the responselist
1417 if (Token
.ResponseList
!= NULL
) {
1418 FreePool (Token
.ResponseList
);
1421 // Free the dhcp packet
1423 if (Token
.Packet
!= NULL
) {
1424 FreePool (Token
.Packet
);
1432 Parse interested dhcp options.
1434 @param Buffer Pointer to the dhcp options packet.
1435 @param Length The length of the dhcp options.
1436 @param OptTag The option OpCode.
1438 @return NULL if the buffer length is 0 and OpCode is not
1439 DHCP4_TAG_EOP, or the pointer to the buffer.
1442 EFI_DHCP4_PACKET_OPTION
*
1443 PxeBcParseExtendOptions (
1449 EFI_DHCP4_PACKET_OPTION
*Option
;
1452 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1455 while (Offset
< Length
&& Option
->OpCode
!= DHCP4_TAG_EOP
) {
1457 if (Option
->OpCode
== OptTag
) {
1462 if (Option
->OpCode
== DHCP4_TAG_PAD
) {
1465 Offset
+= Option
->Length
+ 2;
1468 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1476 This function is to parse and check vendor options.
1478 @param Dhcp4Option Pointer to dhcp options
1479 @param VendorOption Pointer to vendor options
1481 @return TRUE if valid for vendor options, or FALSE.
1485 PxeBcParseVendorOptions (
1486 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1487 IN PXEBC_VENDOR_OPTION
*VendorOption
1491 UINT8 VendorOptionLen
;
1492 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1495 BitMap
= VendorOption
->BitMap
;
1496 VendorOptionLen
= Dhcp4Option
->Length
;
1497 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1500 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= DHCP4_TAG_EOP
)) {
1502 // Parse every Vendor Option and set its BitMap
1504 switch (PxeOption
->OpCode
) {
1506 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1508 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1511 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1513 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1516 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1518 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1521 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1523 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1526 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1528 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1531 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1533 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1536 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1538 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1541 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1543 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1544 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1547 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1549 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1550 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1553 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1555 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1556 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1559 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1561 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1562 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1563 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1566 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1568 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1569 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1572 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1574 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1575 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1579 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1581 if (PxeOption
->OpCode
== DHCP4_TAG_PAD
) {
1584 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1587 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1591 // FixMe, return falas if invalid of any vendor option
1599 This function display boot item detail.
1601 If the length of the boot item string over 70 Char, just display 70 Char.
1603 @param Str Pointer to a string (boot item string).
1604 @param Len The length of string.
1608 PxeBcDisplayBootItem (
1615 Len
= (UINT8
) MIN (70, Len
);
1618 AsciiPrint ("%a \n", Str
);
1624 Choose the boot prompt.
1626 @param Private Pointer to PxeBc private data.
1628 @retval EFI_SUCCESS Select boot prompt done.
1629 @retval EFI_TIMEOUT Select boot prompt time out.
1630 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
1631 @retval EFI_ABORTED User cancel the operation.
1632 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1636 PxeBcSelectBootPrompt (
1637 IN PXEBC_PRIVATE_DATA
*Private
1640 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1641 PXEBC_VENDOR_OPTION
*VendorOpt
;
1642 EFI_EVENT TimeoutEvent
;
1643 EFI_EVENT DescendEvent
;
1644 EFI_INPUT_KEY InputKey
;
1652 TimeoutEvent
= NULL
;
1653 DescendEvent
= NULL
;
1655 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1657 Packet
= &Private
->ProxyOffer
;
1660 Packet
= &Private
->Dhcp4Ack
;
1663 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1664 return EFI_NOT_FOUND
;
1667 VendorOpt
= &Packet
->PxeVendorOption
;
1669 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options (Full
1670 // List), we must not consider a boot prompt or boot menu if all of the
1672 // - the PXE_DISCOVERY_CONTROL PXE tag is present inside the Vendor Options
1673 // (=43) DHCP tag, and
1674 // - the PXE_DISCOVERY_CONTROL PXE tag has bit 3 set, and
1675 // - a boot file name has been presented with DHCP option 67.
1677 if (IS_DISABLE_PROMPT_MENU (VendorOpt
->DiscoverCtrl
) &&
1678 Packet
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
1682 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1686 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1687 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1688 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1694 if (Timeout
== 255) {
1698 Status
= gBS
->CreateEvent (
1706 if (EFI_ERROR (Status
)) {
1710 Status
= gBS
->SetTimer (
1713 MultU64x32 (Timeout
, TICKS_PER_SECOND
)
1716 if (EFI_ERROR (Status
)) {
1720 Status
= gBS
->CreateEvent (
1728 if (EFI_ERROR (Status
)) {
1732 Status
= gBS
->SetTimer (
1738 if (EFI_ERROR (Status
)) {
1742 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1743 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1745 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1747 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1748 AsciiPrint ("(%d) ", Timeout
--);
1750 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1752 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1753 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1754 AsciiPrint ("(%d) ", Timeout
--);
1757 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1759 gBS
->Stall (10 * TICKS_PER_MS
);
1763 if (InputKey
.ScanCode
== 0) {
1765 switch (InputKey
.UnicodeChar
) {
1767 Status
= EFI_ABORTED
;
1773 Status
= EFI_TIMEOUT
;
1781 switch (InputKey
.ScanCode
) {
1783 Status
= EFI_TIMEOUT
;
1787 Status
= EFI_ABORTED
;
1798 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1802 if (DescendEvent
!= NULL
) {
1803 gBS
->CloseEvent (DescendEvent
);
1806 if (TimeoutEvent
!= NULL
) {
1807 gBS
->CloseEvent (TimeoutEvent
);
1815 Select the boot menu.
1817 @param Private Pointer to PxeBc private data.
1818 @param Type The type of the menu.
1819 @param UseDefaultItem Use default item or not.
1821 @retval EFI_ABORTED User cancel operation.
1822 @retval EFI_SUCCESS Select the boot menu success.
1823 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1827 PxeBcSelectBootMenu (
1828 IN PXEBC_PRIVATE_DATA
*Private
,
1830 IN BOOLEAN UseDefaultItem
1833 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1834 PXEBC_VENDOR_OPTION
*VendorOpt
;
1835 EFI_INPUT_KEY InputKey
;
1844 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1845 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1852 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1854 Packet
= &Private
->ProxyOffer
;
1857 Packet
= &Private
->Dhcp4Ack
;
1860 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1862 VendorOpt
= &Packet
->PxeVendorOption
;
1864 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1868 SetMem (Blank
, sizeof(Blank
), ' ');
1870 MenuSize
= VendorOpt
->BootMenuLen
;
1871 MenuItem
= VendorOpt
->BootMenu
;
1873 if (MenuSize
== 0) {
1874 return EFI_NOT_READY
;
1877 while (MenuSize
> 0) {
1878 MenuArray
[Index
++] = MenuItem
;
1879 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1880 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1881 if (Index
>= PXEBC_MAX_MENU_NUM
) {
1886 if (UseDefaultItem
) {
1887 *Type
= MenuArray
[0]->Type
;
1888 *Type
= NTOHS (*Type
);
1894 for (Index
= 0; Index
< MenuNum
; Index
++) {
1895 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1898 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1901 ASSERT (Select
< PXEBC_MAX_MENU_NUM
);
1903 // highlight selected row
1905 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1906 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1907 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1908 AsciiPrint ("%a\r", Blank
);
1909 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1910 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1911 LastSelect
= Select
;
1913 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1914 gBS
->Stall (10 * TICKS_PER_MS
);
1917 if (InputKey
.ScanCode
== 0) {
1918 switch (InputKey
.UnicodeChar
) {
1920 InputKey
.ScanCode
= SCAN_ESC
;
1923 case CTRL ('j'): /* linefeed */
1924 case CTRL ('m'): /* return */
1928 case CTRL ('i'): /* tab */
1932 InputKey
.ScanCode
= SCAN_DOWN
;
1935 case CTRL ('h'): /* backspace */
1938 InputKey
.ScanCode
= SCAN_UP
;
1942 InputKey
.ScanCode
= 0;
1946 switch (InputKey
.ScanCode
) {
1957 if (++Select
== MenuNum
) {
1968 case SCAN_PAGE_DOWN
:
1970 Select
= (UINT16
) (MenuNum
- 1);
1977 /* unhighlight last selected row */
1978 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1979 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1980 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1981 AsciiPrint ("%a\r", Blank
);
1982 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1983 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1986 ASSERT (Select
< PXEBC_MAX_MENU_NUM
);
1989 // Swap the byte order
1991 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1992 *Type
= NTOHS (*Type
);