2 Support for PxeBc dhcp functions.
4 Copyright (c) 2007 - 2009, 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
;
282 // use option 54, if zero, use siaddr in header
284 ZeroMem (&ServerIp
, sizeof(EFI_IP_ADDRESS
));
285 if (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
] != NULL
) {
288 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
289 sizeof (EFI_IPv4_ADDRESS
)
294 &Offer
->Dhcp4
.Header
.ServerAddr
,
295 sizeof (EFI_IPv4_ADDRESS
)
298 if (ServerIp
.Addr
[0] == 0) {
302 CachedPacket
= &Private
->ProxyOffer
;
303 Reply
= &CachedPacket
->Packet
.Offer
;
305 Status
= PxeBcDiscvBootService (
316 if (EFI_ERROR (Status
)) {
320 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
324 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
325 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
327 // This BINL ack doesn't have discovery options set or bootfile name
333 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
334 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
341 Offer dhcp service for each proxy with a BINL dhcp offer.
343 @param Private Pointer to PxeBc private data
344 @param OfferIndex Pointer to the index of cached packets as complements of
345 pxe mode data, the index is maximum offer number.
347 @return If there is no service needed offer return FALSE, otherwise TRUE.
352 IN PXEBC_PRIVATE_DATA
*Private
,
353 OUT UINT32
*OfferIndex
358 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
360 *OfferIndex
= Private
->BinlIndex
[Index
];
362 // Try this BINL proxy offer
364 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
374 This function is to check the selected proxy offer (include BINL dhcp offer and
375 DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code
378 @param Private Pointer to PxeBc private data.
380 @retval EFI_SUCCESS Operational successful.
381 @retval EFI_NO_RESPONSE Offer dhcp service failed.
385 PxeBcCheckSelectedOffer (
386 IN PXEBC_PRIVATE_DATA
*Private
389 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
390 EFI_DHCP4_PACKET_OPTION
**Options
;
392 EFI_DHCP4_PACKET
*Offer
;
393 UINT32 ProxyOfferIndex
;
395 EFI_PXE_BASE_CODE_MODE
*Mode
;
396 EFI_DHCP4_PACKET
*Ack
;
398 ASSERT (Private
->SelectedOffer
!= 0);
400 Status
= EFI_SUCCESS
;
401 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
402 Options
= SelectedOffer
->Dhcp4Option
;
404 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
406 // The addresses are acquired from a BINL dhcp offer, try BINL to get
409 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
410 Status
= EFI_NO_RESPONSE
;
412 } else if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) {
414 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
415 // try proxy offers if there are some, othewise the bootfile name must be
416 // set in this DHCP only offer.
418 if (Private
->GotProxyOffer
) {
420 // Get rid of the compiler warning.
423 if (Private
->SortOffers
) {
425 // The offers are sorted before selecting, the proxy offer type must be
426 // already determined.
428 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
430 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
432 // We buffer all received BINL proxy offers, try them all one by one
434 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
435 Status
= EFI_NO_RESPONSE
;
439 // For other types, only one proxy offer is buffered.
441 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
445 // The proxy offer type is not determined, choose proxy offer in the
448 Status
= EFI_NO_RESPONSE
;
450 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
452 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
453 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
455 // Skip non proxy dhcp offers.
460 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
464 if (!PxeBcTryBinl (Private
, Index
)) {
466 // Failed, skip to the next offer
472 Private
->ProxyOfferType
= Private
->Dhcp4Offers
[Index
].OfferType
;
473 ProxyOfferIndex
= Index
;
474 Status
= EFI_SUCCESS
;
479 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
481 // Copy the proxy offer to Mode and set the flag
483 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
487 // No proxy offer is received, the bootfile name MUST be set.
489 ASSERT (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
493 if (!EFI_ERROR (Status
)) {
495 // Everything is OK, set the flag and copy the DHCP packets.
497 Mode
= Private
->PxeBc
.Mode
;
498 Offer
= &SelectedOffer
->Packet
.Offer
;
501 // The discover packet is already copied, just set flag here.
503 Mode
->DhcpDiscoverValid
= TRUE
;
505 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
506 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
508 // Other type of ACK is already cached. Bootp is special that we should
509 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
511 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
514 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
516 Mode
->DhcpAckReceived
= TRUE
;
519 // Copy the dhcp ack.
521 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
529 Cache the Dhcp4 packet offer, Parse and validate each option of the packet.
531 @param Private Pointer to PxeBc private data.
532 @param RcvdOffer Pointer to the received Dhcp proxy offer packet.
538 PxeBcCacheDhcpOffer (
539 IN PXEBC_PRIVATE_DATA
*Private
,
540 IN EFI_DHCP4_PACKET
*RcvdOffer
543 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
544 EFI_DHCP4_PACKET
*Offer
;
547 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
548 Offer
= &CachedOffer
->Packet
.Offer
;
551 // Cache the orignal dhcp packet
553 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
556 // Parse and validate the options (including dhcp option and vendor option)
558 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
562 OfferType
= CachedOffer
->OfferType
;
564 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
566 if (Private
->BootpIndex
!= 0) {
568 // Only cache the first bootp offer, discard others.
573 // Take as a dhcp only offer, but record index specifically.
575 Private
->BootpIndex
= Private
->NumOffers
+ 1;
579 if (IS_PROXY_DHCP_OFFER (Offer
)) {
581 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
583 Private
->GotProxyOffer
= TRUE
;
585 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
587 // Cache all binl offers.
589 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
590 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
591 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
593 // Only cache the first pxe10/wfm11a offers each, discard the others.
598 // Record index of the proxy dhcp offer with type other than binl.
600 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
604 // It's a dhcp offer with your address.
606 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
607 Private
->ServerCount
[OfferType
]++;
612 // Count the accepted offers.
614 Private
->NumOffers
++;
619 Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.
620 If the proxy does not exist, try offers with bootfile.
622 @param Private Pointer to PxeBc private data.
629 IN PXEBC_PRIVATE_DATA
*Private
634 EFI_DHCP4_PACKET
*Offer
;
636 Private
->SelectedOffer
= 0;
638 if (Private
->SortOffers
) {
640 // Select offer according to the priority
642 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
646 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
648 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
652 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
654 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
655 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
658 // DHCP only and proxy DHCP with PXE10
660 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
661 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
663 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
664 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
667 // DHCP only and proxy DHCP with WfM
669 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
670 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
672 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
676 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
678 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
679 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
682 // DHCP only and proxy DHCP with BINL
684 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
685 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
689 // Try offers with bootfile
691 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
693 // Select the first DHCP only offer with bootfile
695 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
696 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
697 Private
->SelectedOffer
= OfferIndex
+ 1;
702 if (Private
->SelectedOffer
== 0) {
704 // Select the Bootp reply with bootfile if any
706 Private
->SelectedOffer
= Private
->BootpIndex
;
711 // Try the offers in the received order.
713 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
715 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
717 if (IS_PROXY_DHCP_OFFER (Offer
)) {
724 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
725 ((!Private
->GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
727 // DHCP only offer but no proxy offer received and no bootfile option in this offer
732 Private
->SelectedOffer
= Index
+ 1;
742 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
743 to intercept events that occurred in the configuration process. This structure
744 provides advanced control of each state transition of the DHCP process. The
745 returned status code determines the behavior of the EFI DHCPv4 Protocol driver.
746 There are three possible returned values, which are described in the following
749 @param This Pointer to the EFI DHCPv4 Protocol instance that is used to
750 configure this callback function.
751 @param Context Pointer to the context that is initialized by
752 EFI_DHCP4_PROTOCOL.Configure().
753 @param CurrentState The current operational state of the EFI DHCPv4 Protocol
755 @param Dhcp4Event The event that occurs in the current state, which usually means a
757 @param Packet The DHCP packet that is going to be sent or already received.
758 @param NewPacket The packet that is used to replace the above Packet.
760 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
761 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
762 driver will continue to wait for more DHCPOFFER packets until the retry
764 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and
765 return to the Dhcp4Init or Dhcp4InitReboot state.
771 IN EFI_DHCP4_PROTOCOL
* This
,
773 IN EFI_DHCP4_STATE CurrentState
,
774 IN EFI_DHCP4_EVENT Dhcp4Event
,
775 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
776 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
779 PXEBC_PRIVATE_DATA
*Private
;
780 EFI_PXE_BASE_CODE_MODE
*Mode
;
781 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
782 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
786 CHAR8
*SystemSerialNumber
;
787 EFI_DHCP4_HEADER
*DhcpHeader
;
789 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
790 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
791 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
792 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
793 (Dhcp4Event
!= Dhcp4SendRequest
)) {
797 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
798 Mode
= Private
->PxeBc
.Mode
;
799 Callback
= Private
->PxeBcCallback
;
802 // Override the Maximum DHCP Message Size.
804 MaxMsgSize
= PxeBcParseExtendOptions (
805 Packet
->Dhcp4
.Option
,
806 GET_OPTION_BUFFER_LEN (Packet
),
807 PXEBC_DHCP4_TAG_MAXMSG
809 if (MaxMsgSize
!= NULL
) {
810 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
811 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
814 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
815 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
816 Status
= Callback
->Callback (
821 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
823 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
828 Status
= EFI_SUCCESS
;
830 switch (Dhcp4Event
) {
832 case Dhcp4SendDiscover
:
833 case Dhcp4SendRequest
:
834 if (Mode
->SendGUID
) {
836 // send the system GUID instead of the MAC address as the hardware address
837 // in the DHCP packet header.
839 DhcpHeader
= &Packet
->Dhcp4
.Header
;
841 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
843 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
844 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
845 // GUID not yet set - send all 0's to show not programable
847 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
850 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
853 if (Dhcp4Event
== Dhcp4SendDiscover
) {
855 // Cache the dhcp discover packet, of which some information will be used later.
857 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
863 Status
= EFI_NOT_READY
;
864 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
866 // Cache the dhcp offers in Private->Dhcp4Offers[]
868 PxeBcCacheDhcpOffer (Private
, Packet
);
873 case Dhcp4SelectOffer
:
875 // Select an offer, if succeeded, Private->SelectedOffer points to
876 // the index of the selected one.
878 PxeBcSelectOffer (Private
);
880 if (Private
->SelectedOffer
== 0) {
881 Status
= EFI_ABORTED
;
883 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
892 ASSERT (Private
->SelectedOffer
!= 0);
894 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
906 Initialize the DHCP options and build the option list.
908 @param Private Pointer to PxeBc private data.
909 @param OptList Pointer to a DHCP option list.
911 @param IsDhcpDiscover Discover dhcp option or not.
913 @return The index item number of the option list.
917 PxeBcBuildDhcpOptions (
918 IN PXEBC_PRIVATE_DATA
*Private
,
919 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
920 IN BOOLEAN IsDhcpDiscover
924 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
926 CHAR8
*SystemSerialNumber
;
929 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
931 if (!IsDhcpDiscover
) {
933 // Append message type.
935 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
936 OptList
[Index
]->Length
= 1;
937 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
938 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
940 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
943 // Append max message size.
945 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
946 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
947 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
948 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
949 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
951 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
954 // Parameter request list option.
956 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
957 OptList
[Index
]->Length
= 35;
958 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
959 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
960 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
961 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
962 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
963 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
964 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
965 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
966 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
967 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
968 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
969 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
970 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
971 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
972 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
973 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
974 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
975 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
976 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
977 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
978 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
979 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
980 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
981 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
982 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
983 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
984 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
985 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
986 OptEnt
.Para
->ParaList
[27] = 0x80;
987 OptEnt
.Para
->ParaList
[28] = 0x81;
988 OptEnt
.Para
->ParaList
[29] = 0x82;
989 OptEnt
.Para
->ParaList
[30] = 0x83;
990 OptEnt
.Para
->ParaList
[31] = 0x84;
991 OptEnt
.Para
->ParaList
[32] = 0x85;
992 OptEnt
.Para
->ParaList
[33] = 0x86;
993 OptEnt
.Para
->ParaList
[34] = 0x87;
995 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
998 // Append UUID/Guid-based client identifier option
1000 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
1001 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
1002 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
1003 OptEnt
.Uuid
->Type
= 0;
1005 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1007 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
1009 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
1010 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
1011 // GUID not yet set - send all 0's to show not programable
1013 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
1017 // Append client network device interface option
1019 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
1020 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
1021 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
1022 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
1023 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
1024 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
1027 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1030 // Append client system architecture option
1032 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
1033 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1034 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1035 Value
= HTONS (SYS_ARCH
);
1036 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1038 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1041 // Append client system architecture option
1043 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
1044 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
1045 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1046 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1047 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1048 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1049 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1050 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1058 Discover the boot of service and initialize the vendor option if exists.
1060 @param Private Pointer to PxeBc private data.
1061 @param Type PxeBc option boot item type
1062 @param Layer PxeBc option boot item layer
1063 @param UseBis Use BIS or not
1064 @param DestIp Ip address for server
1065 @param IpCount The total count of the server ip address
1066 @param SrvList Server list
1067 @param IsDiscv Discover the vendor or not
1068 @param Reply The dhcp4 packet of Pxe reply
1070 @retval EFI_SUCCESS Operation succeeds.
1071 @retval EFI_OUT_OF_RESOURCES Allocate memory pool failed.
1072 @retval EFI_NOT_FOUND There is no vendor option exists.
1073 @retval EFI_TIMEOUT Send Pxe Discover time out.
1077 PxeBcDiscvBootService (
1078 IN PXEBC_PRIVATE_DATA
* Private
,
1082 IN EFI_IP_ADDRESS
* DestIp
,
1084 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1086 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1089 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1090 EFI_PXE_BASE_CODE_MODE
*Mode
;
1091 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1092 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1098 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1099 EFI_DHCP4_PACKET
*Response
;
1100 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1102 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1103 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1105 CHAR8
*SystemSerialNumber
;
1106 EFI_DHCP4_HEADER
*DhcpHeader
;
1109 Mode
= Private
->PxeBc
.Mode
;
1110 Dhcp4
= Private
->Dhcp4
;
1111 Status
= EFI_SUCCESS
;
1113 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1115 if (DestIp
== NULL
) {
1116 Sport
= PXEBC_DHCP4_S_PORT
;
1119 Sport
= PXEBC_BS_DISCOVER_PORT
;
1123 if (!UseBis
&& Layer
!= NULL
) {
1124 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1127 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1131 // Add vendor option of PXE_BOOT_ITEM
1133 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1134 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1135 if (OptList
[OptCount
] == NULL
) {
1136 return EFI_OUT_OF_RESOURCES
;
1139 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1140 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1141 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1142 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1143 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1144 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1145 PxeBootItem
->Type
= HTONS (Type
);
1146 PxeBootItem
->Layer
= HTONS (*Layer
);
1147 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1152 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1155 gBS
->FreePool (OptList
[OptCount
- 1]);
1158 if (EFI_ERROR (Status
)) {
1162 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1163 if (Mode
->SendGUID
) {
1164 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
1166 // GUID not yet set - send all 0's to show not programable
1168 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1171 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
1174 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1175 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1176 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1178 Token
.RemotePort
= Sport
;
1180 if (DestIp
== NULL
) {
1181 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1183 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1186 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1189 Token
.ListenPointCount
= 1;
1190 Token
.ListenPoints
= &ListenPoint
;
1191 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1192 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1193 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1196 // Send Pxe Discover
1198 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1200 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1202 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1204 if (Token
.Status
!= EFI_TIMEOUT
) {
1209 if (!EFI_ERROR (Status
)) {
1215 Response
= Token
.ResponseList
;
1217 while (RepIndex
< Token
.ResponseCount
) {
1219 while (SrvIndex
< IpCount
) {
1221 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1225 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1232 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1239 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1242 if (RepIndex
< Token
.ResponseCount
) {
1244 if (Reply
!= NULL
) {
1245 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1249 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1250 Mode
->PxeDiscoverValid
= TRUE
;
1252 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1253 Mode
->PxeReplyReceived
= TRUE
;
1256 Status
= EFI_NOT_FOUND
;
1260 // free the responselist
1262 gBS
->FreePool (Token
.ResponseList
);
1265 // Free the dhcp packet
1267 gBS
->FreePool (Token
.Packet
);
1274 Parse interested dhcp options.
1276 @param Buffer Pointer to the dhcp options packet.
1277 @param Length The length of the dhcp options.
1278 @param OptTag The option OpCode.
1280 @return NULL if the buffer length is 0 and OpCode is not
1281 PXEBC_DHCP4_TAG_EOP, or the pointer to the buffer.
1284 EFI_DHCP4_PACKET_OPTION
*
1285 PxeBcParseExtendOptions (
1291 EFI_DHCP4_PACKET_OPTION
*Option
;
1294 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1297 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1299 if (Option
->OpCode
== OptTag
) {
1304 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1307 Offset
+= Option
->Length
+ 2;
1310 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1318 This function is to parse and check vendor options.
1320 @param Dhcp4Option Pointer to dhcp options
1321 @param VendorOption Pointer to vendor options
1323 @return TRUE if valid for vendor options, or FALSE.
1327 PxeBcParseVendorOptions (
1328 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1329 IN PXEBC_VENDOR_OPTION
*VendorOption
1333 UINT8 VendorOptionLen
;
1334 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1337 BitMap
= VendorOption
->BitMap
;
1338 VendorOptionLen
= Dhcp4Option
->Length
;
1339 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1342 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1344 // Parse every Vendor Option and set its BitMap
1346 switch (PxeOption
->OpCode
) {
1348 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1350 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1353 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1355 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1358 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1360 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1363 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1365 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1368 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1370 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1373 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1375 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1378 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1380 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1383 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1385 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1386 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1389 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1391 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1392 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1395 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1397 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1398 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1401 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1403 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1404 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1405 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1408 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1410 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1411 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1414 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1416 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1417 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1421 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1423 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1426 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1429 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1433 // FixMe, return falas if invalid of any vendor option
1441 This function display boot item detail.
1443 If the length of the boot item string over 70 Char, just display 70 Char.
1445 @param Str Pointer to a string (boot item string).
1446 @param Len The length of string.
1452 PxeBcDisplayBootItem (
1459 Len
= (UINT8
) MIN (70, Len
);
1462 AsciiPrint ("%a \n", Str
);
1468 Choose the boot prompt.
1470 @param Private Pointer to PxeBc private data.
1472 @retval EFI_SUCCESS Select boot prompt done.
1473 @retval EFI_TIMEOUT Select boot prompt time out.
1474 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
1475 @retval EFI_ABORTED User cancel the operation.
1476 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1480 PxeBcSelectBootPrompt (
1481 IN PXEBC_PRIVATE_DATA
*Private
1484 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1485 PXEBC_VENDOR_OPTION
*VendorOpt
;
1486 EFI_EVENT TimeoutEvent
;
1487 EFI_EVENT DescendEvent
;
1488 EFI_INPUT_KEY InputKey
;
1496 TimeoutEvent
= NULL
;
1497 DescendEvent
= NULL
;
1499 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1501 Packet
= &Private
->ProxyOffer
;
1504 Packet
= &Private
->Dhcp4Ack
;
1507 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1508 return EFI_NOT_FOUND
;
1511 VendorOpt
= &Packet
->PxeVendorOption
;
1513 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1517 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1518 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1519 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1525 if (Timeout
== 255) {
1529 Status
= gBS
->CreateEvent (
1537 if (EFI_ERROR (Status
)) {
1541 Status
= gBS
->SetTimer (
1544 Timeout
* TICKS_PER_SECOND
1547 if (EFI_ERROR (Status
)) {
1551 Status
= gBS
->CreateEvent (
1559 if (EFI_ERROR (Status
)) {
1563 Status
= gBS
->SetTimer (
1569 if (EFI_ERROR (Status
)) {
1573 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1574 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1576 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1578 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1579 AsciiPrint ("(%d) ", Timeout
--);
1581 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1583 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1584 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1585 AsciiPrint ("(%d) ", Timeout
--);
1588 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1590 gBS
->Stall (10 * TICKS_PER_MS
);
1594 if (InputKey
.ScanCode
== 0) {
1596 switch (InputKey
.UnicodeChar
) {
1598 Status
= EFI_ABORTED
;
1604 Status
= EFI_TIMEOUT
;
1612 switch (InputKey
.ScanCode
) {
1614 Status
= EFI_TIMEOUT
;
1618 Status
= EFI_ABORTED
;
1629 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1633 if (DescendEvent
!= NULL
) {
1634 gBS
->CloseEvent (DescendEvent
);
1637 if (TimeoutEvent
!= NULL
) {
1638 gBS
->CloseEvent (TimeoutEvent
);
1646 Select the boot menu.
1648 @param Private Pointer to PxeBc private data.
1649 @param Type The type of the menu.
1650 @param UseDefaultItem Use default item or not.
1652 @retval EFI_ABORTED User cancel operation.
1653 @retval EFI_SUCCESS Select the boot menu success.
1654 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
1658 PxeBcSelectBootMenu (
1659 IN PXEBC_PRIVATE_DATA
*Private
,
1661 IN BOOLEAN UseDefaultItem
1664 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1665 PXEBC_VENDOR_OPTION
*VendorOpt
;
1666 EFI_INPUT_KEY InputKey
;
1675 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1676 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1683 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1685 Packet
= &Private
->ProxyOffer
;
1688 Packet
= &Private
->Dhcp4Ack
;
1691 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1693 VendorOpt
= &Packet
->PxeVendorOption
;
1695 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1699 SetMem (Blank
, sizeof(Blank
), ' ');
1701 MenuSize
= VendorOpt
->BootMenuLen
;
1702 MenuItem
= VendorOpt
->BootMenu
;
1704 while (MenuSize
> 0) {
1705 MenuArray
[Index
] = MenuItem
;
1706 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1707 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1711 if (UseDefaultItem
) {
1712 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
1713 *Type
= NTOHS (*Type
);
1719 for (Index
= 0; Index
< MenuNum
; Index
++) {
1720 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1723 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1727 // highlight selected row
1729 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1730 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1731 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1732 AsciiPrint ("%a\r", Blank
);
1733 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1734 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1735 LastSelect
= Select
;
1737 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1738 gBS
->Stall (10 * TICKS_PER_MS
);
1741 if (!InputKey
.ScanCode
) {
1742 switch (InputKey
.UnicodeChar
) {
1744 InputKey
.ScanCode
= SCAN_ESC
;
1747 case CTRL ('j'): /* linefeed */
1748 case CTRL ('m'): /* return */
1752 case CTRL ('i'): /* tab */
1756 InputKey
.ScanCode
= SCAN_DOWN
;
1759 case CTRL ('h'): /* backspace */
1762 InputKey
.ScanCode
= SCAN_UP
;
1766 InputKey
.ScanCode
= 0;
1770 switch (InputKey
.ScanCode
) {
1781 if (++Select
== MenuNum
) {
1792 case SCAN_PAGE_DOWN
:
1794 Select
= (UINT16
) (MenuNum
- 1);
1801 /* unhighlight last selected row */
1802 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1803 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1804 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1805 AsciiPrint ("%a\r", Blank
);
1806 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1807 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1811 // Swap the byte order
1813 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1814 *Type
= NTOHS (*Type
);