2 Support for PxeBc dhcp functions.
4 Copyright (c) 2007 - 2008, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PxeBcImpl.h"
19 // This is a map from the interested DHCP4 option tags' index to the tag value.
21 UINT8 mInterestedDhcp4Tags
[PXEBC_DHCP4_TAG_INDEX_MAX
] = {
22 PXEBC_DHCP4_TAG_BOOTFILE_LEN
,
23 PXEBC_DHCP4_TAG_VENDOR
,
24 PXEBC_DHCP4_TAG_OVERLOAD
,
25 PXEBC_DHCP4_TAG_MSG_TYPE
,
26 PXEBC_DHCP4_TAG_SERVER_ID
,
27 PXEBC_DHCP4_TAG_CLASS_ID
,
28 PXEBC_DHCP4_TAG_BOOTFILE
33 This function initialize the DHCP4 message instance.
35 This function will pad each item of dhcp4 message packet.
37 @param Seed Pointer to the message instance of the DHCP4 packet.
38 @param Udp4 Pointer to the EFI_UDP4_PROTOCOL instance.
45 IN EFI_DHCP4_PACKET
*Seed
,
46 IN EFI_UDP4_PROTOCOL
*Udp4
49 EFI_SIMPLE_NETWORK_MODE Mode
;
50 EFI_DHCP4_HEADER
*Header
;
52 Udp4
->GetModeData (Udp4
, NULL
, NULL
, NULL
, &Mode
);
54 Seed
->Size
= sizeof (EFI_DHCP4_PACKET
);
55 Seed
->Length
= sizeof (Seed
->Dhcp4
);
57 Header
= &Seed
->Dhcp4
.Header
;
59 ZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
60 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
61 Header
->HwType
= Mode
.IfType
;
62 Header
->HwAddrLen
= (UINT8
) Mode
.HwAddressSize
;
63 CopyMem (Header
->ClientHwAddr
, &Mode
.CurrentAddress
, Header
->HwAddrLen
);
65 Seed
->Dhcp4
.Magik
= PXEBC_DHCP4_MAGIC
;
66 Seed
->Dhcp4
.Option
[0] = PXEBC_DHCP4_TAG_EOP
;
71 Copy the DCHP4 packet from srouce to destination.
73 @param Dst Pointer to the EFI_DHCP4_PROTOCOL instance.
74 @param Src Pointer to the EFI_DHCP4_PROTOCOL instance.
80 PxeBcCopyEfiDhcp4Packet (
81 IN EFI_DHCP4_PACKET
*Dst
,
82 IN EFI_DHCP4_PACKET
*Src
85 ASSERT (Dst
->Size
>= Src
->Length
);
87 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
88 Dst
->Length
= Src
->Length
;
93 Copy the dhcp4 packet to the PxeBc private data and parse the dhcp4 packet.
95 @param Private Pointer to PxeBc private data.
96 @param OfferIndex Index of cached packets as complements of pxe mode data,
97 the index is maximum offer number.
103 PxeBcCopyProxyOffer (
104 IN PXEBC_PRIVATE_DATA
*Private
,
108 EFI_PXE_BASE_CODE_MODE
*Mode
;
109 EFI_DHCP4_PACKET
*Offer
;
111 ASSERT (OfferIndex
< Private
->NumOffers
);
113 Mode
= Private
->PxeBc
.Mode
;
114 Offer
= &Private
->Dhcp4Offers
[OfferIndex
].Packet
.Offer
;
116 PxeBcCopyEfiDhcp4Packet (&Private
->ProxyOffer
.Packet
.Offer
, Offer
);
117 CopyMem (&Mode
->ProxyOffer
, &Offer
->Dhcp4
, Offer
->Length
);
118 Mode
->ProxyOfferReceived
= TRUE
;
120 PxeBcParseCachedDhcpPacket (&Private
->ProxyOffer
);
125 Parse the cached dhcp packet.
127 @param CachedPacket Pointer to cached dhcp packet.
129 @retval TRUE Succeed to parse and validation.
130 @retval FALSE Fail to parse or validation.
134 PxeBcParseCachedDhcpPacket (
135 IN PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
138 EFI_DHCP4_PACKET
*Offer
;
139 EFI_DHCP4_PACKET_OPTION
**Options
;
140 EFI_DHCP4_PACKET_OPTION
*Option
;
144 CachedPacket
->IsPxeOffer
= FALSE
;
145 ZeroMem (CachedPacket
->Dhcp4Option
, sizeof (CachedPacket
->Dhcp4Option
));
146 ZeroMem (&CachedPacket
->PxeVendorOption
, sizeof (CachedPacket
->PxeVendorOption
));
148 Offer
= &CachedPacket
->Packet
.Offer
;
149 Options
= CachedPacket
->Dhcp4Option
;
152 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.
154 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
155 Options
[Index
] = PxeBcParseExtendOptions (
157 GET_OPTION_BUFFER_LEN (Offer
),
158 mInterestedDhcp4Tags
[Index
]
163 // Check whether is an offer with PXEClient or not.
165 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
166 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
167 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
169 CachedPacket
->IsPxeOffer
= TRUE
;
173 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
175 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
176 if (CachedPacket
->IsPxeOffer
&& (Option
!= NULL
)) {
178 if (!PxeBcParseVendorOptions (Option
, &CachedPacket
->PxeVendorOption
)) {
184 // Check whether bootfilename/serverhostname overloaded (See details in dhcp spec).
185 // If overloaded, parse this buffer as nested dhcp options, or just parse bootfilename/
186 // serverhostname option.
188 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
189 if ((Option
!= NULL
) && (Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
)) {
191 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = PxeBcParseExtendOptions (
192 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
193 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
194 PXEBC_DHCP4_TAG_BOOTFILE
197 } else if ((Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) &&
198 (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
200 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
201 // And do not count dhcp option header, or else will destory the serverhostname.
203 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*) (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
204 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
209 // Determine offer type of the dhcp packet.
211 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
212 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
214 // It's a bootp offer
216 Option
= CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
217 if (Option
== NULL
) {
219 // bootp offer without bootfilename, discard it.
224 OfferType
= DHCP4_PACKET_TYPE_BOOTP
;
228 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
230 // It's a pxe10 offer with PXEClient and discover vendor option.
232 OfferType
= DHCP4_PACKET_TYPE_PXE10
;
233 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
235 // It's a wfm11a offer with PXEClient and mtftp vendor option, and
236 // return false since mtftp not supported currently.
241 // If the binl offer with only PXEClient.
243 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
247 CachedPacket
->OfferType
= OfferType
;
254 Offer dhcp service with a BINL dhcp offer.
256 @param Private Pointer to PxeBc private data.
257 @param Index Index of cached packets as complements of pxe mode data,
258 the index is maximum offer number.
260 @retval TRUE Offer the service successfully under priority BINL.
261 @retval FALSE Boot Service failed, parse cached dhcp packet failed or this
262 BINL ack cannot find options set or bootfile name specified.
267 IN PXEBC_PRIVATE_DATA
*Private
,
271 EFI_DHCP4_PACKET
*Offer
;
272 EFI_IP_ADDRESS ServerIp
;
274 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
275 EFI_DHCP4_PACKET
*Reply
;
277 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
279 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
280 if (Offer
->Dhcp4
.Header
.ServerAddr
.Addr
[0] == 0) {
282 // next server ip address is zero, use server id option instead.
286 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
287 sizeof (EFI_IPv4_ADDRESS
)
291 // use next server ip address.
293 CopyMem (&ServerIp
.Addr
[0], &Offer
->Dhcp4
.Header
.ServerAddr
, sizeof (EFI_IPv4_ADDRESS
));
296 CachedPacket
= &Private
->ProxyOffer
;
297 Reply
= &CachedPacket
->Packet
.Offer
;
299 Status
= PxeBcDiscvBootService (
310 if (EFI_ERROR (Status
)) {
314 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
318 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
319 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
321 // This BINL ack doesn't have discovery options set or bootfile name
327 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
328 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
335 Offer dhcp service for each proxy with a BINL dhcp offer.
337 @param Private Pointer to PxeBc private data
338 @param OfferIndex Pointer to the index of cached packets as complements of
339 pxe mode data, the index is maximum offer number.
341 @return If there is no service needed offer return FALSE, otherwise TRUE.
346 IN PXEBC_PRIVATE_DATA
*Private
,
347 OUT UINT32
*OfferIndex
352 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
354 *OfferIndex
= Private
->BinlIndex
[Index
];
356 // Try this BINL proxy offer
358 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
368 This function is to check the selected proxy offer (include BINL dhcp offer and
369 DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code
372 @param Private Pointer to PxeBc private data.
374 @retval EFI_SUCCESS Operational successful.
375 @retval EFI_NO_RESPONSE Offer dhcp service failed.
379 PxeBcCheckSelectedOffer (
380 IN PXEBC_PRIVATE_DATA
*Private
383 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
384 EFI_DHCP4_PACKET_OPTION
**Options
;
386 EFI_DHCP4_PACKET
*Offer
;
387 UINT32 ProxyOfferIndex
;
389 EFI_PXE_BASE_CODE_MODE
*Mode
;
390 EFI_DHCP4_PACKET
*Ack
;
392 ASSERT (Private
->SelectedOffer
!= 0);
394 Status
= EFI_SUCCESS
;
395 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
396 Options
= SelectedOffer
->Dhcp4Option
;
398 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
400 // The addresses are acquired from a BINL dhcp offer, try BINL to get
403 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
404 Status
= EFI_NO_RESPONSE
;
406 } else if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) {
408 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
409 // try proxy offers if there are some, othewise the bootfile name must be
410 // set in this DHCP only offer.
412 if (Private
->GotProxyOffer
) {
414 // Get rid of the compiler warning.
417 if (Private
->SortOffers
) {
419 // The offers are sorted before selecting, the proxy offer type must be
420 // already determined.
422 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
424 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
426 // We buffer all received BINL proxy offers, try them all one by one
428 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
429 Status
= EFI_NO_RESPONSE
;
433 // For other types, only one proxy offer is buffered.
435 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
439 // The proxy offer type is not determined, choose proxy offer in the
442 Status
= EFI_NO_RESPONSE
;
444 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
446 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
447 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
449 // Skip non proxy dhcp offers.
454 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
458 if (!PxeBcTryBinl (Private
, Index
)) {
460 // Failed, skip to the next offer
466 Private
->ProxyOfferType
= Private
->Dhcp4Offers
[Index
].OfferType
;
467 ProxyOfferIndex
= Index
;
468 Status
= EFI_SUCCESS
;
473 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
475 // Copy the proxy offer to Mode and set the flag
477 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
481 // No proxy offer is received, the bootfile name MUST be set.
483 ASSERT (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
487 if (!EFI_ERROR (Status
)) {
489 // Everything is OK, set the flag and copy the DHCP packets.
491 Mode
= Private
->PxeBc
.Mode
;
492 Offer
= &SelectedOffer
->Packet
.Offer
;
495 // The discover packet is already copied, just set flag here.
497 Mode
->DhcpDiscoverValid
= TRUE
;
499 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
500 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
502 // Other type of ACK is already cached. Bootp is special that we should
503 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
505 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
508 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
510 Mode
->DhcpAckReceived
= TRUE
;
513 // Copy the dhcp ack.
515 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
523 Cache the Dhcp4 packet offer, Parse and validate each option of the packet.
525 @param Private Pointer to PxeBc private data.
526 @param RcvdOffer Pointer to the received Dhcp proxy offer packet.
532 PxeBcCacheDhcpOffer (
533 IN PXEBC_PRIVATE_DATA
*Private
,
534 IN EFI_DHCP4_PACKET
*RcvdOffer
537 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
538 EFI_DHCP4_PACKET
*Offer
;
541 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
542 Offer
= &CachedOffer
->Packet
.Offer
;
545 // Cache the orignal dhcp packet
547 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
550 // Parse and validate the options (including dhcp option and vendor option)
552 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
556 OfferType
= CachedOffer
->OfferType
;
558 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
560 if (Private
->BootpIndex
!= 0) {
562 // Only cache the first bootp offer, discard others.
567 // Take as a dhcp only offer, but record index specifically.
569 Private
->BootpIndex
= Private
->NumOffers
+ 1;
573 if (IS_PROXY_DHCP_OFFER (Offer
)) {
575 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
577 Private
->GotProxyOffer
= TRUE
;
579 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
581 // Cache all binl offers.
583 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
584 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
585 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
587 // Only cache the first pxe10/wfm11a offers each, discard the others.
592 // Record index of the proxy dhcp offer with type other than binl.
594 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
598 // It's a dhcp offer with your address.
600 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
601 Private
->ServerCount
[OfferType
]++;
606 // Count the accepted offers.
608 Private
->NumOffers
++;
613 Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.
614 If the proxy does not exist, try offers with bootfile.
616 @param Private Pointer to PxeBc private data.
623 IN PXEBC_PRIVATE_DATA
*Private
628 EFI_DHCP4_PACKET
*Offer
;
630 Private
->SelectedOffer
= 0;
632 if (Private
->SortOffers
) {
634 // Select offer according to the priority
636 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
640 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
642 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
646 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
648 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
649 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
652 // DHCP only and proxy DHCP with PXE10
654 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
655 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
657 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
658 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
661 // DHCP only and proxy DHCP with WfM
663 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
664 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
666 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
670 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
672 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
673 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
676 // DHCP only and proxy DHCP with BINL
678 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
679 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
683 // Try offers with bootfile
685 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
687 // Select the first DHCP only offer with bootfile
689 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
690 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
691 Private
->SelectedOffer
= OfferIndex
+ 1;
696 if (Private
->SelectedOffer
== 0) {
698 // Select the Bootp reply with bootfile if any
700 Private
->SelectedOffer
= Private
->BootpIndex
;
705 // Try the offers in the received order.
707 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
709 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
711 if (IS_PROXY_DHCP_OFFER (Offer
)) {
718 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
719 ((!Private
->GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
721 // DHCP only offer but no proxy offer received and no bootfile option in this offer
726 Private
->SelectedOffer
= Index
+ 1;
736 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
737 to intercept events that occurred in the configuration process. This structure
738 provides advanced control of each state transition of the DHCP process. The
739 returned status code determines the behavior of the EFI DHCPv4 Protocol driver.
740 There are three possible returned values, which are described in the following
743 @param This Pointer to the EFI DHCPv4 Protocol instance that is used to
744 configure this callback function.
745 @param Context Pointer to the context that is initialized by
746 EFI_DHCP4_PROTOCOL.Configure().
747 @param CurrentState The current operational state of the EFI DHCPv4 Protocol
749 @param Dhcp4Event The event that occurs in the current state, which usually means a
751 @param Packet The DHCP packet that is going to be sent or already received.
752 @param NewPacket The packet that is used to replace the above Packet.
754 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
755 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
756 driver will continue to wait for more DHCPOFFER packets until the retry
758 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and
759 return to the Dhcp4Init or Dhcp4InitReboot state.
764 IN EFI_DHCP4_PROTOCOL
* This
,
766 IN EFI_DHCP4_STATE CurrentState
,
767 IN EFI_DHCP4_EVENT Dhcp4Event
,
768 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
769 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
772 PXEBC_PRIVATE_DATA
*Private
;
773 EFI_PXE_BASE_CODE_MODE
*Mode
;
774 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
775 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
779 CHAR8
*SystemSerialNumber
;
780 EFI_DHCP4_HEADER
*DhcpHeader
;
782 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
783 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
784 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
785 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
786 (Dhcp4Event
!= Dhcp4SendRequest
)) {
790 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
791 Mode
= Private
->PxeBc
.Mode
;
792 Callback
= Private
->PxeBcCallback
;
795 // Override the Maximum DHCP Message Size.
797 MaxMsgSize
= PxeBcParseExtendOptions (
798 Packet
->Dhcp4
.Option
,
799 GET_OPTION_BUFFER_LEN (Packet
),
800 PXEBC_DHCP4_TAG_MAXMSG
802 if (MaxMsgSize
!= NULL
) {
803 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
804 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
807 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
808 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
809 Status
= Callback
->Callback (
814 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
816 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
821 Status
= EFI_SUCCESS
;
823 switch (Dhcp4Event
) {
825 case Dhcp4SendDiscover
:
826 case Dhcp4SendRequest
:
827 if (Mode
->SendGUID
) {
829 // send the system GUID instead of the MAC address as the hardware address
830 // in the DHCP packet header.
832 DhcpHeader
= &Packet
->Dhcp4
.Header
;
834 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
836 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
837 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
838 // GUID not yet set - send all 0's to show not programable
840 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
843 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
846 if (Dhcp4Event
== Dhcp4SendDiscover
) {
848 // Cache the dhcp discover packet, of which some information will be used later.
850 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
856 Status
= EFI_NOT_READY
;
857 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
859 // Cache the dhcp offers in Private->Dhcp4Offers[]
861 PxeBcCacheDhcpOffer (Private
, Packet
);
866 case Dhcp4SelectOffer
:
868 // Select an offer, if succeeded, Private->SelectedOffer points to
869 // the index of the selected one.
871 PxeBcSelectOffer (Private
);
873 if (Private
->SelectedOffer
== 0) {
874 Status
= EFI_ABORTED
;
876 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
885 ASSERT (Private
->SelectedOffer
!= 0);
887 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
899 Initialize the DHCP options and build the option list.
901 @param Private Pointer to PxeBc private data.
902 @param OptList Pointer to a DHCP option list.
904 @param IsDhcpDiscover Discover dhcp option or not.
906 @return The index item number of the option list.
910 PxeBcBuildDhcpOptions (
911 IN PXEBC_PRIVATE_DATA
*Private
,
912 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
913 IN BOOLEAN IsDhcpDiscover
917 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
919 CHAR8
*SystemSerialNumber
;
922 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
924 if (!IsDhcpDiscover
) {
926 // Append message type.
928 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
929 OptList
[Index
]->Length
= 1;
930 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
931 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
933 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
936 // Append max message size.
938 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
939 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
940 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
941 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
942 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
944 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
947 // Parameter request list option.
949 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
950 OptList
[Index
]->Length
= 35;
951 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
952 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
953 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
954 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
955 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
956 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
957 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
958 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
959 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
960 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
961 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
962 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
963 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
964 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
965 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
966 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
967 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
968 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
969 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
970 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
971 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
972 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
973 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
974 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
975 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
976 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
977 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
978 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
979 OptEnt
.Para
->ParaList
[27] = 0x80;
980 OptEnt
.Para
->ParaList
[28] = 0x81;
981 OptEnt
.Para
->ParaList
[29] = 0x82;
982 OptEnt
.Para
->ParaList
[30] = 0x83;
983 OptEnt
.Para
->ParaList
[31] = 0x84;
984 OptEnt
.Para
->ParaList
[32] = 0x85;
985 OptEnt
.Para
->ParaList
[33] = 0x86;
986 OptEnt
.Para
->ParaList
[34] = 0x87;
988 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
991 // Append UUID/Guid-based client identifier option
993 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
994 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
995 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
996 OptEnt
.Uuid
->Type
= 0;
998 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1000 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
1002 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
1003 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
1004 // GUID not yet set - send all 0's to show not programable
1006 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
1010 // Append client network device interface option
1012 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
1013 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
1014 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
1015 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
1016 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
1017 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
1020 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1023 // Append client system architecture option
1025 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
1026 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1027 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1028 Value
= HTONS (SYS_ARCH
);
1029 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1031 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1034 // Append client system architecture option
1036 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
1037 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
1038 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1039 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1040 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1041 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1042 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1043 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1051 Discover the boot of service and initialize the vendor option if exists.
1053 @param Private Pointer to PxeBc private data.
1054 @param Type PxeBc option boot item type
1055 @param Layer PxeBc option boot item layer
1056 @param UseBis Use BIS or not
1057 @param DestIp Ip address for server
1058 @param IpCount The total count of the server ip address
1059 @param SrvList Server list
1060 @param IsDiscv Discover the vendor or not
1061 @param Reply The dhcp4 packet of Pxe reply
1063 @retval EFI_SUCCESS Operation succeeds.
1064 @retval EFI_OUT_OF_RESOURCES Allocate memory pool failed.
1065 @retval EFI_NOT_FOUND There is no vendor option exists.
1066 @retval EFI_TIMEOUT Send Pxe Discover time out.
1070 PxeBcDiscvBootService (
1071 IN PXEBC_PRIVATE_DATA
* Private
,
1075 IN EFI_IP_ADDRESS
* DestIp
,
1077 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1079 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1082 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1083 EFI_PXE_BASE_CODE_MODE
*Mode
;
1084 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1085 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1091 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1092 EFI_DHCP4_PACKET
*Response
;
1093 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1095 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1096 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1098 CHAR8
*SystemSerialNumber
;
1099 EFI_DHCP4_HEADER
*DhcpHeader
;
1102 Mode
= Private
->PxeBc
.Mode
;
1103 Dhcp4
= Private
->Dhcp4
;
1104 Status
= EFI_SUCCESS
;
1106 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1108 if (DestIp
== NULL
) {
1109 Sport
= PXEBC_DHCP4_S_PORT
;
1112 Sport
= PXEBC_BS_DISCOVER_PORT
;
1116 if (!UseBis
&& Layer
!= NULL
) {
1117 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1120 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1124 // Add vendor option of PXE_BOOT_ITEM
1126 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1127 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1128 if (OptList
[OptCount
] == NULL
) {
1129 return EFI_OUT_OF_RESOURCES
;
1132 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1133 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1134 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1135 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1136 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1137 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1138 PxeBootItem
->Type
= HTONS (Type
);
1139 PxeBootItem
->Layer
= HTONS (*Layer
);
1140 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1145 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1148 gBS
->FreePool (OptList
[OptCount
- 1]);
1151 if (EFI_ERROR (Status
)) {
1155 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1156 if (Mode
->SendGUID
) {
1157 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
1159 // GUID not yet set - send all 0's to show not programable
1161 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1164 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
1167 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1168 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1169 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1171 Token
.RemotePort
= Sport
;
1173 if (DestIp
== NULL
) {
1174 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1176 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1179 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1182 Token
.ListenPointCount
= 1;
1183 Token
.ListenPoints
= &ListenPoint
;
1184 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1185 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1186 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1189 // Send Pxe Discover
1191 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1193 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1195 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1197 if (Token
.Status
!= EFI_TIMEOUT
) {
1202 if (!EFI_ERROR (Status
)) {
1208 Response
= Token
.ResponseList
;
1210 while (RepIndex
< Token
.ResponseCount
) {
1212 while (SrvIndex
< IpCount
) {
1214 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1218 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1225 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1232 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1235 if (RepIndex
< Token
.ResponseCount
) {
1237 if (Reply
!= NULL
) {
1238 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1242 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1243 Mode
->PxeDiscoverValid
= TRUE
;
1245 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1246 Mode
->PxeReplyReceived
= TRUE
;
1249 Status
= EFI_NOT_FOUND
;
1253 // free the responselist
1255 gBS
->FreePool (Token
.ResponseList
);
1258 // Free the dhcp packet
1260 gBS
->FreePool (Token
.Packet
);
1267 Parse interested dhcp options.
1269 @param Buffer Pointer to the dhcp options packet.
1270 @param Length The length of the dhcp options.
1271 @param OptTag The option OpCode.
1273 @return NULL if the buffer length is 0 and OpCode is not
1274 PXEBC_DHCP4_TAG_EOP, or the pointer to the buffer.
1277 EFI_DHCP4_PACKET_OPTION
*
1278 PxeBcParseExtendOptions (
1284 EFI_DHCP4_PACKET_OPTION
*Option
;
1287 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1290 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1292 if (Option
->OpCode
== OptTag
) {
1297 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1300 Offset
+= Option
->Length
+ 2;
1303 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1311 This function is to parse and check vendor options.
1313 @param Dhcp4Option Pointer to dhcp options
1314 @param VendorOption Pointer to vendor options
1316 @return TRUE if valid for vendor options, or FALSE.
1320 PxeBcParseVendorOptions (
1321 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1322 IN PXEBC_VENDOR_OPTION
*VendorOption
1326 UINT8 VendorOptionLen
;
1327 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1330 BitMap
= VendorOption
->BitMap
;
1331 VendorOptionLen
= Dhcp4Option
->Length
;
1332 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1335 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1337 // Parse every Vendor Option and set its BitMap
1339 switch (PxeOption
->OpCode
) {
1341 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1343 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1346 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1348 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1351 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1353 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1356 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1358 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1361 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1363 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1366 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1368 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1371 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1373 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1376 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1378 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1379 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1382 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1384 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1385 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1388 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1390 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1391 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1394 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1396 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1397 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1398 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1401 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1403 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1404 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1407 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1409 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1410 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1414 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1416 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1419 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1422 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1426 // FixMe, return falas if invalid of any vendor option
1434 This function display boot item detail.
1436 If the length of the boot item string over 70 Char, just display 70 Char.
1438 @param Str Pointer to a string (boot item string).
1439 @param Len The length of string.
1445 PxeBcDisplayBootItem (
1452 Len
= (UINT8
) MIN (70, Len
);
1455 AsciiPrint ("%a \n", Str
);
1461 Choose the boot prompt.
1463 @param Private Pointer to PxeBc private data.
1465 @retval EFI_SUCCESS Select boot prompt done.
1466 @retval EFI_TIMEOUT Select boot prompt time out.
1467 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
1468 @retval EFI_ABORTED User cancel the operation.
1469 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1473 PxeBcSelectBootPrompt (
1474 IN PXEBC_PRIVATE_DATA
*Private
1477 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1478 PXEBC_VENDOR_OPTION
*VendorOpt
;
1479 EFI_EVENT TimeoutEvent
;
1480 EFI_EVENT DescendEvent
;
1481 EFI_INPUT_KEY InputKey
;
1489 TimeoutEvent
= NULL
;
1490 DescendEvent
= NULL
;
1492 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1494 Packet
= &Private
->ProxyOffer
;
1497 Packet
= &Private
->Dhcp4Ack
;
1500 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1501 return EFI_NOT_FOUND
;
1504 VendorOpt
= &Packet
->PxeVendorOption
;
1506 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1510 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1511 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1512 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1518 if (Timeout
== 255) {
1522 Status
= gBS
->CreateEvent (
1530 if (EFI_ERROR (Status
)) {
1534 Status
= gBS
->SetTimer (
1537 Timeout
* TICKS_PER_SECOND
1540 if (EFI_ERROR (Status
)) {
1544 Status
= gBS
->CreateEvent (
1552 if (EFI_ERROR (Status
)) {
1556 Status
= gBS
->SetTimer (
1562 if (EFI_ERROR (Status
)) {
1566 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1567 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1569 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1571 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1572 AsciiPrint ("(%d) ", Timeout
--);
1574 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1576 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1577 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1578 AsciiPrint ("(%d) ", Timeout
--);
1581 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1583 gBS
->Stall (10 * TICKS_PER_MS
);
1587 if (InputKey
.ScanCode
== 0) {
1589 switch (InputKey
.UnicodeChar
) {
1591 Status
= EFI_ABORTED
;
1597 Status
= EFI_TIMEOUT
;
1605 switch (InputKey
.ScanCode
) {
1607 Status
= EFI_TIMEOUT
;
1611 Status
= EFI_ABORTED
;
1622 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1626 if (DescendEvent
!= NULL
) {
1627 gBS
->CloseEvent (DescendEvent
);
1630 if (TimeoutEvent
!= NULL
) {
1631 gBS
->CloseEvent (TimeoutEvent
);
1639 Select the boot menu.
1641 @param Private Pointer to PxeBc private data.
1642 @param Type The type of the menu.
1643 @param UseDefaultItem Use default item or not.
1645 @retval EFI_ABORTED User cancel operation.
1646 @retval EFI_SUCCESS Select the boot menu success.
1647 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1651 PxeBcSelectBootMenu (
1652 IN PXEBC_PRIVATE_DATA
*Private
,
1654 IN BOOLEAN UseDefaultItem
1657 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1658 PXEBC_VENDOR_OPTION
*VendorOpt
;
1659 EFI_INPUT_KEY InputKey
;
1668 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1669 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1676 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1678 Packet
= &Private
->ProxyOffer
;
1681 Packet
= &Private
->Dhcp4Ack
;
1684 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1686 VendorOpt
= &Packet
->PxeVendorOption
;
1688 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1692 SetMem (Blank
, sizeof(Blank
), ' ');
1694 MenuSize
= VendorOpt
->BootMenuLen
;
1695 MenuItem
= VendorOpt
->BootMenu
;
1697 while (MenuSize
> 0) {
1698 MenuArray
[Index
] = MenuItem
;
1699 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1700 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1704 if (UseDefaultItem
) {
1705 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
1706 *Type
= NTOHS (*Type
);
1712 for (Index
= 0; Index
< MenuNum
; Index
++) {
1713 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1716 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1720 // highlight selected row
1722 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1723 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1724 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1725 AsciiPrint ("%a\r", Blank
);
1726 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1727 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1728 LastSelect
= Select
;
1730 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1731 gBS
->Stall (10 * TICKS_PER_MS
);
1734 if (!InputKey
.ScanCode
) {
1735 switch (InputKey
.UnicodeChar
) {
1737 InputKey
.ScanCode
= SCAN_ESC
;
1740 case CTRL ('j'): /* linefeed */
1741 case CTRL ('m'): /* return */
1745 case CTRL ('i'): /* tab */
1749 InputKey
.ScanCode
= SCAN_DOWN
;
1752 case CTRL ('h'): /* backspace */
1755 InputKey
.ScanCode
= SCAN_UP
;
1759 InputKey
.ScanCode
= 0;
1763 switch (InputKey
.ScanCode
) {
1774 if (++Select
== MenuNum
) {
1785 case SCAN_PAGE_DOWN
:
1787 Select
= (UINT16
) (MenuNum
- 1);
1794 /* unhighlight last selected row */
1795 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1796 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1797 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1798 AsciiPrint ("%a\r", Blank
);
1799 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1800 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1804 // Swap the byte order
1806 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1807 *Type
= NTOHS (*Type
);