3 Copyright (c) 2007 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Support for PxeBc dhcp functions
24 #include "PxeBcImpl.h"
27 // This is a map from the interested DHCP4 option tags' index to the tag value.
29 UINT8 mInterestedDhcp4Tags
[PXEBC_DHCP4_TAG_INDEX_MAX
] = {
30 PXEBC_DHCP4_TAG_BOOTFILE_LEN
,
31 PXEBC_DHCP4_TAG_VENDOR
,
32 PXEBC_DHCP4_TAG_OVERLOAD
,
33 PXEBC_DHCP4_TAG_MSG_TYPE
,
34 PXEBC_DHCP4_TAG_SERVER_ID
,
35 PXEBC_DHCP4_TAG_CLASS_ID
,
36 PXEBC_DHCP4_TAG_BOOTFILE
41 GC_NOTO: Add function description
43 @param Seed GC_NOTO: add argument description
44 @param Udp4 GC_NOTO: add argument description
46 @return GC_NOTO: add return values
51 IN EFI_DHCP4_PACKET
*Seed
,
52 IN EFI_UDP4_PROTOCOL
*Udp4
55 EFI_SIMPLE_NETWORK_MODE Mode
;
56 EFI_DHCP4_HEADER
*Header
;
58 Udp4
->GetModeData (Udp4
, NULL
, NULL
, NULL
, &Mode
);
60 Seed
->Size
= sizeof (EFI_DHCP4_PACKET
);
61 Seed
->Length
= sizeof (Seed
->Dhcp4
);
63 Header
= &Seed
->Dhcp4
.Header
;
65 ZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
66 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
67 Header
->HwType
= Mode
.IfType
;
68 Header
->HwAddrLen
= (UINT8
) Mode
.HwAddressSize
;
69 CopyMem (Header
->ClientHwAddr
, &Mode
.CurrentAddress
, Header
->HwAddrLen
);
71 Seed
->Dhcp4
.Magik
= PXEBC_DHCP4_MAGIC
;
72 Seed
->Dhcp4
.Option
[0] = PXEBC_DHCP4_TAG_EOP
;
77 GC_NOTO: Add function description
79 @param Dst GC_NOTO: add argument description
80 @param Src GC_NOTO: add argument description
82 @return GC_NOTO: add return values
86 PxeBcCopyEfiDhcp4Packet (
87 IN EFI_DHCP4_PACKET
*Dst
,
88 IN EFI_DHCP4_PACKET
*Src
91 ASSERT (Dst
->Size
>= Src
->Length
);
93 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
94 Dst
->Length
= Src
->Length
;
99 GC_NOTO: Add function description
101 @param Private GC_NOTO: add argument description
102 @param OfferIndex GC_NOTO: add argument description
104 @return GC_NOTO: add return values
108 PxeBcCopyProxyOffer (
109 IN PXEBC_PRIVATE_DATA
*Private
,
113 EFI_PXE_BASE_CODE_MODE
*Mode
;
114 EFI_DHCP4_PACKET
*Offer
;
116 ASSERT (OfferIndex
< Private
->NumOffers
);
118 Mode
= Private
->PxeBc
.Mode
;
119 Offer
= &Private
->Dhcp4Offers
[OfferIndex
].Packet
.Offer
;
121 PxeBcCopyEfiDhcp4Packet (&Private
->ProxyOffer
.Packet
.Offer
, Offer
);
122 CopyMem (&Mode
->ProxyOffer
, &Offer
->Dhcp4
, Offer
->Length
);
123 Mode
->ProxyOfferReceived
= TRUE
;
125 PxeBcParseCachedDhcpPacket (&Private
->ProxyOffer
);
130 Parse the cached dhcp packet.
132 @param CachedPacket Pointer to cached dhcp packet
134 @return TRUE : Success to parse and validation
135 @return FALSE : Fail to parse or validation
139 PxeBcParseCachedDhcpPacket (
140 IN PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
143 EFI_DHCP4_PACKET
*Offer
;
144 EFI_DHCP4_PACKET_OPTION
**Options
;
145 EFI_DHCP4_PACKET_OPTION
*Option
;
149 CachedPacket
->IsPxeOffer
= FALSE
;
150 ZeroMem (CachedPacket
->Dhcp4Option
, sizeof (CachedPacket
->Dhcp4Option
));
151 ZeroMem (&CachedPacket
->PxeVendorOption
, sizeof (CachedPacket
->PxeVendorOption
));
153 Offer
= &CachedPacket
->Packet
.Offer
;
154 Options
= CachedPacket
->Dhcp4Option
;
157 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.
159 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
160 Options
[Index
] = PxeBcParseExtendOptions (
162 GET_OPTION_BUFFER_LEN (Offer
),
163 mInterestedDhcp4Tags
[Index
]
168 // Check whether is an offer with PXEClient or not.
170 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
171 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
172 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
174 CachedPacket
->IsPxeOffer
= TRUE
;
178 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
180 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
181 if (CachedPacket
->IsPxeOffer
&& (Option
!= NULL
)) {
183 if (!PxeBcParseVendorOptions (Option
, &CachedPacket
->PxeVendorOption
)) {
189 // Check whether bootfilename/serverhostname overloaded (See details in dhcp spec).
190 // If overloaded, parse this buffer as nested dhcp options, or just parse bootfilename/
191 // serverhostname option.
193 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
194 if ((Option
!= NULL
) && (Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
)) {
196 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = PxeBcParseExtendOptions (
197 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
198 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
199 PXEBC_DHCP4_TAG_BOOTFILE
202 } else if ((Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) &&
203 (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
205 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
206 // And do not count dhcp option header, or else will destory the serverhostname.
208 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*) (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
209 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
214 // Determine offer type of the dhcp packet.
216 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
217 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
219 // It's a bootp offer
221 Option
= CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
222 if (Option
== NULL
) {
224 // bootp offer without bootfilename, discard it.
229 OfferType
= DHCP4_PACKET_TYPE_BOOTP
;
233 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
235 // It's a pxe10 offer with PXEClient and discover vendor option.
237 OfferType
= DHCP4_PACKET_TYPE_PXE10
;
238 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket
->PxeVendorOption
.BitMap
)) {
240 // It's a wfm11a offer with PXEClient and mtftp vendor option, and
241 // return false since mtftp not supported currently.
246 // If the binl offer with only PXEClient.
248 OfferType
= (UINT8
) ((CachedPacket
->IsPxeOffer
) ? DHCP4_PACKET_TYPE_BINL
: DHCP4_PACKET_TYPE_DHCP_ONLY
);
252 CachedPacket
->OfferType
= OfferType
;
259 GC_NOTO: Add function description
261 @param Private GC_NOTO: add argument description
262 @param Index GC_NOTO: add argument description
264 @return GC_NOTO: add return values
269 IN PXEBC_PRIVATE_DATA
*Private
,
273 EFI_DHCP4_PACKET
*Offer
;
274 EFI_IP_ADDRESS ServerIp
;
276 PXEBC_CACHED_DHCP4_PACKET
*CachedPacket
;
277 EFI_DHCP4_PACKET
*Reply
;
279 ASSERT (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
);
281 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
282 if (Offer
->Dhcp4
.Header
.ServerAddr
.Addr
[0] == 0) {
284 // next server ip address is zero, use server id option instead.
288 Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
289 sizeof (EFI_IPv4_ADDRESS
)
293 // use next server ip address.
295 CopyMem (&ServerIp
.Addr
[0], &Offer
->Dhcp4
.Header
.ServerAddr
, sizeof (EFI_IPv4_ADDRESS
));
298 CachedPacket
= &Private
->ProxyOffer
;
299 Reply
= &CachedPacket
->Packet
.Offer
;
301 Status
= PxeBcDiscvBootService (
312 if (EFI_ERROR (Status
)) {
316 if (!PxeBcParseCachedDhcpPacket (CachedPacket
)) {
320 if ((CachedPacket
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) &&
321 (CachedPacket
->Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
323 // This BINL ack doesn't have discovery options set or bootfile name
329 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
330 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
, &Reply
->Dhcp4
, Reply
->Length
);
337 GC_NOTO: Add function description
339 @param Private GC_NOTO: add argument description
340 @param OfferIndex GC_NOTO: add argument description
342 @return GC_NOTO: add return values
347 IN PXEBC_PRIVATE_DATA
*Private
,
348 OUT UINT32
*OfferIndex
353 for (Index
= 0; Index
< Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]; Index
++) {
355 *OfferIndex
= Private
->BinlIndex
[Index
];
357 // Try this BINL proxy offer
359 if (PxeBcTryBinl (Private
, *OfferIndex
)) {
369 GC_NOTO: Add function description
371 @param Private GC_NOTO: add argument description
373 @return GC_NOTO: add return values
377 PxeBcCheckSelectedOffer (
378 IN PXEBC_PRIVATE_DATA
*Private
381 PXEBC_CACHED_DHCP4_PACKET
*SelectedOffer
;
382 EFI_DHCP4_PACKET_OPTION
**Options
;
384 EFI_DHCP4_PACKET
*Offer
;
385 UINT32 ProxyOfferIndex
;
387 EFI_PXE_BASE_CODE_MODE
*Mode
;
388 EFI_DHCP4_PACKET
*Ack
;
390 ASSERT (Private
->SelectedOffer
!= 0);
392 Status
= EFI_SUCCESS
;
393 SelectedOffer
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1];
394 Options
= SelectedOffer
->Dhcp4Option
;
396 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BINL
) {
398 // The addresses are acquired from a BINL dhcp offer, try BINL to get
401 if (!PxeBcTryBinl (Private
, Private
->SelectedOffer
- 1)) {
402 Status
= EFI_NO_RESPONSE
;
404 } else if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) {
406 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
407 // try proxy offers if there are some, othewise the bootfile name must be
408 // set in this DHCP only offer.
410 if (Private
->GotProxyOffer
) {
412 // Get rid of the compiler warning.
415 if (Private
->SortOffers
) {
417 // The offers are sorted before selecting, the proxy offer type must be
418 // already determined.
420 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
422 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
424 // We buffer all received BINL proxy offers, try them all one by one
426 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
427 Status
= EFI_NO_RESPONSE
;
431 // For other types, only one proxy offer is buffered.
433 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
437 // The proxy offer type is not determined, choose proxy offer in the
440 Status
= EFI_NO_RESPONSE
;
442 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
444 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
445 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
447 // Skip non proxy dhcp offers.
452 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
456 if (!PxeBcTryBinl (Private
, Index
)) {
458 // Failed, skip to the next offer
464 Private
->ProxyOfferType
= Private
->Dhcp4Offers
[Index
].OfferType
;
465 ProxyOfferIndex
= Index
;
466 Status
= EFI_SUCCESS
;
471 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
473 // Copy the proxy offer to Mode and set the flag
475 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
479 // No proxy offer is received, the bootfile name MUST be set.
481 ASSERT (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
485 if (!EFI_ERROR (Status
)) {
487 // Everything is OK, set the flag and copy the DHCP packets.
489 Mode
= Private
->PxeBc
.Mode
;
490 Offer
= &SelectedOffer
->Packet
.Offer
;
493 // The discover packet is already copied, just set flag here.
495 Mode
->DhcpDiscoverValid
= TRUE
;
497 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
498 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
500 // Other type of ACK is already cached. Bootp is special that we should
501 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
503 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
506 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
508 Mode
->DhcpAckReceived
= TRUE
;
511 // Copy the dhcp ack.
513 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
521 GC_NOTO: Add function description
523 @param Private GC_NOTO: add argument description
524 @param RcvdOffer GC_NOTO: add argument description
526 @return GC_NOTO: add return values
530 PxeBcCacheDhcpOffer (
531 IN PXEBC_PRIVATE_DATA
*Private
,
532 IN EFI_DHCP4_PACKET
*RcvdOffer
535 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
536 EFI_DHCP4_PACKET
*Offer
;
539 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
540 Offer
= &CachedOffer
->Packet
.Offer
;
543 // Cache the orignal dhcp packet
545 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
548 // Parse and validate the options (including dhcp option and vendor option)
550 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
554 OfferType
= CachedOffer
->OfferType
;
556 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
558 if (Private
->BootpIndex
!= 0) {
560 // Only cache the first bootp offer, discard others.
565 // Take as a dhcp only offer, but record index specifically.
567 Private
->BootpIndex
= Private
->NumOffers
+ 1;
571 if (IS_PROXY_DHCP_OFFER (Offer
)) {
573 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
575 Private
->GotProxyOffer
= TRUE
;
577 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
579 // Cache all binl offers.
581 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
582 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
583 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
585 // Only cache the first pxe10/wfm11a offers each, discard the others.
590 // Record index of the proxy dhcp offer with type other than binl.
592 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
596 // It's a dhcp offer with your address.
598 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
599 Private
->ServerCount
[OfferType
]++;
604 // Count the accepted offers.
606 Private
->NumOffers
++;
611 GC_NOTO: Add function description
613 @param Private GC_NOTO: add argument description
615 @return GC_NOTO: add return values
620 IN PXEBC_PRIVATE_DATA
*Private
625 EFI_DHCP4_PACKET
*Offer
;
627 Private
->SelectedOffer
= 0;
629 if (Private
->SortOffers
) {
631 // Select offer according to the priority
633 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
637 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
639 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
643 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
645 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
646 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
649 // DHCP only and proxy DHCP with PXE10
651 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
652 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
654 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
655 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
658 // DHCP only and proxy DHCP with WfM
660 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
661 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
663 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
667 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
669 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
670 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
673 // DHCP only and proxy DHCP with BINL
675 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
676 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
680 // Try offers with bootfile
682 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
684 // Select the first DHCP only offer with bootfile
686 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
687 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
688 Private
->SelectedOffer
= OfferIndex
+ 1;
693 if (Private
->SelectedOffer
== 0) {
695 // Select the Bootp reply with bootfile if any
697 Private
->SelectedOffer
= Private
->BootpIndex
;
702 // Try the offers in the received order.
704 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
706 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
708 if (IS_PROXY_DHCP_OFFER (Offer
)) {
715 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
716 ((!Private
->GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
718 // DHCP only offer but no proxy offer received and no bootfile option in this offer
723 Private
->SelectedOffer
= Index
+ 1;
731 GC_NOTO: Add function description
733 @param This GC_NOTO: add argument description
734 @param Context GC_NOTO: add argument description
735 @param CurrentState GC_NOTO: add argument description
736 @param Dhcp4Event GC_NOTO: add argument description
737 @param Packet GC_NOTO: add argument description
738 @param NewPacket GC_NOTO: add argument description
740 @retval EFI_SUCCESS GC_NOTO: Add description for return value
741 @retval EFI_ABORTED GC_NOTO: Add description for return value
746 IN EFI_DHCP4_PROTOCOL
* This
,
748 IN EFI_DHCP4_STATE CurrentState
,
749 IN EFI_DHCP4_EVENT Dhcp4Event
,
750 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
751 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
754 PXEBC_PRIVATE_DATA
*Private
;
755 EFI_PXE_BASE_CODE_MODE
*Mode
;
756 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
757 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
761 CHAR8
*SystemSerialNumber
;
762 EFI_DHCP4_HEADER
*DhcpHeader
;
764 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
765 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
766 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
767 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
768 (Dhcp4Event
!= Dhcp4SendRequest
)) {
772 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
773 Mode
= Private
->PxeBc
.Mode
;
774 Callback
= Private
->PxeBcCallback
;
777 // Override the Maximum DHCP Message Size.
779 MaxMsgSize
= PxeBcParseExtendOptions (
780 Packet
->Dhcp4
.Option
,
781 GET_OPTION_BUFFER_LEN (Packet
),
782 PXEBC_DHCP4_TAG_MAXMSG
784 if (MaxMsgSize
!= NULL
) {
785 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
786 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
789 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
790 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
791 Status
= Callback
->Callback (
796 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
798 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
803 Status
= EFI_SUCCESS
;
805 switch (Dhcp4Event
) {
807 case Dhcp4SendDiscover
:
808 case Dhcp4SendRequest
:
809 if (Mode
->SendGUID
) {
811 // send the system GUID instead of the MAC address as the hardware address
812 // in the DHCP packet header.
814 DhcpHeader
= &Packet
->Dhcp4
.Header
;
816 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
818 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
819 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
820 // GUID not yet set - send all 0's to show not programable
822 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
825 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
828 if (Dhcp4Event
== Dhcp4SendDiscover
) {
830 // Cache the dhcp discover packet, of which some information will be used later.
832 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
838 Status
= EFI_NOT_READY
;
839 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
841 // Cache the dhcp offers in Private->Dhcp4Offers[]
843 PxeBcCacheDhcpOffer (Private
, Packet
);
848 case Dhcp4SelectOffer
:
850 // Select an offer, if succeeded, Private->SelectedOffer points to
851 // the index of the selected one.
853 PxeBcSelectOffer (Private
);
855 if (Private
->SelectedOffer
== 0) {
856 Status
= EFI_ABORTED
;
858 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
867 ASSERT (Private
->SelectedOffer
!= 0);
869 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
881 GC_NOTO: Add function description
883 @param Private GC_NOTO: add argument description
884 @param OptList GC_NOTO: add argument description
885 @param IsDhcpDiscover GC_NOTO: add argument description
887 @return GC_NOTO: add return values
891 PxeBcBuildDhcpOptions (
892 IN PXEBC_PRIVATE_DATA
*Private
,
893 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
894 IN BOOLEAN IsDhcpDiscover
898 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
900 CHAR8
*SystemSerialNumber
;
903 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
905 if (!IsDhcpDiscover
) {
907 // Append message type.
909 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
910 OptList
[Index
]->Length
= 1;
911 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
912 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
914 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
917 // Append max message size.
919 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
920 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
921 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
922 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
923 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
925 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
928 // Parameter request list option.
930 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
931 OptList
[Index
]->Length
= 35;
932 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
933 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
934 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
935 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
936 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
937 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
938 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
939 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
940 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
941 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
942 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
943 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
944 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
945 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
946 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
947 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
948 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
949 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
950 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
951 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
952 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
953 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
954 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
955 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
956 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
957 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
958 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
959 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
960 OptEnt
.Para
->ParaList
[27] = 0x80;
961 OptEnt
.Para
->ParaList
[28] = 0x81;
962 OptEnt
.Para
->ParaList
[29] = 0x82;
963 OptEnt
.Para
->ParaList
[30] = 0x83;
964 OptEnt
.Para
->ParaList
[31] = 0x84;
965 OptEnt
.Para
->ParaList
[32] = 0x85;
966 OptEnt
.Para
->ParaList
[33] = 0x86;
967 OptEnt
.Para
->ParaList
[34] = 0x87;
969 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
972 // Append UUID/Guid-based client identifier option
974 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
975 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
976 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
977 OptEnt
.Uuid
->Type
= 0;
979 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
981 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
983 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
984 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
985 // GUID not yet set - send all 0's to show not programable
987 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
991 // Append client network device interface option
993 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
994 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
995 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
996 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
997 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
998 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
1001 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1004 // Append client system architecture option
1006 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
1007 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1008 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1009 Value
= HTONS (SYS_ARCH
);
1010 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1012 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1015 // Append client system architecture option
1017 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
1018 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
1019 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1020 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1021 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1022 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1023 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1024 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1032 GC_NOTO: Add function description
1034 @param Private GC_NOTO: add argument description
1035 @param Type GC_NOTO: add argument description
1036 @param Layer GC_NOTO: add argument description
1037 @param UseBis GC_NOTO: add argument description
1038 @param DestIp GC_NOTO: add argument description
1039 @param IpCount GC_NOTO: add argument description
1040 @param SrvList GC_NOTO: add argument description
1041 @param IsDiscv GC_NOTO: add argument description
1042 @param Reply GC_NOTO: add argument description
1044 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value
1048 PxeBcDiscvBootService (
1049 IN PXEBC_PRIVATE_DATA
* Private
,
1053 IN EFI_IP_ADDRESS
* DestIp
,
1055 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1057 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1060 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1061 EFI_PXE_BASE_CODE_MODE
*Mode
;
1062 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1063 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1069 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1070 EFI_DHCP4_PACKET
*Response
;
1071 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1073 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1074 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1076 CHAR8
*SystemSerialNumber
;
1077 EFI_DHCP4_HEADER
*DhcpHeader
;
1080 Mode
= Private
->PxeBc
.Mode
;
1081 Dhcp4
= Private
->Dhcp4
;
1082 Status
= EFI_SUCCESS
;
1084 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1086 if (DestIp
== NULL
) {
1087 Sport
= PXEBC_DHCP4_S_PORT
;
1090 Sport
= PXEBC_BS_DISCOVER_PORT
;
1094 if (!UseBis
&& Layer
!= NULL
) {
1095 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1098 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1102 // Add vendor option of PXE_BOOT_ITEM
1104 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1105 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1106 if (OptList
[OptCount
] == NULL
) {
1107 return EFI_OUT_OF_RESOURCES
;
1110 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1111 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1112 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1113 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1114 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1115 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1116 PxeBootItem
->Type
= HTONS (Type
);
1117 PxeBootItem
->Layer
= HTONS (*Layer
);
1118 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1123 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1126 gBS
->FreePool (OptList
[OptCount
- 1]);
1129 if (EFI_ERROR (Status
)) {
1133 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1134 if (Mode
->SendGUID
) {
1135 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
1137 // GUID not yet set - send all 0's to show not programable
1139 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1142 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
1145 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1146 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1147 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1149 Token
.RemotePort
= Sport
;
1151 if (DestIp
== NULL
) {
1152 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1154 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1157 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1160 Token
.ListenPointCount
= 1;
1161 Token
.ListenPoints
= &ListenPoint
;
1162 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1163 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1164 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1167 // Send Pxe Discover
1169 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1171 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1173 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1175 if (Token
.Status
!= EFI_TIMEOUT
) {
1180 if (!EFI_ERROR (Status
)) {
1186 Response
= Token
.ResponseList
;
1188 while (RepIndex
< Token
.ResponseCount
) {
1190 while (SrvIndex
< IpCount
) {
1192 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1196 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1203 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1210 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1213 if (RepIndex
< Token
.ResponseCount
) {
1215 if (Reply
!= NULL
) {
1216 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1220 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1221 Mode
->PxeDiscoverValid
= TRUE
;
1223 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1224 Mode
->PxeReplyReceived
= TRUE
;
1227 Status
= EFI_NOT_FOUND
;
1231 // free the responselist
1233 gBS
->FreePool (Token
.ResponseList
);
1236 // Free the dhcp packet
1238 gBS
->FreePool (Token
.Packet
);
1245 GC_NOTO: Add function description
1247 @param Buffer GC_NOTO: add argument description
1248 @param Length GC_NOTO: add argument description
1249 @param OptTag GC_NOTO: add argument description
1251 @return GC_NOTO: add return values
1254 EFI_DHCP4_PACKET_OPTION
*
1255 PxeBcParseExtendOptions (
1261 EFI_DHCP4_PACKET_OPTION
*Option
;
1264 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1267 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1269 if (Option
->OpCode
== OptTag
) {
1274 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1277 Offset
+= Option
->Length
+ 2;
1280 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1288 This function is to parse and check vendor options.
1290 @param Dhcp4Option Pointer to dhcp options
1291 @param VendorOption Pointer to vendor options
1293 @return TRUE : Valid vendor options
1294 @return FALSE : Invalid vendor options
1298 PxeBcParseVendorOptions (
1299 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1300 IN PXEBC_VENDOR_OPTION
*VendorOption
1304 UINT8 VendorOptionLen
;
1305 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1308 BitMap
= VendorOption
->BitMap
;
1309 VendorOptionLen
= Dhcp4Option
->Length
;
1310 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1313 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1315 // Parse every Vendor Option and set its BitMap
1317 switch (PxeOption
->OpCode
) {
1319 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1321 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1324 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1326 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1329 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1331 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1334 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1336 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1339 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1341 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1344 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1346 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1349 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1351 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1354 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1356 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1357 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1360 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1362 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1363 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1366 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1368 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1369 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1372 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1374 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1375 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1376 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1379 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1381 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1382 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1385 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1387 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1388 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1392 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1394 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1397 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1400 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1404 // FixMe, return falas if invalid of any vendor option
1412 GC_NOTO: Add function description
1414 @param Str GC_NOTO: add argument description
1415 @param Len GC_NOTO: add argument description
1417 @return GC_NOTO: add return values
1421 PxeBcDisplayBootItem (
1428 Len
= (UINT8
) MIN (70, Len
);
1431 AsciiPrint ("%a \n", Str
);
1437 GC_NOTO: Add function description
1439 @param Private GC_NOTO: add argument description
1441 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1442 @retval EFI_TIMEOUT GC_NOTO: Add description for return value
1446 PxeBcSelectBootPrompt (
1447 IN PXEBC_PRIVATE_DATA
*Private
1450 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1451 PXEBC_VENDOR_OPTION
*VendorOpt
;
1452 EFI_EVENT TimeoutEvent
;
1453 EFI_EVENT DescendEvent
;
1454 EFI_INPUT_KEY InputKey
;
1462 TimeoutEvent
= NULL
;
1463 DescendEvent
= NULL
;
1465 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1467 Packet
= &Private
->ProxyOffer
;
1470 Packet
= &Private
->Dhcp4Ack
;
1473 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1474 return EFI_NOT_FOUND
;
1477 VendorOpt
= &Packet
->PxeVendorOption
;
1479 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1483 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1484 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1485 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1491 if (Timeout
== 255) {
1495 Status
= gBS
->CreateEvent (
1503 if (EFI_ERROR (Status
)) {
1507 Status
= gBS
->SetTimer (
1510 Timeout
* TICKS_PER_SECOND
1513 if (EFI_ERROR (Status
)) {
1517 Status
= gBS
->CreateEvent (
1525 if (EFI_ERROR (Status
)) {
1529 Status
= gBS
->SetTimer (
1535 if (EFI_ERROR (Status
)) {
1539 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1540 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1542 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1544 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1545 AsciiPrint ("(%d) ", Timeout
--);
1547 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1549 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1550 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1551 AsciiPrint ("(%d) ", Timeout
--);
1554 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1556 gBS
->Stall (10 * TICKS_PER_MS
);
1560 if (InputKey
.ScanCode
== 0) {
1562 switch (InputKey
.UnicodeChar
) {
1564 Status
= EFI_ABORTED
;
1570 Status
= EFI_TIMEOUT
;
1578 switch (InputKey
.ScanCode
) {
1580 Status
= EFI_TIMEOUT
;
1584 Status
= EFI_ABORTED
;
1595 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1599 if (DescendEvent
!= NULL
) {
1600 gBS
->CloseEvent (DescendEvent
);
1603 if (TimeoutEvent
!= NULL
) {
1604 gBS
->CloseEvent (TimeoutEvent
);
1612 GC_NOTO: Add function description
1614 @param Private GC_NOTO: add argument description
1615 @param Type GC_NOTO: add argument description
1617 @retval EFI_ABORTED GC_NOTO: Add description for return value
1618 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1622 PxeBcSelectBootMenu (
1623 IN PXEBC_PRIVATE_DATA
*Private
,
1625 IN BOOLEAN UseDefaultItem
1628 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1629 PXEBC_VENDOR_OPTION
*VendorOpt
;
1630 EFI_INPUT_KEY InputKey
;
1639 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1640 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1647 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1649 Packet
= &Private
->ProxyOffer
;
1652 Packet
= &Private
->Dhcp4Ack
;
1655 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1657 VendorOpt
= &Packet
->PxeVendorOption
;
1659 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1663 SetMem (Blank
, sizeof(Blank
), ' ');
1665 MenuSize
= VendorOpt
->BootMenuLen
;
1666 MenuItem
= VendorOpt
->BootMenu
;
1668 while (MenuSize
> 0) {
1669 MenuArray
[Index
] = MenuItem
;
1670 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1671 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1675 if (UseDefaultItem
) {
1676 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
1677 *Type
= NTOHS (*Type
);
1683 for (Index
= 0; Index
< MenuNum
; Index
++) {
1684 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1687 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1691 // highlight selected row
1693 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1694 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1695 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1696 AsciiPrint ("%a\r", Blank
);
1697 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1698 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1699 LastSelect
= Select
;
1701 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1702 gBS
->Stall (10 * TICKS_PER_MS
);
1705 if (!InputKey
.ScanCode
) {
1706 switch (InputKey
.UnicodeChar
) {
1708 InputKey
.ScanCode
= SCAN_ESC
;
1711 case CTRL ('j'): /* linefeed */
1712 case CTRL ('m'): /* return */
1716 case CTRL ('i'): /* tab */
1720 InputKey
.ScanCode
= SCAN_DOWN
;
1723 case CTRL ('h'): /* backspace */
1726 InputKey
.ScanCode
= SCAN_UP
;
1730 InputKey
.ScanCode
= 0;
1734 switch (InputKey
.ScanCode
) {
1745 if (++Select
== MenuNum
) {
1756 case SCAN_PAGE_DOWN
:
1758 Select
= (UINT16
) (MenuNum
- 1);
1765 /* unhighlight last selected row */
1766 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1767 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1768 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1769 AsciiPrint ("%a\r", Blank
);
1770 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1771 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1775 // Swap the byte order
1777 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1778 *Type
= NTOHS (*Type
);