2 Functions implementation related with DHCPv4 for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "PxeBcImpl.h"
13 // This is a map from the interested DHCP4 option tags' index to the tag value.
15 UINT8 mInterestedDhcp4Tags
[PXEBC_DHCP4_TAG_INDEX_MAX
] = {
16 DHCP4_TAG_BOOTFILE_LEN
,
21 DHCP4_TAG_VENDOR_CLASS_ID
,
26 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
28 UINT32 mPxeDhcpTimeout
[4] = { 4, 8, 16, 32 };
31 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
33 @param[in] Buffer Pointer to the option buffer.
34 @param[in] Length Length of the option buffer.
35 @param[in] OptTag Tag of the required option.
37 @retval NULL Failed to find the required option.
38 @retval Others The position of the required option.
41 EFI_DHCP4_PACKET_OPTION
*
42 PxeBcParseDhcp4Options (
48 EFI_DHCP4_PACKET_OPTION
*Option
;
51 Option
= (EFI_DHCP4_PACKET_OPTION
*)Buffer
;
54 while (Offset
< Length
&& Option
->OpCode
!= DHCP4_TAG_EOP
) {
55 if (Option
->OpCode
== OptTag
) {
57 // Found the required option.
63 // Skip the current option to the next.
65 if (Option
->OpCode
== DHCP4_TAG_PAD
) {
68 Offset
+= Option
->Length
+ 2;
71 Option
= (EFI_DHCP4_PACKET_OPTION
*)(Buffer
+ Offset
);
78 Parse the PXE vendor options and extract the information from them.
80 @param[in] Dhcp4Option Pointer to vendor options in buffer.
81 @param[in] VendorOption Pointer to structure to store information in vendor options.
85 PxeBcParseVendorOptions (
86 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
87 IN PXEBC_VENDOR_OPTION
*VendorOption
91 UINT8 VendorOptionLen
;
92 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
95 BitMap
= VendorOption
->BitMap
;
96 VendorOptionLen
= Dhcp4Option
->Length
;
97 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*)&Dhcp4Option
->Data
[0];
100 ASSERT (PxeOption
!= NULL
);
102 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= DHCP4_TAG_EOP
)) {
104 // Parse all the interesting PXE vendor options one by one.
106 switch (PxeOption
->OpCode
) {
107 case PXEBC_VENDOR_TAG_MTFTP_IP
:
109 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
112 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
114 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
117 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
119 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
122 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
124 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
127 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
129 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
132 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
134 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
137 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
139 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
142 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
144 VendorOption
->BootSvrLen
= PxeOption
->Length
;
145 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*)PxeOption
->Data
;
148 case PXEBC_VENDOR_TAG_BOOT_MENU
:
150 VendorOption
->BootMenuLen
= PxeOption
->Length
;
151 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*)PxeOption
->Data
;
154 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
156 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
157 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*)PxeOption
->Data
;
160 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
162 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
163 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
164 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
167 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
169 VendorOption
->CredTypeLen
= PxeOption
->Length
;
170 VendorOption
->CredType
= (UINT32
*)PxeOption
->Data
;
173 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
175 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
176 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
181 // Not interesting PXE vendor options.
187 // Set the bit map for the special PXE options.
189 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
192 // Continue to the next option.
194 if (PxeOption
->OpCode
== DHCP4_TAG_PAD
) {
197 Offset
= (UINT8
)(Offset
+ PxeOption
->Length
+ 2);
200 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*)(Dhcp4Option
->Data
+ Offset
);
205 Build the options buffer for the DHCPv4 request packet.
207 @param[in] Private Pointer to PxeBc private data.
208 @param[out] OptList Pointer to the option pointer array.
209 @param[in] Buffer Pointer to the buffer to contain the option list.
210 @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.
211 Otherwise, it is not necessary.
213 @return Index The count of the built-in options.
217 PxeBcBuildDhcp4Options (
218 IN PXEBC_PRIVATE_DATA
*Private
,
219 OUT EFI_DHCP4_PACKET_OPTION
**OptList
,
221 IN BOOLEAN NeedMsgType
225 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
229 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*)Buffer
;
233 // Append message type.
235 OptList
[Index
]->OpCode
= DHCP4_TAG_MSG_TYPE
;
236 OptList
[Index
]->Length
= 1;
237 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*)OptList
[Index
]->Data
;
238 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
240 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
243 // Append max message size.
245 OptList
[Index
]->OpCode
= DHCP4_TAG_MAXMSG
;
246 OptList
[Index
]->Length
= (UINT8
)sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
247 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*)OptList
[Index
]->Data
;
248 Value
= NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE
);
249 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
251 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
255 // Append parameter request list option.
257 OptList
[Index
]->OpCode
= DHCP4_TAG_PARA_LIST
;
258 OptList
[Index
]->Length
= 35;
259 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*)OptList
[Index
]->Data
;
260 OptEnt
.Para
->ParaList
[0] = DHCP4_TAG_NETMASK
;
261 OptEnt
.Para
->ParaList
[1] = DHCP4_TAG_TIME_OFFSET
;
262 OptEnt
.Para
->ParaList
[2] = DHCP4_TAG_ROUTER
;
263 OptEnt
.Para
->ParaList
[3] = DHCP4_TAG_TIME_SERVER
;
264 OptEnt
.Para
->ParaList
[4] = DHCP4_TAG_NAME_SERVER
;
265 OptEnt
.Para
->ParaList
[5] = DHCP4_TAG_DNS_SERVER
;
266 OptEnt
.Para
->ParaList
[6] = DHCP4_TAG_HOSTNAME
;
267 OptEnt
.Para
->ParaList
[7] = DHCP4_TAG_BOOTFILE_LEN
;
268 OptEnt
.Para
->ParaList
[8] = DHCP4_TAG_DOMAINNAME
;
269 OptEnt
.Para
->ParaList
[9] = DHCP4_TAG_ROOTPATH
;
270 OptEnt
.Para
->ParaList
[10] = DHCP4_TAG_EXTEND_PATH
;
271 OptEnt
.Para
->ParaList
[11] = DHCP4_TAG_EMTU
;
272 OptEnt
.Para
->ParaList
[12] = DHCP4_TAG_TTL
;
273 OptEnt
.Para
->ParaList
[13] = DHCP4_TAG_BROADCAST
;
274 OptEnt
.Para
->ParaList
[14] = DHCP4_TAG_NIS_DOMAIN
;
275 OptEnt
.Para
->ParaList
[15] = DHCP4_TAG_NIS_SERVER
;
276 OptEnt
.Para
->ParaList
[16] = DHCP4_TAG_NTP_SERVER
;
277 OptEnt
.Para
->ParaList
[17] = DHCP4_TAG_VENDOR
;
278 OptEnt
.Para
->ParaList
[18] = DHCP4_TAG_REQUEST_IP
;
279 OptEnt
.Para
->ParaList
[19] = DHCP4_TAG_LEASE
;
280 OptEnt
.Para
->ParaList
[20] = DHCP4_TAG_SERVER_ID
;
281 OptEnt
.Para
->ParaList
[21] = DHCP4_TAG_T1
;
282 OptEnt
.Para
->ParaList
[22] = DHCP4_TAG_T2
;
283 OptEnt
.Para
->ParaList
[23] = DHCP4_TAG_VENDOR_CLASS_ID
;
284 OptEnt
.Para
->ParaList
[24] = DHCP4_TAG_TFTP
;
285 OptEnt
.Para
->ParaList
[25] = DHCP4_TAG_BOOTFILE
;
286 OptEnt
.Para
->ParaList
[26] = DHCP4_TAG_UUID
;
287 OptEnt
.Para
->ParaList
[27] = 0x80;
288 OptEnt
.Para
->ParaList
[28] = 0x81;
289 OptEnt
.Para
->ParaList
[29] = 0x82;
290 OptEnt
.Para
->ParaList
[30] = 0x83;
291 OptEnt
.Para
->ParaList
[31] = 0x84;
292 OptEnt
.Para
->ParaList
[32] = 0x85;
293 OptEnt
.Para
->ParaList
[33] = 0x86;
294 OptEnt
.Para
->ParaList
[34] = 0x87;
296 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
299 // Append UUID/Guid-based client identifier option
301 OptList
[Index
]->OpCode
= DHCP4_TAG_UUID
;
302 OptList
[Index
]->Length
= (UINT8
)sizeof (PXEBC_DHCP4_OPTION_UUID
);
303 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*)OptList
[Index
]->Data
;
304 OptEnt
.Uuid
->Type
= 0;
306 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
308 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*)OptEnt
.Uuid
->Guid
))) {
310 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
312 DEBUG ((DEBUG_WARN
, "PXE: Failed to read system GUID from the smbios table!\n"));
313 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
317 // Append client network device interface option
319 OptList
[Index
]->OpCode
= DHCP4_TAG_UNDI
;
320 OptList
[Index
]->Length
= (UINT8
)sizeof (PXEBC_DHCP4_OPTION_UNDI
);
321 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*)OptList
[Index
]->Data
;
323 if (Private
->Nii
!= NULL
) {
324 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
325 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
326 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
328 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
329 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
330 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
334 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
337 // Append client system architecture option
339 OptList
[Index
]->OpCode
= DHCP4_TAG_ARCH
;
340 OptList
[Index
]->Length
= (UINT8
)sizeof (PXEBC_DHCP4_OPTION_ARCH
);
341 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*)OptList
[Index
]->Data
;
342 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
343 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
345 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
348 // Append vendor class identify option
350 OptList
[Index
]->OpCode
= DHCP4_TAG_VENDOR_CLASS_ID
;
351 OptList
[Index
]->Length
= (UINT8
)sizeof (PXEBC_DHCP4_OPTION_CLID
);
352 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*)OptList
[Index
]->Data
;
355 DEFAULT_CLASS_ID_DATA
,
356 sizeof (PXEBC_DHCP4_OPTION_CLID
)
358 PxeBcUintnToAscDecWithFormat (
359 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
360 OptEnt
.Clid
->ArchitectureType
,
361 sizeof (OptEnt
.Clid
->ArchitectureType
)
364 if (Private
->Nii
!= NULL
) {
365 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
366 PxeBcUintnToAscDecWithFormat (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
367 PxeBcUintnToAscDecWithFormat (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
376 Create a template DHCPv4 packet as a seed.
378 @param[out] Seed Pointer to the seed packet.
379 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.
383 PxeBcSeedDhcp4Packet (
384 OUT EFI_DHCP4_PACKET
*Seed
,
385 IN EFI_UDP4_PROTOCOL
*Udp4
388 EFI_SIMPLE_NETWORK_MODE Mode
;
389 EFI_DHCP4_HEADER
*Header
;
392 // Get IfType and HwAddressSize from SNP mode data.
394 Udp4
->GetModeData (Udp4
, NULL
, NULL
, NULL
, &Mode
);
396 Seed
->Size
= sizeof (EFI_DHCP4_PACKET
);
397 Seed
->Length
= sizeof (Seed
->Dhcp4
);
398 Header
= &Seed
->Dhcp4
.Header
;
399 ZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
400 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
401 Header
->HwType
= Mode
.IfType
;
402 Header
->HwAddrLen
= (UINT8
)Mode
.HwAddressSize
;
403 CopyMem (Header
->ClientHwAddr
, &Mode
.CurrentAddress
, Header
->HwAddrLen
);
405 Seed
->Dhcp4
.Magik
= PXEBC_DHCP4_MAGIC
;
406 Seed
->Dhcp4
.Option
[0] = DHCP4_TAG_EOP
;
410 Cache the DHCPv4 packet.
412 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
413 @param[in] Src Pointer to the DHCPv4 packet to be cached.
415 @retval EFI_SUCCESS Packet is copied.
416 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
420 PxeBcCacheDhcp4Packet (
421 IN EFI_DHCP4_PACKET
*Dst
,
422 IN EFI_DHCP4_PACKET
*Src
425 if (Dst
->Size
< Src
->Length
) {
426 return EFI_BUFFER_TOO_SMALL
;
429 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
430 Dst
->Length
= Src
->Length
;
436 Parse the cached DHCPv4 packet, including all the options.
438 @param[in] Cache4 Pointer to cached DHCPv4 packet.
440 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
441 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.
445 PxeBcParseDhcp4Packet (
446 IN PXEBC_DHCP4_PACKET_CACHE
*Cache4
449 EFI_DHCP4_PACKET
*Offer
;
450 EFI_DHCP4_PACKET_OPTION
**Options
;
451 EFI_DHCP4_PACKET_OPTION
*Option
;
452 PXEBC_OFFER_TYPE OfferType
;
454 BOOLEAN IsProxyOffer
;
457 BOOLEAN FileFieldOverloaded
;
459 IsProxyOffer
= FALSE
;
461 FileFieldOverloaded
= FALSE
;
463 ZeroMem (Cache4
->OptList
, sizeof (Cache4
->OptList
));
464 ZeroMem (&Cache4
->VendorOpt
, sizeof (Cache4
->VendorOpt
));
466 Offer
= &Cache4
->Packet
.Offer
;
467 Options
= Cache4
->OptList
;
470 // Parse DHCPv4 options in this offer, and store the pointers.
471 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
473 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
474 Options
[Index
] = PxeBcParseDhcp4Options (
476 GET_OPTION_BUFFER_LEN (Offer
),
477 mInterestedDhcp4Tags
[Index
]
482 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
483 // If yes, try to parse options from the BootFileName field, then ServerName field.
485 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
486 if (Option
!= NULL
) {
487 if ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
) != 0) {
488 FileFieldOverloaded
= TRUE
;
489 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
490 if (Options
[Index
] == NULL
) {
491 Options
[Index
] = PxeBcParseDhcp4Options (
492 (UINT8
*)Offer
->Dhcp4
.Header
.BootFileName
,
493 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
494 mInterestedDhcp4Tags
[Index
]
500 if ((Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME
) != 0) {
501 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
502 if (Options
[Index
] == NULL
) {
503 Options
[Index
] = PxeBcParseDhcp4Options (
504 (UINT8
*)Offer
->Dhcp4
.Header
.ServerName
,
505 sizeof (Offer
->Dhcp4
.Header
.ServerName
),
506 mInterestedDhcp4Tags
[Index
]
514 // The offer with zero "yiaddr" is a proxy offer.
516 if (Offer
->Dhcp4
.Header
.YourAddr
.Addr
[0] == 0) {
521 // The offer with "PXEClient" is a PXE offer.
523 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
524 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
525 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0))
531 // Parse PXE vendor options in this offer, and store the contents/pointers.
533 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
534 if (IsPxeOffer
&& (Option
!= NULL
)) {
535 PxeBcParseVendorOptions (Option
, &Cache4
->VendorOpt
);
539 // Parse PXE boot file name:
540 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
541 // Otherwise, read from boot file field in DHCP header.
543 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
545 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
546 // terminated string. So force to append null terminated character at the end of string.
548 Ptr8
= (UINT8
*)&Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
549 Ptr8
+= Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
550 if (*(Ptr8
- 1) != '\0') {
553 } else if (!FileFieldOverloaded
&& (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
555 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
556 // Do not count dhcp option header here, or else will destroy the serverhostname.
558 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*)
559 (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
560 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
564 // Determine offer type of the DHCPv4 packet.
566 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
567 if ((Option
== NULL
) || (Option
->Data
[0] == 0)) {
569 // It's a Bootp offer.
571 OfferType
= PxeOfferTypeBootp
;
573 Option
= Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
574 if (Option
== NULL
) {
576 // If the Bootp offer without bootfilename, discard it.
578 return EFI_DEVICE_ERROR
;
581 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4
->VendorOpt
.BitMap
)) {
583 // It's a PXE10 offer with PXEClient and discover vendor option.
585 OfferType
= IsProxyOffer
? PxeOfferTypeProxyPxe10
: PxeOfferTypeDhcpPxe10
;
586 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4
->VendorOpt
.BitMap
)) {
588 // It's a WFM11a offer with PXEClient and mtftp vendor option.
589 // But multi-cast download is not supported currently, so discard it.
591 return EFI_DEVICE_ERROR
;
592 } else if (IsPxeOffer
) {
594 // It's a BINL offer only with PXEClient.
596 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
599 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
601 OfferType
= PxeOfferTypeDhcpOnly
;
605 Cache4
->OfferType
= OfferType
;
611 Cache the DHCPv4 ack packet, and parse it on demand.
613 @param[in] Private Pointer to PxeBc private data.
614 @param[in] Ack Pointer to the DHCPv4 ack packet.
615 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
617 @retval EFI_SUCCESS Cache and parse the packet successfully.
618 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
623 IN PXEBC_PRIVATE_DATA
*Private
,
624 IN EFI_DHCP4_PACKET
*Ack
,
628 EFI_PXE_BASE_CODE_MODE
*Mode
;
631 Mode
= Private
->PxeBc
.Mode
;
633 Status
= PxeBcCacheDhcp4Packet (&Private
->DhcpAck
.Dhcp4
.Packet
.Ack
, Ack
);
634 if (EFI_ERROR (Status
)) {
640 // Parse the ack packet and store it into mode data if needed.
642 PxeBcParseDhcp4Packet (&Private
->DhcpAck
.Dhcp4
);
643 CopyMem (&Mode
->DhcpAck
.Dhcpv4
, &Ack
->Dhcp4
, Ack
->Length
);
644 Mode
->DhcpAckReceived
= TRUE
;
651 Cache the DHCPv4 proxy offer packet according to the received order.
653 @param[in] Private Pointer to PxeBc private data.
654 @param[in] OfferIndex The received order of offer packets.
656 @retval EFI_SUCCESS Cache and parse the packet successfully.
657 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
661 PxeBcCopyProxyOffer (
662 IN PXEBC_PRIVATE_DATA
*Private
,
666 EFI_PXE_BASE_CODE_MODE
*Mode
;
667 EFI_DHCP4_PACKET
*Offer
;
670 ASSERT (OfferIndex
< Private
->OfferNum
);
671 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
673 Mode
= Private
->PxeBc
.Mode
;
674 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp4
.Packet
.Offer
;
677 // Cache the proxy offer packet and parse it.
679 Status
= PxeBcCacheDhcp4Packet (&Private
->ProxyOffer
.Dhcp4
.Packet
.Offer
, Offer
);
680 if (EFI_ERROR (Status
)) {
684 PxeBcParseDhcp4Packet (&Private
->ProxyOffer
.Dhcp4
);
687 // Store this packet into mode data.
689 CopyMem (&Mode
->ProxyOffer
.Dhcpv4
, &Offer
->Dhcp4
, Offer
->Length
);
690 Mode
->ProxyOfferReceived
= TRUE
;
696 Retry to request bootfile name by the BINL offer.
698 @param[in] Private Pointer to PxeBc private data.
699 @param[in] Index The received order of offer packets.
701 @retval EFI_SUCCESS Successfully retried to request bootfile name.
702 @retval EFI_DEVICE_ERROR Failed to retry bootfile name.
706 PxeBcRetryBinlOffer (
707 IN PXEBC_PRIVATE_DATA
*Private
,
711 EFI_DHCP4_PACKET
*Offer
;
712 EFI_IP_ADDRESS ServerIp
;
714 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
715 EFI_DHCP4_PACKET
*Reply
;
717 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
719 Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
== PxeOfferTypeDhcpBinl
||
720 Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
== PxeOfferTypeProxyBinl
723 Offer
= &Private
->OfferBuffer
[Index
].Dhcp4
.Packet
.Offer
;
726 // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
728 if (Offer
->Dhcp4
.Header
.ServerAddr
.Addr
[0] == 0) {
731 Private
->OfferBuffer
[Index
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
732 sizeof (EFI_IPv4_ADDRESS
)
737 &Offer
->Dhcp4
.Header
.ServerAddr
,
738 sizeof (EFI_IPv4_ADDRESS
)
742 Private
->IsDoDiscover
= FALSE
;
743 Cache4
= &Private
->ProxyOffer
.Dhcp4
;
744 Reply
= &Cache4
->Packet
.Offer
;
747 // Send another request packet for bootfile name.
749 Status
= PxeBcDhcp4Discover (
758 if (EFI_ERROR (Status
)) {
763 // Parse the reply for the last request packet.
765 Status
= PxeBcParseDhcp4Packet (Cache4
);
766 if (EFI_ERROR (Status
)) {
770 if ((Cache4
->OfferType
!= PxeOfferTypeProxyPxe10
) &&
771 (Cache4
->OfferType
!= PxeOfferTypeProxyWfm11a
) &&
772 (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))
775 // This BINL ack doesn't have discovery option set or multicast option set
776 // or bootfile name specified.
778 return EFI_DEVICE_ERROR
;
782 // Store the reply into mode data.
784 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
785 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
.Dhcpv4
, &Reply
->Dhcp4
, Reply
->Length
);
791 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
793 @param[in] Private Pointer to PxeBc private data.
794 @param[in] RcvdOffer Pointer to the received offer packet.
796 @retval EFI_SUCCESS Cache and parse the packet successfully.
797 @retval Others Operation failed.
801 PxeBcCacheDhcp4Offer (
802 IN PXEBC_PRIVATE_DATA
*Private
,
803 IN EFI_DHCP4_PACKET
*RcvdOffer
806 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
807 EFI_DHCP4_PACKET
*Offer
;
808 PXEBC_OFFER_TYPE OfferType
;
811 ASSERT (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
);
812 Cache4
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp4
;
813 Offer
= &Cache4
->Packet
.Offer
;
816 // Cache the content of DHCPv4 packet firstly.
818 Status
= PxeBcCacheDhcp4Packet (Offer
, RcvdOffer
);
819 if (EFI_ERROR (Status
)) {
824 // Validate the DHCPv4 packet, and parse the options and offer type.
826 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4
))) {
831 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
833 OfferType
= Cache4
->OfferType
;
834 ASSERT (OfferType
< PxeOfferTypeMax
);
836 if (OfferType
== PxeOfferTypeBootp
) {
838 // It's a Bootp offer, only cache the first one, and discard the others.
840 if (Private
->OfferCount
[OfferType
] == 0) {
841 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
842 Private
->OfferCount
[OfferType
] = 1;
847 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
848 if (IS_PROXY_DHCP_OFFER (Offer
)) {
850 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
852 Private
->IsProxyRecved
= TRUE
;
854 if (OfferType
== PxeOfferTypeProxyBinl
) {
856 // Cache all proxy BINL offers.
858 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
859 Private
->OfferCount
[OfferType
]++;
860 } else if (((OfferType
== PxeOfferTypeProxyPxe10
) || (OfferType
== PxeOfferTypeProxyWfm11a
)) &&
861 (Private
->OfferCount
[OfferType
] < 1))
864 // Only cache the first PXE10/WFM11a offer, and discard the others.
866 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
867 Private
->OfferCount
[OfferType
] = 1;
873 // It's a DHCPv4 offer with yiaddr, and cache them all.
875 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
876 Private
->OfferCount
[OfferType
]++;
886 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
888 @param[in] Private Pointer to PxeBc private data.
892 PxeBcSelectDhcp4Offer (
893 IN PXEBC_PRIVATE_DATA
*Private
898 EFI_DHCP4_PACKET
*Offer
;
900 Private
->SelectIndex
= 0;
902 if (Private
->IsOfferSorted
) {
904 // Select offer by default policy.
906 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
908 // 1. DhcpPxe10 offer
910 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
911 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
913 // 2. DhcpWfm11a offer
915 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
916 } else if ((Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0) &&
917 (Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0))
920 // 3. DhcpOnly offer and ProxyPxe10 offer.
922 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
923 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
924 } else if ((Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0) &&
925 (Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0))
928 // 4. DhcpOnly offer and ProxyWfm11a offer.
930 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
931 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
932 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
934 // 5. DhcpBinl offer.
936 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
937 } else if ((Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0) &&
938 (Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0))
941 // 6. DhcpOnly offer and ProxyBinl offer.
943 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
944 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
947 // 7. DhcpOnly offer with bootfilename.
949 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
950 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
951 if (Private
->OfferBuffer
[OfferIndex
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
952 Private
->SelectIndex
= OfferIndex
+ 1;
958 // 8. Bootp offer with bootfilename.
960 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeBootp
][0];
961 if ((Private
->SelectIndex
== 0) &&
962 (Private
->OfferCount
[PxeOfferTypeBootp
] > 0) &&
963 (Private
->OfferBuffer
[OfferIndex
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
))
965 Private
->SelectIndex
= OfferIndex
+ 1;
970 // Select offer by received order.
972 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
973 Offer
= &Private
->OfferBuffer
[Index
].Dhcp4
.Packet
.Offer
;
975 if (IS_PROXY_DHCP_OFFER (Offer
)) {
982 if (!Private
->IsProxyRecved
&&
983 (Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
== PxeOfferTypeDhcpOnly
) &&
984 (Private
->OfferBuffer
[Index
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
))
987 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
993 // Record the index of the select offer.
995 Private
->SelectIndex
= Index
+ 1;
1002 Handle the DHCPv4 offer packet.
1004 @param[in] Private Pointer to PxeBc private data.
1006 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.
1007 @retval EFI_NO_RESPONSE No response to the following request packet.
1008 @retval EFI_NOT_FOUND No boot filename received.
1009 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1013 PxeBcHandleDhcp4Offer (
1014 IN PXEBC_PRIVATE_DATA
*Private
1017 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
1018 EFI_DHCP4_PACKET_OPTION
**Options
;
1020 EFI_DHCP4_PACKET
*Offer
;
1021 PXEBC_OFFER_TYPE OfferType
;
1025 EFI_PXE_BASE_CODE_MODE
*Mode
;
1026 EFI_DHCP4_PACKET
*Ack
;
1028 ASSERT (Private
->SelectIndex
> 0);
1029 SelectIndex
= (UINT32
)(Private
->SelectIndex
- 1);
1030 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1031 Cache4
= &Private
->OfferBuffer
[SelectIndex
].Dhcp4
;
1032 Options
= Cache4
->OptList
;
1033 Status
= EFI_SUCCESS
;
1035 if (Cache4
->OfferType
== PxeOfferTypeDhcpBinl
) {
1037 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1039 if (EFI_ERROR (PxeBcRetryBinlOffer (Private
, SelectIndex
))) {
1040 Status
= EFI_NO_RESPONSE
;
1042 } else if (Cache4
->OfferType
== PxeOfferTypeDhcpOnly
) {
1043 if (Private
->IsProxyRecved
) {
1045 // DhcpOnly offer is selected, so need try to request bootfile name.
1048 if (Private
->IsOfferSorted
) {
1050 // The proxy offer should be determined if select by default policy.
1051 // IsOfferSorted means all offers are labeled by OfferIndex.
1053 ASSERT (Private
->SelectProxyType
< PxeOfferTypeMax
);
1054 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1056 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1058 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1060 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1061 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1062 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1063 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private
, ProxyIndex
))) {
1068 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1069 Status
= EFI_NO_RESPONSE
;
1073 // For other proxy offers, only one is buffered.
1075 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1079 // The proxy offer should not be determined if select by received order.
1081 Status
= EFI_NO_RESPONSE
;
1083 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1084 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1085 Offer
= &Private
->OfferBuffer
[Index
].Dhcp4
.Packet
.Offer
;
1086 OfferType
= Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
;
1087 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
1089 // Skip non proxy DHCPv4 offers.
1094 if (OfferType
== PxeOfferTypeProxyBinl
) {
1096 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1098 if (EFI_ERROR (PxeBcRetryBinlOffer (Private
, Index
))) {
1103 Private
->SelectProxyType
= OfferType
;
1105 Status
= EFI_SUCCESS
;
1110 if (!EFI_ERROR (Status
) && (Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
)) {
1112 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1114 Status
= PxeBcCopyProxyOffer (Private
, ProxyIndex
);
1118 // Otherwise, the bootfile name must be included in DhcpOnly offer.
1120 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) {
1121 Status
= EFI_NOT_FOUND
;
1126 if (!EFI_ERROR (Status
)) {
1128 // All PXE boot information is ready by now.
1130 Mode
= Private
->PxeBc
.Mode
;
1131 Offer
= &Cache4
->Packet
.Offer
;
1132 Ack
= &Private
->DhcpAck
.Dhcp4
.Packet
.Ack
;
1133 if (Cache4
->OfferType
== PxeOfferTypeBootp
) {
1135 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
1136 // should be taken as ack.
1141 Status
= PxeBcCopyDhcp4Ack (Private
, Ack
, TRUE
);
1142 if (EFI_ERROR (Status
)) {
1146 Mode
->DhcpDiscoverValid
= TRUE
;
1153 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
1154 to intercept events that occurred in the configuration process.
1156 @param[in] This Pointer to the EFI DHCPv4 Protocol.
1157 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
1158 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
1159 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
1161 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
1162 @param[out] NewPacket The packet that is used to replace the above Packet.
1164 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
1165 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
1166 driver will continue to wait for more DHCPOFFER packets until the
1167 retry timeout expires.
1168 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
1169 and return to the Dhcp4Init or Dhcp4InitReboot state.
1174 PxeBcDhcp4CallBack (
1175 IN EFI_DHCP4_PROTOCOL
*This
,
1177 IN EFI_DHCP4_STATE CurrentState
,
1178 IN EFI_DHCP4_EVENT Dhcp4Event
,
1179 IN EFI_DHCP4_PACKET
*Packet OPTIONAL
,
1180 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
1183 PXEBC_PRIVATE_DATA
*Private
;
1184 EFI_PXE_BASE_CODE_MODE
*Mode
;
1185 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1186 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
1191 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
1192 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
1193 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
1194 (Dhcp4Event
!= Dhcp4RcvdAck
))
1199 ASSERT (Packet
!= NULL
);
1201 Private
= (PXEBC_PRIVATE_DATA
*)Context
;
1202 Mode
= Private
->PxeBc
.Mode
;
1203 Callback
= Private
->PxeBcCallback
;
1206 // Override the Maximum DHCP Message Size.
1208 MaxMsgSize
= PxeBcParseDhcp4Options (
1209 Packet
->Dhcp4
.Option
,
1210 GET_OPTION_BUFFER_LEN (Packet
),
1213 if (MaxMsgSize
!= NULL
) {
1214 Value
= HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE
);
1215 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
1219 // Callback to user if any packets sent or received.
1221 if ((Dhcp4Event
!= Dhcp4SelectOffer
) && (Callback
!= NULL
)) {
1222 Received
= (BOOLEAN
)(Dhcp4Event
== Dhcp4RcvdOffer
|| Dhcp4Event
== Dhcp4RcvdAck
);
1223 Status
= Callback
->Callback (
1228 (EFI_PXE_BASE_CODE_PACKET
*)&Packet
->Dhcp4
1230 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1235 Status
= EFI_SUCCESS
;
1237 switch (Dhcp4Event
) {
1238 case Dhcp4SendDiscover
:
1239 if (Packet
->Length
> PXEBC_DHCP4_PACKET_MAX_SIZE
) {
1241 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1243 Status
= EFI_ABORTED
;
1248 // Cache the DHCPv4 discover packet to mode data directly.
1249 // It need to check SendGuid as well as Dhcp4SendRequest.
1251 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp4
, Packet
->Length
);
1253 case Dhcp4SendRequest
:
1254 if (Packet
->Length
> PXEBC_DHCP4_PACKET_MAX_SIZE
) {
1256 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1258 Status
= EFI_ABORTED
;
1262 if (Mode
->SendGUID
) {
1264 // Send the system Guid instead of the MAC address as the hardware address if required.
1266 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*)Packet
->Dhcp4
.Header
.ClientHwAddr
))) {
1268 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
1270 DEBUG ((DEBUG_WARN
, "PXE: Failed to read system GUID from the smbios table!\n"));
1271 ZeroMem (Packet
->Dhcp4
.Header
.ClientHwAddr
, sizeof (EFI_GUID
));
1274 Packet
->Dhcp4
.Header
.HwAddrLen
= (UINT8
)sizeof (EFI_GUID
);
1279 case Dhcp4RcvdOffer
:
1280 Status
= EFI_NOT_READY
;
1281 if (Packet
->Length
> PXEBC_DHCP4_PACKET_MAX_SIZE
) {
1283 // Ignore the incoming packets which exceed the maximum length.
1288 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1290 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
1291 // the OfferIndex and OfferCount.
1292 // If error happens, just ignore this packet and continue to wait more offer.
1294 PxeBcCacheDhcp4Offer (Private
, Packet
);
1299 case Dhcp4SelectOffer
:
1300 ASSERT (NewPacket
!= NULL
);
1303 // Select offer by the default policy or by order, and record the SelectIndex
1304 // and SelectProxyType.
1306 PxeBcSelectDhcp4Offer (Private
);
1308 if (Private
->SelectIndex
== 0) {
1309 Status
= EFI_ABORTED
;
1311 *NewPacket
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp4
.Packet
.Offer
;
1318 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
1319 // without verification.
1321 ASSERT (Private
->SelectIndex
!= 0);
1323 Status
= PxeBcCopyDhcp4Ack (Private
, Packet
, FALSE
);
1324 if (EFI_ERROR (Status
)) {
1325 Status
= EFI_ABORTED
;
1338 Build and send out the request packet for the bootfile, and parse the reply.
1340 @param[in] Private Pointer to PxeBc private data.
1341 @param[in] Type PxeBc option boot item type.
1342 @param[in] Layer Pointer to option boot item layer.
1343 @param[in] UseBis Use BIS or not.
1344 @param[in] DestIp Pointer to the server address.
1345 @param[in] IpCount The total count of the server address.
1346 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
1348 @retval EFI_SUCCESS Successfully discovered boot file.
1349 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
1350 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1351 @retval Others Failed to discover boot file.
1355 PxeBcDhcp4Discover (
1356 IN PXEBC_PRIVATE_DATA
*Private
,
1360 IN EFI_IP_ADDRESS
*DestIp
,
1362 IN EFI_PXE_BASE_CODE_SRVLIST
*SrvList
1365 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1366 EFI_PXE_BASE_CODE_MODE
*Mode
;
1367 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1368 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1374 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1375 EFI_DHCP4_PACKET
*Response
;
1376 UINT8 Buffer
[PXEBC_DHCP4_OPTION_MAX_SIZE
];
1377 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_OPTION_MAX_NUM
];
1379 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1380 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1384 Mode
= Private
->PxeBc
.Mode
;
1385 Dhcp4
= Private
->Dhcp4
;
1386 Status
= EFI_SUCCESS
;
1388 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1391 // Use broadcast if destination address not specified.
1393 if (DestIp
== NULL
) {
1394 Sport
= PXEBC_DHCP4_S_PORT
;
1397 Sport
= PXEBC_BS_DISCOVER_PORT
;
1401 if (!UseBis
&& (Layer
!= NULL
)) {
1402 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1406 // Build all the options for the request packet.
1408 OptCount
= PxeBcBuildDhcp4Options (Private
, OptList
, Buffer
, TRUE
);
1410 if (Private
->IsDoDiscover
) {
1412 // Add vendor option of PXE_BOOT_ITEM
1414 VendorOptLen
= (UINT8
)((sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1);
1415 OptList
[OptCount
] = AllocateZeroPool (VendorOptLen
);
1416 if (OptList
[OptCount
] == NULL
) {
1417 return EFI_OUT_OF_RESOURCES
;
1420 OptList
[OptCount
]->OpCode
= DHCP4_TAG_VENDOR
;
1421 OptList
[OptCount
]->Length
= (UINT8
)(VendorOptLen
- 2);
1422 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*)OptList
[OptCount
]->Data
;
1423 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1424 PxeOpt
->Length
= (UINT8
)sizeof (PXEBC_OPTION_BOOT_ITEM
);
1425 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*)PxeOpt
->Data
;
1426 PxeBootItem
->Type
= HTONS (Type
);
1427 PxeOpt
->Data
[PxeOpt
->Length
] = DHCP4_TAG_EOP
;
1429 if (Layer
!= NULL
) {
1430 PxeBootItem
->Layer
= HTONS (*Layer
);
1437 // Build the request packet with seed packet and option list.
1439 Status
= Dhcp4
->Build (
1441 &Private
->SeedPacket
,
1449 // Free the vendor option of PXE_BOOT_ITEM.
1451 if (Private
->IsDoDiscover
) {
1452 FreePool (OptList
[OptCount
- 1]);
1455 if (EFI_ERROR (Status
)) {
1459 if (Mode
->SendGUID
) {
1460 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*)Token
.Packet
->Dhcp4
.Header
.ClientHwAddr
))) {
1462 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
1464 DEBUG ((DEBUG_WARN
, "PXE: Failed to read system GUID from the smbios table!\n"));
1465 ZeroMem (Token
.Packet
->Dhcp4
.Header
.ClientHwAddr
, sizeof (EFI_GUID
));
1468 Token
.Packet
->Dhcp4
.Header
.HwAddrLen
= (UINT8
)sizeof (EFI_GUID
);
1472 // Set fields of the token for the request packet.
1474 Xid
= NET_RANDOM (NetRandomInitSeed ());
1475 Token
.Packet
->Dhcp4
.Header
.Xid
= HTONL (Xid
);
1476 Token
.Packet
->Dhcp4
.Header
.Reserved
= HTONS ((UINT16
)((IsBCast
) ? 0x8000 : 0x0));
1477 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1479 Token
.RemotePort
= Sport
;
1482 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1484 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1487 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1490 Token
.ListenPointCount
= 1;
1491 Token
.ListenPoints
= &ListenPoint
;
1492 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1493 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1494 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1498 // Send out the request packet to discover the bootfile.
1500 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1501 Token
.TimeoutValue
= (UINT16
)(PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
);
1502 Token
.Packet
->Dhcp4
.Header
.Seconds
= (UINT16
)(PXEBC_BOOT_REQUEST_TIMEOUT
* (TryIndex
- 1));
1504 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1505 if (Token
.Status
!= EFI_TIMEOUT
) {
1510 if (TryIndex
> PXEBC_BOOT_REQUEST_RETRIES
) {
1512 // No server response our PXE request
1514 Status
= EFI_TIMEOUT
;
1517 if (!EFI_ERROR (Status
)) {
1520 Response
= Token
.ResponseList
;
1522 // Find the right PXE Reply according to server address.
1524 while (RepIndex
< Token
.ResponseCount
) {
1525 if (Response
->Length
> PXEBC_DHCP4_PACKET_MAX_SIZE
) {
1528 Response
= (EFI_DHCP4_PACKET
*)((UINT8
*)Response
+ Response
->Size
);
1532 while (SrvIndex
< IpCount
) {
1533 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1537 if ((SrvList
[SrvIndex
].Type
== Type
) &&
1538 EFI_IP4_EQUAL (&Response
->Dhcp4
.Header
.ServerAddr
, &SrvList
[SrvIndex
].IpAddr
))
1546 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1552 Response
= (EFI_DHCP4_PACKET
*)((UINT8
*)Response
+ Response
->Size
);
1555 if (RepIndex
< Token
.ResponseCount
) {
1557 // Cache the right PXE reply packet here, set valid flag later.
1558 // Especially for PXE discover packet, store it into mode data here.
1560 if (Private
->IsDoDiscover
) {
1561 Status
= PxeBcCacheDhcp4Packet (&Private
->PxeReply
.Dhcp4
.Packet
.Ack
, Response
);
1562 if (EFI_ERROR (Status
)) {
1566 CopyMem (&Mode
->PxeDiscover
, &Token
.Packet
->Dhcp4
, Token
.Packet
->Length
);
1568 Status
= PxeBcCacheDhcp4Packet (&Private
->ProxyOffer
.Dhcp4
.Packet
.Offer
, Response
);
1569 if (EFI_ERROR (Status
)) {
1575 // Not found the right PXE reply packet.
1577 Status
= EFI_NOT_FOUND
;
1583 if (Token
.ResponseList
!= NULL
) {
1584 FreePool (Token
.ResponseList
);
1587 if (Token
.Packet
!= NULL
) {
1588 FreePool (Token
.Packet
);
1595 Switch the Ip4 policy to static.
1597 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1599 @retval EFI_SUCCESS The policy is already configured to static.
1600 @retval Others Other error as indicated..
1605 IN PXEBC_PRIVATE_DATA
*Private
1609 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
1610 EFI_IP4_CONFIG2_POLICY Policy
;
1613 Ip4Config2
= Private
->Ip4Config2
;
1614 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
1615 Status
= Ip4Config2
->GetData (
1617 Ip4Config2DataTypePolicy
,
1621 if (EFI_ERROR (Status
)) {
1625 if (Policy
!= Ip4Config2PolicyStatic
) {
1626 Policy
= Ip4Config2PolicyStatic
;
1627 Status
= Ip4Config2
->SetData (
1629 Ip4Config2DataTypePolicy
,
1630 sizeof (EFI_IP4_CONFIG2_POLICY
),
1633 if (EFI_ERROR (Status
)) {
1642 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1644 @param[in] Private Pointer to PxeBc private data.
1645 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL
1647 @retval EFI_SUCCESS The D.O.R.A process successfully finished.
1648 @retval Others Failed to finish the D.O.R.A process.
1653 IN PXEBC_PRIVATE_DATA
*Private
,
1654 IN EFI_DHCP4_PROTOCOL
*Dhcp4
1657 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1658 EFI_DHCP4_CONFIG_DATA Config
;
1659 EFI_DHCP4_MODE_DATA Mode
;
1660 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_OPTION_MAX_NUM
];
1661 UINT8 Buffer
[PXEBC_DHCP4_OPTION_MAX_SIZE
];
1665 ASSERT (Dhcp4
!= NULL
);
1667 Status
= EFI_SUCCESS
;
1668 PxeMode
= Private
->PxeBc
.Mode
;
1671 // Build option list for the request packet.
1673 OptCount
= PxeBcBuildDhcp4Options (Private
, OptList
, Buffer
, FALSE
);
1674 ASSERT (OptCount
> 0);
1676 ZeroMem (&Mode
, sizeof (EFI_DHCP4_MODE_DATA
));
1677 ZeroMem (&Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
1679 Config
.OptionCount
= OptCount
;
1680 Config
.OptionList
= OptList
;
1681 Config
.Dhcp4Callback
= PxeBcDhcp4CallBack
;
1682 Config
.CallbackContext
= Private
;
1683 Config
.DiscoverTryCount
= PXEBC_DHCP_RETRIES
;
1684 Config
.DiscoverTimeout
= mPxeDhcpTimeout
;
1687 // Configure the DHCPv4 instance for PXE boot.
1689 Status
= Dhcp4
->Configure (Dhcp4
, &Config
);
1690 if (EFI_ERROR (Status
)) {
1695 // Initialize the record fields for DHCPv4 offer in private data.
1697 Private
->IsProxyRecved
= FALSE
;
1698 Private
->OfferNum
= 0;
1699 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1700 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1702 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
1703 if (EFI_ERROR (Status
)) {
1704 if (Status
== EFI_ICMP_ERROR
) {
1705 PxeMode
->IcmpErrorReceived
= TRUE
;
1708 if ((Status
== EFI_TIMEOUT
) && (Private
->OfferNum
> 0)) {
1709 Status
= EFI_NO_RESPONSE
;
1716 // Get the acquired IPv4 address and store them.
1718 Status
= Dhcp4
->GetModeData (Dhcp4
, &Mode
);
1719 if (EFI_ERROR (Status
)) {
1723 ASSERT (Mode
.State
== Dhcp4Bound
);
1725 CopyMem (&Private
->StationIp
, &Mode
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
1726 CopyMem (&Private
->SubnetMask
, &Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1727 CopyMem (&Private
->GatewayIp
, &Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
1728 CopyMem (&PxeMode
->StationIp
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1729 CopyMem (&PxeMode
->SubnetMask
, &Private
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1731 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, &Private
->SubnetMask
);
1732 if (EFI_ERROR (Status
)) {
1737 // Check the selected offer whether BINL retry is needed.
1739 Status
= PxeBcHandleDhcp4Offer (Private
);
1741 AsciiPrint ("\n Station IP address is ");
1743 PxeBcShowIp4Addr (&Private
->StationIp
.v4
);
1747 if (EFI_ERROR (Status
)) {
1748 Dhcp4
->Stop (Dhcp4
);
1749 Dhcp4
->Configure (Dhcp4
, NULL
);
1751 ZeroMem (&Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
1752 Dhcp4
->Configure (Dhcp4
, &Config
);
1753 Private
->IsAddressOk
= TRUE
;