3 Copyright (c) 2007, 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 EFI_FIELD_OFFSET (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
) &&
405 (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
407 // The selected offer to finish the D.O.R.A. is a DHCP only offer and
408 // bootfile name is not provided in this offer, we need try proxy offers
409 // to get the bootfile name or the discovery info
411 ProxyOfferIndex
= Private
->NumOffers
;
413 if (Private
->SortOffers
) {
415 // Choose proxy offer from the type we stored during DHCP offer selection
417 ASSERT (Private
->ProxyIndex
[Private
->ProxyOfferType
] > 0);
419 if (Private
->ProxyOfferType
== DHCP4_PACKET_TYPE_BINL
) {
421 // We buffer all received BINL proxy offers, try them all one by one
423 if (!PxeBcTryBinlProxy (Private
, &ProxyOfferIndex
)) {
424 Status
= EFI_NO_RESPONSE
;
428 // For other types, only one proxy offer is buffered.
430 ProxyOfferIndex
= Private
->ProxyIndex
[Private
->ProxyOfferType
] - 1;
434 // Choose proxy offer in the received order.
436 Status
= EFI_NO_RESPONSE
;
438 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
440 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
441 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
443 // Skip non proxy dhcp offers.
448 if (Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_BINL
) {
452 if (!PxeBcTryBinl (Private
, Index
)) {
454 // Failed, skip to the next offer
460 Status
= EFI_SUCCESS
;
465 if (!EFI_ERROR (Status
) && (Private
->ProxyOfferType
!= DHCP4_PACKET_TYPE_BINL
)) {
467 // Copy the proxy offer to Mode and set the flag
469 PxeBcCopyProxyOffer (Private
, ProxyOfferIndex
);
473 if (!EFI_ERROR (Status
)) {
475 // Everything is OK, set the flag and copy the DHCP packets.
477 Mode
= Private
->PxeBc
.Mode
;
478 Offer
= &SelectedOffer
->Packet
.Offer
;
481 // The discover packet is already copied, just set flag here.
483 Mode
->DhcpDiscoverValid
= TRUE
;
485 Ack
= &Private
->Dhcp4Ack
.Packet
.Ack
;
486 if (SelectedOffer
->OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
488 // Other type of ACK is already cached. Bootp is special that we should
489 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
491 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Offer
);
494 PxeBcParseCachedDhcpPacket (&Private
->Dhcp4Ack
);
496 Mode
->DhcpAckReceived
= TRUE
;
499 // Copy the dhcp ack.
501 CopyMem (&Mode
->DhcpAck
, &Ack
->Dhcp4
, Ack
->Length
);
509 GC_NOTO: Add function description
511 @param Private GC_NOTO: add argument description
512 @param RcvdOffer GC_NOTO: add argument description
514 @return GC_NOTO: add return values
518 PxeBcCacheDhcpOffer (
519 IN PXEBC_PRIVATE_DATA
*Private
,
520 IN EFI_DHCP4_PACKET
*RcvdOffer
523 PXEBC_CACHED_DHCP4_PACKET
*CachedOffer
;
524 EFI_DHCP4_PACKET
*Offer
;
527 CachedOffer
= &Private
->Dhcp4Offers
[Private
->NumOffers
];
528 Offer
= &CachedOffer
->Packet
.Offer
;
531 // Cache the orignal dhcp packet
533 PxeBcCopyEfiDhcp4Packet (Offer
, RcvdOffer
);
536 // Parse and validate the options (including dhcp option and vendor option)
538 if (!PxeBcParseCachedDhcpPacket (CachedOffer
)) {
542 OfferType
= CachedOffer
->OfferType
;
544 if (OfferType
== DHCP4_PACKET_TYPE_BOOTP
) {
546 if (Private
->BootpIndex
!= 0) {
548 // Only cache the first bootp offer, discard others.
553 // Take as a dhcp only offer, but record index specifically.
555 Private
->BootpIndex
= Private
->NumOffers
+ 1;
559 if (IS_PROXY_DHCP_OFFER (Offer
)) {
561 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
563 if (OfferType
== DHCP4_PACKET_TYPE_BINL
) {
565 // Cache all binl offers.
567 Private
->BinlIndex
[Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]] = Private
->NumOffers
;
568 Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
]++;
569 } else if (Private
->ProxyIndex
[OfferType
] != 0) {
571 // Only cache the first pxe10/wfm11a offers each, discard the others.
576 // Record index of the proxy dhcp offer with type other than binl.
578 Private
->ProxyIndex
[OfferType
] = Private
->NumOffers
+ 1;
582 // It's a dhcp offer with your address.
584 Private
->OfferIndex
[OfferType
][Private
->ServerCount
[OfferType
]] = Private
->NumOffers
;
585 Private
->ServerCount
[OfferType
]++;
590 // Count the accepted offers.
592 Private
->NumOffers
++;
597 GC_NOTO: Add function description
599 @param Private GC_NOTO: add argument description
601 @return GC_NOTO: add return values
606 IN PXEBC_PRIVATE_DATA
*Private
611 EFI_DHCP4_PACKET
*Offer
;
612 BOOLEAN GotProxyOffer
;
614 Private
->SelectedOffer
= 0;
616 if (Private
->SortOffers
) {
618 // Select offer according to the priority
620 if (Private
->ServerCount
[DHCP4_PACKET_TYPE_PXE10
] > 0) {
624 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_PXE10
][0] + 1;
626 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_WFM11A
] > 0) {
630 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_WFM11A
][0] + 1;
632 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_PXE10
] > 0) &&
633 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
636 // DHCP only and proxy DHCP with PXE10
638 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
639 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_PXE10
;
641 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_WFM11A
] > 0) &&
642 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
645 // DHCP only and proxy DHCP with WfM
647 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
648 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_WFM11A
;
650 } else if (Private
->ServerCount
[DHCP4_PACKET_TYPE_BINL
] > 0) {
654 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_BINL
][0] + 1;
656 } else if ((Private
->ProxyIndex
[DHCP4_PACKET_TYPE_BINL
] > 0) &&
657 (Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
] > 0)
660 // DHCP only and proxy DHCP with BINL
662 Private
->SelectedOffer
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][0] + 1;
663 Private
->ProxyOfferType
= DHCP4_PACKET_TYPE_BINL
;
667 // Try offers with bootfile
669 for (Index
= 0; Index
< Private
->ServerCount
[DHCP4_PACKET_TYPE_DHCP_ONLY
]; Index
++) {
671 // Select the first DHCP only offer with bootfile
673 OfferIndex
= Private
->OfferIndex
[DHCP4_PACKET_TYPE_DHCP_ONLY
][Index
];
674 if (Private
->Dhcp4Offers
[OfferIndex
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
675 Private
->SelectedOffer
= OfferIndex
+ 1;
680 if (Private
->SelectedOffer
== 0) {
682 // Select the Bootp reply with bootfile if any
684 Private
->SelectedOffer
= Private
->BootpIndex
;
689 // Try the offers in the received order.
691 GotProxyOffer
= FALSE
;
692 for (Index
= 0; Index
< DHCP4_PACKET_TYPE_MAX
; Index
++) {
694 GotProxyOffer
= (BOOLEAN
) (Private
->ProxyIndex
[Index
] > 0);
700 for (Index
= 0; Index
< Private
->NumOffers
; Index
++) {
702 Offer
= &Private
->Dhcp4Offers
[Index
].Packet
.Offer
;
704 if (IS_PROXY_DHCP_OFFER (Offer
)) {
711 if ((Private
->Dhcp4Offers
[Index
].OfferType
== DHCP4_PACKET_TYPE_DHCP_ONLY
) &&
712 ((!GotProxyOffer
) && (Private
->Dhcp4Offers
[Index
].Dhcp4Option
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))) {
714 // DHCP only offer but no proxy offer received and no bootfile option in this offer
719 Private
->SelectedOffer
= Index
+ 1;
727 GC_NOTO: Add function description
729 @param This GC_NOTO: add argument description
730 @param Context GC_NOTO: add argument description
731 @param CurrentState GC_NOTO: add argument description
732 @param Dhcp4Event GC_NOTO: add argument description
733 @param Packet GC_NOTO: add argument description
734 @param NewPacket GC_NOTO: add argument description
736 @retval EFI_SUCCESS GC_NOTO: Add description for return value
737 @retval EFI_ABORTED GC_NOTO: Add description for return value
742 IN EFI_DHCP4_PROTOCOL
* This
,
744 IN EFI_DHCP4_STATE CurrentState
,
745 IN EFI_DHCP4_EVENT Dhcp4Event
,
746 IN EFI_DHCP4_PACKET
* Packet OPTIONAL
,
747 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
750 PXEBC_PRIVATE_DATA
*Private
;
751 EFI_PXE_BASE_CODE_MODE
*Mode
;
752 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
753 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
757 CHAR8
*SystemSerialNumber
;
758 EFI_DHCP4_HEADER
*DhcpHeader
;
760 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
761 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
762 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
763 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
764 (Dhcp4Event
!= Dhcp4SendRequest
)) {
768 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
769 Mode
= Private
->PxeBc
.Mode
;
770 Callback
= Private
->PxeBcCallback
;
773 // Override the Maximum DHCP Message Size.
775 MaxMsgSize
= PxeBcParseExtendOptions (
776 Packet
->Dhcp4
.Option
,
777 GET_OPTION_BUFFER_LEN (Packet
),
778 PXEBC_DHCP4_TAG_MAXMSG
780 if (MaxMsgSize
!= NULL
) {
781 Value
= HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
782 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
785 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
786 Received
= (BOOLEAN
) ((Dhcp4Event
== Dhcp4RcvdOffer
) || (Dhcp4Event
== Dhcp4RcvdAck
));
787 Status
= Callback
->Callback (
792 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
794 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
799 Status
= EFI_SUCCESS
;
801 switch (Dhcp4Event
) {
803 case Dhcp4SendDiscover
:
804 case Dhcp4SendRequest
:
805 if (Mode
->SendGUID
) {
807 // send the system GUID instead of the MAC address as the hardware address
808 // in the DHCP packet header.
810 DhcpHeader
= &Packet
->Dhcp4
.Header
;
812 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
814 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
815 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
816 // GUID not yet set - send all 0's to show not programable
818 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
821 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
824 if (Dhcp4Event
== Dhcp4SendDiscover
) {
826 // Cache the dhcp discover packet, of which some information will be used later.
828 CopyMem (Mode
->DhcpDiscover
.Raw
, &Packet
->Dhcp4
, Packet
->Length
);
834 Status
= EFI_NOT_READY
;
835 if (Private
->NumOffers
< PXEBC_MAX_OFFER_NUM
) {
837 // Cache the dhcp offers in Private->Dhcp4Offers[]
839 PxeBcCacheDhcpOffer (Private
, Packet
);
844 case Dhcp4SelectOffer
:
846 // Select an offer, if succeeded, Private->SelectedOffer points to
847 // the index of the selected one.
849 PxeBcSelectOffer (Private
);
851 if (Private
->SelectedOffer
== 0) {
852 Status
= EFI_ABORTED
;
854 *NewPacket
= &Private
->Dhcp4Offers
[Private
->SelectedOffer
- 1].Packet
.Offer
;
863 ASSERT (Private
->SelectedOffer
!= 0);
865 PxeBcCopyEfiDhcp4Packet (&Private
->Dhcp4Ack
.Packet
.Ack
, Packet
);
877 GC_NOTO: Add function description
879 @param Private GC_NOTO: add argument description
880 @param OptList GC_NOTO: add argument description
881 @param IsDhcpDiscover GC_NOTO: add argument description
883 @return GC_NOTO: add return values
887 PxeBcBuildDhcpOptions (
888 IN PXEBC_PRIVATE_DATA
*Private
,
889 IN EFI_DHCP4_PACKET_OPTION
**OptList
,
890 IN BOOLEAN IsDhcpDiscover
894 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
896 CHAR8
*SystemSerialNumber
;
899 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Private
->OptionBuffer
;
901 if (!IsDhcpDiscover
) {
903 // Append message type.
905 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
906 OptList
[Index
]->Length
= 1;
907 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
908 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
910 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
913 // Append max message size.
915 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
916 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
917 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
918 Value
= NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE
);
919 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
921 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
924 // Parameter request list option.
926 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
927 OptList
[Index
]->Length
= 35;
928 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
929 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
930 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
931 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
932 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
933 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
934 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
935 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
936 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
937 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
938 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
939 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
940 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
941 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
942 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
943 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
944 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
945 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
946 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
947 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
948 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
949 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
950 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
951 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
952 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
953 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
954 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
955 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
956 OptEnt
.Para
->ParaList
[27] = 0x80;
957 OptEnt
.Para
->ParaList
[28] = 0x81;
958 OptEnt
.Para
->ParaList
[29] = 0x82;
959 OptEnt
.Para
->ParaList
[30] = 0x83;
960 OptEnt
.Para
->ParaList
[31] = 0x84;
961 OptEnt
.Para
->ParaList
[32] = 0x85;
962 OptEnt
.Para
->ParaList
[33] = 0x86;
963 OptEnt
.Para
->ParaList
[34] = 0x87;
965 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
968 // Append UUID/Guid-based client identifier option
970 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
971 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UUID
);
972 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
973 OptEnt
.Uuid
->Type
= 0;
975 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
977 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) OptEnt
.Uuid
->Guid
, &SystemSerialNumber
))) {
979 // GUID not yet set - send all 0xff's to show programable (via SetVariable)
980 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
981 // GUID not yet set - send all 0's to show not programable
983 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
987 // Append client network device interface option
989 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
990 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_UNDI
);
991 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
992 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
993 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
994 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
997 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1000 // Append client system architecture option
1002 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
1003 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_ARCH
);
1004 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
1005 Value
= HTONS (SYS_ARCH
);
1006 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
1008 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
1011 // Append client system architecture option
1013 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
1014 OptList
[Index
]->Length
= sizeof (PXEBC_DHCP4_OPTION_CLID
);
1015 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
1016 CopyMem (OptEnt
.Clid
, DEFAULT_CLASS_ID_DATA
, sizeof (PXEBC_DHCP4_OPTION_CLID
));
1017 CvtNum (SYS_ARCH
, OptEnt
.Clid
->ArchitectureType
, sizeof (OptEnt
.Clid
->ArchitectureType
));
1018 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
1019 CvtNum (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
1020 CvtNum (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
1028 GC_NOTO: Add function description
1030 @param Private GC_NOTO: add argument description
1031 @param Type GC_NOTO: add argument description
1032 @param Layer GC_NOTO: add argument description
1033 @param UseBis GC_NOTO: add argument description
1034 @param DestIp GC_NOTO: add argument description
1035 @param IpCount GC_NOTO: add argument description
1036 @param SrvList GC_NOTO: add argument description
1037 @param IsDiscv GC_NOTO: add argument description
1038 @param Reply GC_NOTO: add argument description
1040 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value
1044 PxeBcDiscvBootService (
1045 IN PXEBC_PRIVATE_DATA
* Private
,
1049 IN EFI_IP_ADDRESS
* DestIp
,
1051 IN EFI_PXE_BASE_CODE_SRVLIST
* SrvList
,
1053 OUT EFI_DHCP4_PACKET
* Reply OPTIONAL
1056 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1057 EFI_PXE_BASE_CODE_MODE
*Mode
;
1058 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1059 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1065 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1066 EFI_DHCP4_PACKET
*Response
;
1067 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_MAX_OPTION_NUM
];
1069 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1070 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1072 CHAR8
*SystemSerialNumber
;
1073 EFI_DHCP4_HEADER
*DhcpHeader
;
1076 Mode
= Private
->PxeBc
.Mode
;
1077 Dhcp4
= Private
->Dhcp4
;
1078 Status
= EFI_SUCCESS
;
1080 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1082 if (DestIp
== NULL
) {
1083 Sport
= PXEBC_DHCP4_S_PORT
;
1086 Sport
= PXEBC_BS_DISCOVER_PORT
;
1090 if (!UseBis
&& Layer
!= NULL
) {
1091 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1094 OptCount
= PxeBcBuildDhcpOptions (Private
, OptList
, FALSE
);
1098 // Add vendor option of PXE_BOOT_ITEM
1100 VendorOptLen
= (sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1;
1101 OptList
[OptCount
] = AllocatePool (VendorOptLen
);
1102 if (OptList
[OptCount
] == NULL
) {
1103 return EFI_OUT_OF_RESOURCES
;
1106 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1107 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1108 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1109 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1110 PxeOpt
->Length
= sizeof (PXEBC_OPTION_BOOT_ITEM
);
1111 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1112 PxeBootItem
->Type
= HTONS (Type
);
1113 PxeBootItem
->Layer
= HTONS (*Layer
);
1114 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1119 Status
= Dhcp4
->Build (Dhcp4
, &Private
->SeedPacket
, 0, NULL
, OptCount
, OptList
, &Token
.Packet
);
1122 gBS
->FreePool (OptList
[OptCount
- 1]);
1125 if (EFI_ERROR (Status
)) {
1129 DhcpHeader
= &Token
.Packet
->Dhcp4
.Header
;
1130 if (Mode
->SendGUID
) {
1131 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID
*) DhcpHeader
->ClientHwAddr
, &SystemSerialNumber
))) {
1133 // GUID not yet set - send all 0's to show not programable
1135 ZeroMem (DhcpHeader
->ClientHwAddr
, sizeof (EFI_GUID
));
1138 DhcpHeader
->HwAddrLen
= sizeof (EFI_GUID
);
1141 Token
.Packet
->Dhcp4
.Header
.Xid
= NET_RANDOM (NetRandomInitSeed ());
1142 Token
.Packet
->Dhcp4
.Header
.Reserved
= (UINT16
) ((IsBCast
) ? 0xf000 : 0x0);
1143 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1145 Token
.RemotePort
= Sport
;
1147 if (DestIp
== NULL
) {
1148 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1150 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1153 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1156 Token
.ListenPointCount
= 1;
1157 Token
.ListenPoints
= &ListenPoint
;
1158 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1159 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1160 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1163 // Send Pxe Discover
1165 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1167 Token
.TimeoutValue
= PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
;
1169 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1171 if (Token
.Status
!= EFI_TIMEOUT
) {
1176 if (!EFI_ERROR (Status
)) {
1182 Response
= Token
.ResponseList
;
1184 while (RepIndex
< Token
.ResponseCount
) {
1186 while (SrvIndex
< IpCount
) {
1188 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1192 if ((SrvList
[SrvIndex
].Type
== Type
) && EFI_IP4_EQUAL (&(Response
->Dhcp4
.Header
.ServerAddr
), &(Private
->ServerIp
))) {
1199 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1206 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1209 if (RepIndex
< Token
.ResponseCount
) {
1211 if (Reply
!= NULL
) {
1212 PxeBcCopyEfiDhcp4Packet (Reply
, Response
);
1216 CopyMem (&(Mode
->PxeDiscover
), &(Token
.Packet
->Dhcp4
), Token
.Packet
->Length
);
1217 Mode
->PxeDiscoverValid
= TRUE
;
1219 CopyMem (Mode
->PxeReply
.Raw
, &Response
->Dhcp4
, Response
->Length
);
1220 Mode
->PxeReplyReceived
= TRUE
;
1223 Status
= EFI_NOT_FOUND
;
1227 // free the responselist
1229 gBS
->FreePool (Token
.ResponseList
);
1232 // Free the dhcp packet
1234 gBS
->FreePool (Token
.Packet
);
1241 GC_NOTO: Add function description
1243 @param Buffer GC_NOTO: add argument description
1244 @param Length GC_NOTO: add argument description
1245 @param OptTag GC_NOTO: add argument description
1247 @return GC_NOTO: add return values
1250 EFI_DHCP4_PACKET_OPTION
*
1251 PxeBcParseExtendOptions (
1257 EFI_DHCP4_PACKET_OPTION
*Option
;
1260 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
1263 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
1265 if (Option
->OpCode
== OptTag
) {
1270 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1273 Offset
+= Option
->Length
+ 2;
1276 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
1284 This function is to parse and check vendor options.
1286 @param Dhcp4Option Pointer to dhcp options
1287 @param VendorOption Pointer to vendor options
1289 @return TRUE : Valid vendor options
1290 @return FALSE : Invalid vendor options
1294 PxeBcParseVendorOptions (
1295 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
1296 IN PXEBC_VENDOR_OPTION
*VendorOption
1300 UINT8 VendorOptionLen
;
1301 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
1304 BitMap
= VendorOption
->BitMap
;
1305 VendorOptionLen
= Dhcp4Option
->Length
;
1306 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
1309 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
1311 // Parse every Vendor Option and set its BitMap
1313 switch (PxeOption
->OpCode
) {
1315 case PXEBC_VENDOR_TAG_MTFTP_IP
:
1317 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1320 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
1322 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
1325 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
1327 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
1330 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
1332 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
1335 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
1337 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
1340 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
1342 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
1345 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
1347 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1350 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
1352 VendorOption
->BootSvrLen
= PxeOption
->Length
;
1353 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
1356 case PXEBC_VENDOR_TAG_BOOT_MENU
:
1358 VendorOption
->BootMenuLen
= PxeOption
->Length
;
1359 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
1362 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
1364 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
1365 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
1368 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
1370 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
1371 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
1372 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
1375 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
1377 VendorOption
->CredTypeLen
= PxeOption
->Length
;
1378 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
1381 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
1383 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
1384 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
1388 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
1390 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
1393 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
1396 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
1400 // FixMe, return falas if invalid of any vendor option
1408 GC_NOTO: Add function description
1410 @param Str GC_NOTO: add argument description
1411 @param Len GC_NOTO: add argument description
1413 @return GC_NOTO: add return values
1417 PxeBcDisplayBootItem (
1424 Len
= (UINT8
) MIN (70, Len
);
1427 AsciiPrint ("%a \n", Str
);
1433 GC_NOTO: Add function description
1435 @param Private GC_NOTO: add argument description
1437 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1438 @retval EFI_TIMEOUT GC_NOTO: Add description for return value
1442 PxeBcSelectBootPrompt (
1443 IN PXEBC_PRIVATE_DATA
*Private
1446 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1447 PXEBC_VENDOR_OPTION
*VendorOpt
;
1448 EFI_EVENT TimeoutEvent
;
1449 EFI_EVENT DescendEvent
;
1450 EFI_INPUT_KEY InputKey
;
1458 TimeoutEvent
= NULL
;
1459 DescendEvent
= NULL
;
1461 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1463 Packet
= &Private
->ProxyOffer
;
1466 Packet
= &Private
->Dhcp4Ack
;
1469 if (Packet
->OfferType
!= DHCP4_PACKET_TYPE_PXE10
) {
1470 return EFI_NOT_FOUND
;
1473 VendorOpt
= &Packet
->PxeVendorOption
;
1475 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
1479 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
1480 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
1481 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
1487 if (Timeout
== 255) {
1491 Status
= gBS
->CreateEvent (
1499 if (EFI_ERROR (Status
)) {
1503 Status
= gBS
->SetTimer (
1506 Timeout
* TICKS_PER_SECOND
1509 if (EFI_ERROR (Status
)) {
1513 Status
= gBS
->CreateEvent (
1521 if (EFI_ERROR (Status
)) {
1525 Status
= gBS
->SetTimer (
1531 if (EFI_ERROR (Status
)) {
1535 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
1536 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
1538 PxeBcDisplayBootItem (Prompt
, PromptLen
);
1540 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1541 AsciiPrint ("(%d) ", Timeout
--);
1543 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1545 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
1546 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
1547 AsciiPrint ("(%d) ", Timeout
--);
1550 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1552 gBS
->Stall (10 * TICKS_PER_MS
);
1556 if (InputKey
.ScanCode
== 0) {
1558 switch (InputKey
.UnicodeChar
) {
1560 Status
= EFI_ABORTED
;
1566 Status
= EFI_TIMEOUT
;
1574 switch (InputKey
.ScanCode
) {
1576 Status
= EFI_TIMEOUT
;
1580 Status
= EFI_ABORTED
;
1591 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
1595 if (DescendEvent
!= NULL
) {
1596 gBS
->CloseEvent (DescendEvent
);
1599 if (TimeoutEvent
!= NULL
) {
1600 gBS
->CloseEvent (TimeoutEvent
);
1608 GC_NOTO: Add function description
1610 @param Private GC_NOTO: add argument description
1611 @param Type GC_NOTO: add argument description
1613 @retval EFI_ABORTED GC_NOTO: Add description for return value
1614 @retval EFI_SUCCESS GC_NOTO: Add description for return value
1618 PxeBcSelectBootMenu (
1619 IN PXEBC_PRIVATE_DATA
*Private
,
1621 IN BOOLEAN UseDefaultItem
1624 PXEBC_CACHED_DHCP4_PACKET
*Packet
;
1625 PXEBC_VENDOR_OPTION
*VendorOpt
;
1626 EFI_INPUT_KEY InputKey
;
1635 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
1636 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MAX_MENU_NUM
];
1643 if (Private
->PxeBc
.Mode
->ProxyOfferReceived
) {
1645 Packet
= &Private
->ProxyOffer
;
1648 Packet
= &Private
->Dhcp4Ack
;
1651 ASSERT (Packet
->OfferType
== DHCP4_PACKET_TYPE_PXE10
);
1653 VendorOpt
= &Packet
->PxeVendorOption
;
1655 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
1659 SetMem (Blank
, sizeof(Blank
), ' ');
1661 MenuSize
= VendorOpt
->BootMenuLen
;
1662 MenuItem
= VendorOpt
->BootMenu
;
1664 while (MenuSize
> 0) {
1665 MenuArray
[Index
] = MenuItem
;
1666 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
1667 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
1671 if (UseDefaultItem
) {
1672 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
1673 *Type
= NTOHS (*Type
);
1679 for (Index
= 0; Index
< MenuNum
; Index
++) {
1680 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
1683 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
1687 // highlight selected row
1689 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
1690 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
1691 Blank
[MenuArray
[Select
]->DescLen
] = 0;
1692 AsciiPrint ("%a\r", Blank
);
1693 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
1694 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1695 LastSelect
= Select
;
1697 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
1698 gBS
->Stall (10 * TICKS_PER_MS
);
1701 if (!InputKey
.ScanCode
) {
1702 switch (InputKey
.UnicodeChar
) {
1704 InputKey
.ScanCode
= SCAN_ESC
;
1707 case CTRL ('j'): /* linefeed */
1708 case CTRL ('m'): /* return */
1712 case CTRL ('i'): /* tab */
1716 InputKey
.ScanCode
= SCAN_DOWN
;
1719 case CTRL ('h'): /* backspace */
1722 InputKey
.ScanCode
= SCAN_UP
;
1726 InputKey
.ScanCode
= 0;
1730 switch (InputKey
.ScanCode
) {
1741 if (++Select
== MenuNum
) {
1752 case SCAN_PAGE_DOWN
:
1754 Select
= (UINT16
) (MenuNum
- 1);
1761 /* unhighlight last selected row */
1762 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1763 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
1764 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
1765 AsciiPrint ("%a\r", Blank
);
1766 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
1767 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
1771 // Swap the byte order
1773 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
1774 *Type
= NTOHS (*Type
);