2 Functions implementation related with DHCPv4 for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PxeBcImpl.h"
19 // This is a map from the interested DHCP4 option tags' index to the tag value.
21 UINT8 mInterestedDhcp4Tags
[PXEBC_DHCP4_TAG_INDEX_MAX
] = {
22 PXEBC_DHCP4_TAG_BOOTFILE_LEN
,
23 PXEBC_DHCP4_TAG_VENDOR
,
24 PXEBC_DHCP4_TAG_OVERLOAD
,
25 PXEBC_DHCP4_TAG_MSG_TYPE
,
26 PXEBC_DHCP4_TAG_SERVER_ID
,
27 PXEBC_DHCP4_TAG_CLASS_ID
,
28 PXEBC_DHCP4_TAG_BOOTFILE
32 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
34 UINT32 mPxeDhcpTimeout
[4] = {4, 8, 16, 32};
38 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
40 @param[in] Buffer Pointer to the option buffer.
41 @param[in] Length Length of the option buffer.
42 @param[in] OptTag Tag of the required option.
44 @retval NULL Failed to find the required option.
45 @retval Others The position of the required option.
48 EFI_DHCP4_PACKET_OPTION
*
49 PxeBcParseDhcp4Options (
55 EFI_DHCP4_PACKET_OPTION
*Option
;
58 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
61 while (Offset
< Length
&& Option
->OpCode
!= PXEBC_DHCP4_TAG_EOP
) {
63 if (Option
->OpCode
== OptTag
) {
65 // Found the required option.
71 // Skip the current option to the next.
73 if (Option
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
76 Offset
+= Option
->Length
+ 2;
79 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
87 Parse the PXE vender options and extract the information from them.
89 @param[in] Dhcp4Option Pointer to vendor options in buffer.
90 @param[in] VendorOption Pointer to structure to store information in vendor options.
94 PxeBcParseVendorOptions (
95 IN EFI_DHCP4_PACKET_OPTION
*Dhcp4Option
,
96 IN PXEBC_VENDOR_OPTION
*VendorOption
100 UINT8 VendorOptionLen
;
101 EFI_DHCP4_PACKET_OPTION
*PxeOption
;
104 BitMap
= VendorOption
->BitMap
;
105 VendorOptionLen
= Dhcp4Option
->Length
;
106 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) &Dhcp4Option
->Data
[0];
109 ASSERT (PxeOption
!= NULL
);
111 while ((Offset
< VendorOptionLen
) && (PxeOption
->OpCode
!= PXEBC_DHCP4_TAG_EOP
)) {
113 // Parse all the interesting PXE vendor options one by one.
115 switch (PxeOption
->OpCode
) {
117 case PXEBC_VENDOR_TAG_MTFTP_IP
:
119 CopyMem (&VendorOption
->MtftpIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
122 case PXEBC_VENDOR_TAG_MTFTP_CPORT
:
124 CopyMem (&VendorOption
->MtftpCPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpCPort
));
127 case PXEBC_VENDOR_TAG_MTFTP_SPORT
:
129 CopyMem (&VendorOption
->MtftpSPort
, PxeOption
->Data
, sizeof (VendorOption
->MtftpSPort
));
132 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT
:
134 VendorOption
->MtftpTimeout
= *PxeOption
->Data
;
137 case PXEBC_VENDOR_TAG_MTFTP_DELAY
:
139 VendorOption
->MtftpDelay
= *PxeOption
->Data
;
142 case PXEBC_VENDOR_TAG_DISCOVER_CTRL
:
144 VendorOption
->DiscoverCtrl
= *PxeOption
->Data
;
147 case PXEBC_VENDOR_TAG_DISCOVER_MCAST
:
149 CopyMem (&VendorOption
->DiscoverMcastIp
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
152 case PXEBC_VENDOR_TAG_BOOT_SERVERS
:
154 VendorOption
->BootSvrLen
= PxeOption
->Length
;
155 VendorOption
->BootSvr
= (PXEBC_BOOT_SVR_ENTRY
*) PxeOption
->Data
;
158 case PXEBC_VENDOR_TAG_BOOT_MENU
:
160 VendorOption
->BootMenuLen
= PxeOption
->Length
;
161 VendorOption
->BootMenu
= (PXEBC_BOOT_MENU_ENTRY
*) PxeOption
->Data
;
164 case PXEBC_VENDOR_TAG_MENU_PROMPT
:
166 VendorOption
->MenuPromptLen
= PxeOption
->Length
;
167 VendorOption
->MenuPrompt
= (PXEBC_MENU_PROMPT
*) PxeOption
->Data
;
170 case PXEBC_VENDOR_TAG_MCAST_ALLOC
:
172 CopyMem (&VendorOption
->McastIpBase
, PxeOption
->Data
, sizeof (EFI_IPv4_ADDRESS
));
173 CopyMem (&VendorOption
->McastIpBlock
, PxeOption
->Data
+ 4, sizeof (VendorOption
->McastIpBlock
));
174 CopyMem (&VendorOption
->McastIpRange
, PxeOption
->Data
+ 6, sizeof (VendorOption
->McastIpRange
));
177 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES
:
179 VendorOption
->CredTypeLen
= PxeOption
->Length
;
180 VendorOption
->CredType
= (UINT32
*) PxeOption
->Data
;
183 case PXEBC_VENDOR_TAG_BOOT_ITEM
:
185 CopyMem (&VendorOption
->BootSrvType
, PxeOption
->Data
, sizeof (VendorOption
->BootSrvType
));
186 CopyMem (&VendorOption
->BootSrvLayer
, PxeOption
->Data
+ 2, sizeof (VendorOption
->BootSrvLayer
));
191 // Not interesting PXE vendor options.
197 // Set the bit map for the special PXE options.
199 SET_VENDOR_OPTION_BIT_MAP (BitMap
, PxeOption
->OpCode
);
202 // Continue to the next option.
204 if (PxeOption
->OpCode
== PXEBC_DHCP4_TAG_PAD
) {
207 Offset
= (UINT8
) (Offset
+ PxeOption
->Length
+ 2);
210 PxeOption
= (EFI_DHCP4_PACKET_OPTION
*) (Dhcp4Option
->Data
+ Offset
);
216 Build the options buffer for the DHCPv4 request packet.
218 @param[in] Private Pointer to PxeBc private data.
219 @param[out] OptList Pointer to the option pointer array.
220 @param[in] Buffer Pointer to the buffer to contain the option list.
221 @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.
222 Otherwise, it is not necessary.
224 @return Index The count of the built-in options.
228 PxeBcBuildDhcp4Options (
229 IN PXEBC_PRIVATE_DATA
*Private
,
230 OUT EFI_DHCP4_PACKET_OPTION
**OptList
,
232 IN BOOLEAN NeedMsgType
236 PXEBC_DHCP4_OPTION_ENTRY OptEnt
;
240 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
244 // Append message type.
246 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MSG_TYPE
;
247 OptList
[Index
]->Length
= 1;
248 OptEnt
.Mesg
= (PXEBC_DHCP4_OPTION_MESG
*) OptList
[Index
]->Data
;
249 OptEnt
.Mesg
->Type
= PXEBC_DHCP4_MSG_TYPE_REQUEST
;
251 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
254 // Append max message size.
256 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_MAXMSG
;
257 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
);
258 OptEnt
.MaxMesgSize
= (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE
*) OptList
[Index
]->Data
;
259 Value
= NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE
- 8);
260 CopyMem (&OptEnt
.MaxMesgSize
->Size
, &Value
, sizeof (UINT16
));
262 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
266 // Append parameter request list option.
268 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_PARA_LIST
;
269 OptList
[Index
]->Length
= 35;
270 OptEnt
.Para
= (PXEBC_DHCP4_OPTION_PARA
*) OptList
[Index
]->Data
;
271 OptEnt
.Para
->ParaList
[0] = PXEBC_DHCP4_TAG_NETMASK
;
272 OptEnt
.Para
->ParaList
[1] = PXEBC_DHCP4_TAG_TIME_OFFSET
;
273 OptEnt
.Para
->ParaList
[2] = PXEBC_DHCP4_TAG_ROUTER
;
274 OptEnt
.Para
->ParaList
[3] = PXEBC_DHCP4_TAG_TIME_SERVER
;
275 OptEnt
.Para
->ParaList
[4] = PXEBC_DHCP4_TAG_NAME_SERVER
;
276 OptEnt
.Para
->ParaList
[5] = PXEBC_DHCP4_TAG_DNS_SERVER
;
277 OptEnt
.Para
->ParaList
[6] = PXEBC_DHCP4_TAG_HOSTNAME
;
278 OptEnt
.Para
->ParaList
[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN
;
279 OptEnt
.Para
->ParaList
[8] = PXEBC_DHCP4_TAG_DOMAINNAME
;
280 OptEnt
.Para
->ParaList
[9] = PXEBC_DHCP4_TAG_ROOTPATH
;
281 OptEnt
.Para
->ParaList
[10] = PXEBC_DHCP4_TAG_EXTEND_PATH
;
282 OptEnt
.Para
->ParaList
[11] = PXEBC_DHCP4_TAG_EMTU
;
283 OptEnt
.Para
->ParaList
[12] = PXEBC_DHCP4_TAG_TTL
;
284 OptEnt
.Para
->ParaList
[13] = PXEBC_DHCP4_TAG_BROADCAST
;
285 OptEnt
.Para
->ParaList
[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN
;
286 OptEnt
.Para
->ParaList
[15] = PXEBC_DHCP4_TAG_NIS_SERVER
;
287 OptEnt
.Para
->ParaList
[16] = PXEBC_DHCP4_TAG_NTP_SERVER
;
288 OptEnt
.Para
->ParaList
[17] = PXEBC_DHCP4_TAG_VENDOR
;
289 OptEnt
.Para
->ParaList
[18] = PXEBC_DHCP4_TAG_REQUEST_IP
;
290 OptEnt
.Para
->ParaList
[19] = PXEBC_DHCP4_TAG_LEASE
;
291 OptEnt
.Para
->ParaList
[20] = PXEBC_DHCP4_TAG_SERVER_ID
;
292 OptEnt
.Para
->ParaList
[21] = PXEBC_DHCP4_TAG_T1
;
293 OptEnt
.Para
->ParaList
[22] = PXEBC_DHCP4_TAG_T2
;
294 OptEnt
.Para
->ParaList
[23] = PXEBC_DHCP4_TAG_CLASS_ID
;
295 OptEnt
.Para
->ParaList
[24] = PXEBC_DHCP4_TAG_TFTP
;
296 OptEnt
.Para
->ParaList
[25] = PXEBC_DHCP4_TAG_BOOTFILE
;
297 OptEnt
.Para
->ParaList
[26] = PXEBC_PXE_DHCP4_TAG_UUID
;
298 OptEnt
.Para
->ParaList
[27] = 0x80;
299 OptEnt
.Para
->ParaList
[28] = 0x81;
300 OptEnt
.Para
->ParaList
[29] = 0x82;
301 OptEnt
.Para
->ParaList
[30] = 0x83;
302 OptEnt
.Para
->ParaList
[31] = 0x84;
303 OptEnt
.Para
->ParaList
[32] = 0x85;
304 OptEnt
.Para
->ParaList
[33] = 0x86;
305 OptEnt
.Para
->ParaList
[34] = 0x87;
307 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
310 // Append UUID/Guid-based client identifier option
312 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UUID
;
313 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UUID
);
314 OptEnt
.Uuid
= (PXEBC_DHCP4_OPTION_UUID
*) OptList
[Index
]->Data
;
315 OptEnt
.Uuid
->Type
= 0;
317 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
319 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) OptEnt
.Uuid
->Guid
))) {
321 // Zero the Guid to indicate NOT programable if failed to get system Guid.
323 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
327 // Append client network device interface option
329 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_UNDI
;
330 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_UNDI
);
331 OptEnt
.Undi
= (PXEBC_DHCP4_OPTION_UNDI
*) OptList
[Index
]->Data
;
333 if (Private
->Nii
!= NULL
) {
334 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
335 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
336 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
338 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
339 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
340 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
344 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
347 // Append client system architecture option
349 OptList
[Index
]->OpCode
= PXEBC_PXE_DHCP4_TAG_ARCH
;
350 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_ARCH
);
351 OptEnt
.Arch
= (PXEBC_DHCP4_OPTION_ARCH
*) OptList
[Index
]->Data
;
352 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
353 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
355 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
358 // Append vendor class identify option
360 OptList
[Index
]->OpCode
= PXEBC_DHCP4_TAG_CLASS_ID
;
361 OptList
[Index
]->Length
= (UINT8
) sizeof (PXEBC_DHCP4_OPTION_CLID
);
362 OptEnt
.Clid
= (PXEBC_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
365 DEFAULT_CLASS_ID_DATA
,
366 sizeof (PXEBC_DHCP4_OPTION_CLID
)
368 PxeBcUintnToAscDecWithFormat (
369 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
370 OptEnt
.Clid
->ArchitectureType
,
371 sizeof (OptEnt
.Clid
->ArchitectureType
)
374 if (Private
->Nii
!= NULL
) {
375 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
376 PxeBcUintnToAscDecWithFormat (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
377 PxeBcUintnToAscDecWithFormat (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
387 Create a template DHCPv4 packet as a seed.
389 @param[out] Seed Pointer to the seed packet.
390 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.
394 PxeBcSeedDhcp4Packet (
395 OUT EFI_DHCP4_PACKET
*Seed
,
396 IN EFI_UDP4_PROTOCOL
*Udp4
399 EFI_SIMPLE_NETWORK_MODE Mode
;
400 EFI_DHCP4_HEADER
*Header
;
403 // Get IfType and HwAddressSize from SNP mode data.
405 Udp4
->GetModeData (Udp4
, NULL
, NULL
, NULL
, &Mode
);
407 Seed
->Size
= sizeof (EFI_DHCP4_PACKET
);
408 Seed
->Length
= sizeof (Seed
->Dhcp4
);
409 Header
= &Seed
->Dhcp4
.Header
;
410 ZeroMem (Header
, sizeof (EFI_DHCP4_HEADER
));
411 Header
->OpCode
= PXEBC_DHCP4_OPCODE_REQUEST
;
412 Header
->HwType
= Mode
.IfType
;
413 Header
->HwAddrLen
= (UINT8
) Mode
.HwAddressSize
;
414 CopyMem (Header
->ClientHwAddr
, &Mode
.CurrentAddress
, Header
->HwAddrLen
);
416 Seed
->Dhcp4
.Magik
= PXEBC_DHCP4_MAGIC
;
417 Seed
->Dhcp4
.Option
[0] = PXEBC_DHCP4_TAG_EOP
;
422 Cache the DHCPv4 packet.
424 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
425 @param[in] Src Pointer to the DHCPv4 packet to be cached.
429 PxeBcCacheDhcp4Packet (
430 IN EFI_DHCP4_PACKET
*Dst
,
431 IN EFI_DHCP4_PACKET
*Src
434 ASSERT (Dst
->Size
>= Src
->Length
);
436 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
437 Dst
->Length
= Src
->Length
;
442 Parse the cached DHCPv4 packet, including all the options.
444 @param[in] Cache4 Pointer to cached DHCPv4 packet.
446 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
447 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.
451 PxeBcParseDhcp4Packet (
452 IN PXEBC_DHCP4_PACKET_CACHE
*Cache4
455 EFI_DHCP4_PACKET
*Offer
;
456 EFI_DHCP4_PACKET_OPTION
**Options
;
457 EFI_DHCP4_PACKET_OPTION
*Option
;
458 PXEBC_OFFER_TYPE OfferType
;
460 BOOLEAN IsProxyOffer
;
464 IsProxyOffer
= FALSE
;
467 ZeroMem (Cache4
->OptList
, sizeof (Cache4
->OptList
));
468 ZeroMem (&Cache4
->VendorOpt
, sizeof (Cache4
->VendorOpt
));
470 Offer
= &Cache4
->Packet
.Offer
;
471 Options
= Cache4
->OptList
;
474 // Parse DHCPv4 options in this offer, and store the pointers.
476 for (Index
= 0; Index
< PXEBC_DHCP4_TAG_INDEX_MAX
; Index
++) {
477 Options
[Index
] = PxeBcParseDhcp4Options (
479 GET_OPTION_BUFFER_LEN (Offer
),
480 mInterestedDhcp4Tags
[Index
]
485 // The offer with "yiaddr" is a proxy offer.
487 if (Offer
->Dhcp4
.Header
.YourAddr
.Addr
[0] == 0) {
492 // The offer with "PXEClient" is a PXE offer.
494 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_CLASS_ID
];
495 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
496 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
501 // Parse PXE vendor options in this offer, and store the contents/pointers.
503 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_VENDOR
];
504 if (IsPxeOffer
&& Option
!= NULL
) {
505 PxeBcParseVendorOptions (Option
, &Cache4
->VendorOpt
);
509 // Check whether bootfilename and serverhostname overloaded, refers to rfc-2132 in details.
510 // If overloaded, parse the buffer as nested DHCPv4 options, or else just parse as bootfilename
511 // and serverhostname option.
513 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_OVERLOAD
];
514 if (Option
!= NULL
&& (Option
->Data
[0] & PXEBC_DHCP4_OVERLOAD_FILE
) != 0) {
516 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = PxeBcParseDhcp4Options (
517 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
518 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
519 PXEBC_DHCP4_TAG_BOOTFILE
522 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
523 // terminated string. So force to append null terminated character at the end of string.
525 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
526 Ptr8
= (UINT8
*)&Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
527 Ptr8
+= Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
531 } else if ((Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) &&
532 (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
534 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
535 // Do not count dhcp option header here, or else will destroy the serverhostname.
537 Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*)
538 (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
539 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
544 // Determine offer type of the DHCPv4 packet.
546 Option
= Options
[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE
];
547 if (Option
== NULL
|| Option
->Data
[0] == 0) {
549 // It's a Bootp offer.
551 OfferType
= PxeOfferTypeBootp
;
553 Option
= Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
];
554 if (Option
== NULL
) {
556 // If the Bootp offer without bootfilename, discard it.
558 return EFI_DEVICE_ERROR
;
562 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4
->VendorOpt
.BitMap
)) {
564 // It's a PXE10 offer with PXEClient and discover vendor option.
566 OfferType
= IsProxyOffer
? PxeOfferTypeProxyPxe10
: PxeOfferTypeDhcpPxe10
;
567 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4
->VendorOpt
.BitMap
)) {
569 // It's a WFM11a offer with PXEClient and mtftp vendor option.
570 // But multi-cast download is not supported currently, so discard it.
572 return EFI_DEVICE_ERROR
;
573 } else if (IsPxeOffer
) {
575 // It's a BINL offer only with PXEClient.
577 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
580 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
582 OfferType
= PxeOfferTypeDhcpOnly
;
586 Cache4
->OfferType
= OfferType
;
593 Cache the DHCPv4 ack packet, and parse it on demand.
595 @param[in] Private Pointer to PxeBc private data.
596 @param[in] Ack Pointer to the DHCPv4 ack packet.
597 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
602 IN PXEBC_PRIVATE_DATA
*Private
,
603 IN EFI_DHCP4_PACKET
*Ack
,
607 EFI_PXE_BASE_CODE_MODE
*Mode
;
609 Mode
= Private
->PxeBc
.Mode
;
611 PxeBcCacheDhcp4Packet (&Private
->DhcpAck
.Dhcp4
.Packet
.Ack
, Ack
);
615 // Parse the ack packet and store it into mode data if needed.
617 PxeBcParseDhcp4Packet (&Private
->DhcpAck
.Dhcp4
);
618 CopyMem (&Mode
->DhcpAck
.Dhcpv4
, &Ack
->Dhcp4
, Ack
->Length
);
619 Mode
->DhcpAckReceived
= TRUE
;
625 Cache the DHCPv4 proxy offer packet according to the received order.
627 @param[in] Private Pointer to PxeBc private data.
628 @param[in] OfferIndex The received order of offer packets.
632 PxeBcCopyProxyOffer (
633 IN PXEBC_PRIVATE_DATA
*Private
,
637 EFI_PXE_BASE_CODE_MODE
*Mode
;
638 EFI_DHCP4_PACKET
*Offer
;
640 ASSERT (OfferIndex
< Private
->OfferNum
);
641 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
643 Mode
= Private
->PxeBc
.Mode
;
644 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp4
.Packet
.Offer
;
647 // Cache the proxy offer packet and parse it.
649 PxeBcCacheDhcp4Packet (&Private
->ProxyOffer
.Dhcp4
.Packet
.Offer
, Offer
);
650 PxeBcParseDhcp4Packet (&Private
->ProxyOffer
.Dhcp4
);
653 // Store this packet into mode data.
655 CopyMem (&Mode
->ProxyOffer
.Dhcpv4
, &Offer
->Dhcp4
, Offer
->Length
);
656 Mode
->ProxyOfferReceived
= TRUE
;
661 Retry to request bootfile name by the BINL offer.
663 @param[in] Private Pointer to PxeBc private data.
664 @param[in] Index The received order of offer packets.
666 @retval EFI_SUCCESS Successfully retried to request bootfile name.
667 @retval EFI_DEVICE_ERROR Failed to retry bootfile name.
671 PxeBcRetryBinlOffer (
672 IN PXEBC_PRIVATE_DATA
*Private
,
676 EFI_DHCP4_PACKET
*Offer
;
677 EFI_IP_ADDRESS ServerIp
;
679 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
680 EFI_DHCP4_PACKET
*Reply
;
682 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
683 ASSERT (Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
== PxeOfferTypeDhcpBinl
||
684 Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
== PxeOfferTypeProxyBinl
);
686 Offer
= &Private
->OfferBuffer
[Index
].Dhcp4
.Packet
.Offer
;
689 // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
691 if (Offer
->Dhcp4
.Header
.ServerAddr
.Addr
[0] == 0) {
694 Private
->OfferBuffer
[Index
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
695 sizeof (EFI_IPv4_ADDRESS
)
700 &Offer
->Dhcp4
.Header
.ServerAddr
,
701 sizeof (EFI_IPv4_ADDRESS
)
705 Private
->IsDoDiscover
= FALSE
;
706 Cache4
= &Private
->ProxyOffer
.Dhcp4
;
707 Reply
= &Cache4
->Packet
.Offer
;
710 // Send another request packet for bootfile name.
712 Status
= PxeBcDhcp4Discover (
721 if (EFI_ERROR (Status
)) {
726 // Parse the reply for the last request packet.
728 Status
= PxeBcParseDhcp4Packet (Cache4
);
729 if (EFI_ERROR (Status
)) {
733 if (Cache4
->OfferType
!= PxeOfferTypeProxyPxe10
&&
734 Cache4
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
735 Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) {
737 // This BINL ack doesn't have discovery option set or multicast option set
738 // or bootfile name specified.
740 return EFI_DEVICE_ERROR
;
744 // Store the reply into mode data.
746 Private
->PxeBc
.Mode
->ProxyOfferReceived
= TRUE
;
747 CopyMem (&Private
->PxeBc
.Mode
->ProxyOffer
.Dhcpv4
, &Reply
->Dhcp4
, Reply
->Length
);
754 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
756 @param[in] Private Pointer to PxeBc private data.
757 @param[in] RcvdOffer Pointer to the received offer packet.
761 PxeBcCacheDhcp4Offer (
762 IN PXEBC_PRIVATE_DATA
*Private
,
763 IN EFI_DHCP4_PACKET
*RcvdOffer
766 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
767 EFI_DHCP4_PACKET
*Offer
;
768 PXEBC_OFFER_TYPE OfferType
;
770 ASSERT (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
);
771 Cache4
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp4
;
772 Offer
= &Cache4
->Packet
.Offer
;
775 // Cache the content of DHCPv4 packet firstly.
777 PxeBcCacheDhcp4Packet (Offer
, RcvdOffer
);
780 // Validate the DHCPv4 packet, and parse the options and offer type.
782 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4
))) {
787 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
789 OfferType
= Cache4
->OfferType
;
790 ASSERT (OfferType
< PxeOfferTypeMax
);
792 if (OfferType
== PxeOfferTypeBootp
) {
794 // It's a Bootp offer, only cache the first one, and discard the others.
796 if (Private
->OfferCount
[OfferType
] == 0) {
797 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
798 Private
->OfferCount
[OfferType
] = 1;
803 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
804 if (IS_PROXY_DHCP_OFFER (Offer
)) {
806 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
808 Private
->IsProxyRecved
= TRUE
;
810 if (OfferType
== PxeOfferTypeProxyBinl
) {
812 // Cache all proxy BINL offers.
814 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
815 Private
->OfferCount
[OfferType
]++;
816 } else if (Private
->OfferCount
[OfferType
] > 0) {
818 // Only cache the first PXE10/WFM11a offer, and discard the others.
820 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
821 Private
->OfferCount
[OfferType
] = 1;
827 // It's a DHCPv4 offer with yiaddr, and cache them all.
829 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
830 Private
->OfferCount
[OfferType
]++;
839 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
841 @param[in] Private Pointer to PxeBc private data.
845 PxeBcSelectDhcp4Offer (
846 IN PXEBC_PRIVATE_DATA
*Private
851 EFI_DHCP4_PACKET
*Offer
;
853 Private
->SelectIndex
= 0;
855 if (Private
->IsOfferSorted
) {
857 // Select offer by default policy.
859 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
861 // 1. DhcpPxe10 offer
863 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
865 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
867 // 2. DhcpWfm11a offer
869 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
871 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
872 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
874 // 3. DhcpOnly offer and ProxyPxe10 offer.
876 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
877 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
879 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
880 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
882 // 4. DhcpOnly offer and ProxyWfm11a offer.
884 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
885 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
887 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
889 // 5. DhcpBinl offer.
891 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
893 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
894 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
896 // 6. DhcpOnly offer and ProxyBinl offer.
898 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
899 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
903 // 7. DhcpOnly offer with bootfilename.
905 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
906 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
907 if (Private
->OfferBuffer
[OfferIndex
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
908 Private
->SelectIndex
= OfferIndex
+ 1;
913 // 8. Bootp offer with bootfilename.
915 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeBootp
][0];
916 if (Private
->SelectIndex
== 0 &&
917 Private
->OfferCount
[PxeOfferTypeBootp
] > 0 &&
918 Private
->OfferBuffer
[OfferIndex
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
919 Private
->SelectIndex
= OfferIndex
+ 1;
924 // Select offer by received order.
926 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
928 Offer
= &Private
->OfferBuffer
[Index
].Dhcp4
.Packet
.Offer
;
930 if (IS_PROXY_DHCP_OFFER (Offer
)) {
937 if (!Private
->IsProxyRecved
&&
938 Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
== PxeOfferTypeDhcpOnly
&&
939 Private
->OfferBuffer
[Index
].Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) {
941 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
947 // Record the index of the select offer.
949 Private
->SelectIndex
= Index
+ 1;
957 Handle the DHCPv4 offer packet.
959 @param[in] Private Pointer to PxeBc private data.
961 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.
962 @retval EFI_NO_RESPONSE No response to the following request packet.
963 @retval EFI_NOT_FOUND No boot filename received.
967 PxeBcHandleDhcp4Offer (
968 IN PXEBC_PRIVATE_DATA
*Private
971 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
972 EFI_DHCP4_PACKET_OPTION
**Options
;
974 EFI_DHCP4_PACKET
*Offer
;
975 PXEBC_OFFER_TYPE OfferType
;
979 EFI_PXE_BASE_CODE_MODE
*Mode
;
980 EFI_DHCP4_PACKET
*Ack
;
982 ASSERT (Private
->SelectIndex
> 0);
983 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
984 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
985 Cache4
= &Private
->OfferBuffer
[SelectIndex
].Dhcp4
;
986 Options
= Cache4
->OptList
;
987 Status
= EFI_SUCCESS
;
989 if (Cache4
->OfferType
== PxeOfferTypeDhcpBinl
) {
991 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
993 if (EFI_ERROR (PxeBcRetryBinlOffer (Private
, SelectIndex
))) {
994 Status
= EFI_NO_RESPONSE
;
996 } else if (Cache4
->OfferType
== PxeOfferTypeDhcpOnly
) {
998 if (Private
->IsProxyRecved
) {
1000 // DhcpOnly offer is selected, so need try to request bootfile name.
1003 if (Private
->IsOfferSorted
) {
1005 // The proxy offer should be determined if select by default policy.
1006 // IsOfferSorted means all offers are labeled by OfferIndex.
1008 ASSERT (Private
->SelectProxyType
< PxeOfferTypeMax
);
1009 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1011 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1013 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1015 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1016 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1017 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1018 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private
, ProxyIndex
))) {
1022 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1023 Status
= EFI_NO_RESPONSE
;
1027 // For other proxy offers, only one is buffered.
1029 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1033 // The proxy offer should not be determined if select by received order.
1035 Status
= EFI_NO_RESPONSE
;
1037 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1038 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1039 Offer
= &Private
->OfferBuffer
[Index
].Dhcp4
.Packet
.Offer
;
1040 OfferType
= Private
->OfferBuffer
[Index
].Dhcp4
.OfferType
;
1041 if (!IS_PROXY_DHCP_OFFER (Offer
)) {
1043 // Skip non proxy DHCPv4 offers.
1048 if (OfferType
== PxeOfferTypeProxyBinl
) {
1050 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1052 if (EFI_ERROR (PxeBcRetryBinlOffer (Private
, Index
))) {
1057 Private
->SelectProxyType
= OfferType
;
1059 Status
= EFI_SUCCESS
;
1064 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1066 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1068 PxeBcCopyProxyOffer (Private
, ProxyIndex
);
1072 // Othewise, the bootfile name must be included in DhcpOnly offer.
1074 if (Options
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) {
1075 Status
= EFI_NOT_FOUND
;
1080 if (!EFI_ERROR (Status
)) {
1082 // All PXE boot information is ready by now.
1084 Mode
= Private
->PxeBc
.Mode
;
1085 Offer
= &Cache4
->Packet
.Offer
;
1086 Ack
= &Private
->DhcpAck
.Dhcp4
.Packet
.Ack
;
1087 if (Cache4
->OfferType
== PxeOfferTypeBootp
) {
1089 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
1090 // should be taken as ack.
1095 PxeBcCopyDhcp4Ack (Private
, Ack
, TRUE
);
1096 Mode
->DhcpDiscoverValid
= TRUE
;
1104 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
1105 to intercept events that occurred in the configuration process.
1107 @param[in] This Pointer to the EFI DHCPv4 Protocol.
1108 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
1109 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
1110 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
1112 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
1113 @param[out] NewPacket The packet that is used to replace the above Packet.
1115 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
1116 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
1117 driver will continue to wait for more DHCPOFFER packets until the
1118 retry timeout expires.
1119 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
1120 and return to the Dhcp4Init or Dhcp4InitReboot state.
1125 PxeBcDhcp4CallBack (
1126 IN EFI_DHCP4_PROTOCOL
*This
,
1128 IN EFI_DHCP4_STATE CurrentState
,
1129 IN EFI_DHCP4_EVENT Dhcp4Event
,
1130 IN EFI_DHCP4_PACKET
*Packet OPTIONAL
,
1131 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
1134 PXEBC_PRIVATE_DATA
*Private
;
1135 EFI_PXE_BASE_CODE_MODE
*Mode
;
1136 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1137 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
1142 if ((Dhcp4Event
!= Dhcp4RcvdOffer
) &&
1143 (Dhcp4Event
!= Dhcp4SelectOffer
) &&
1144 (Dhcp4Event
!= Dhcp4SendDiscover
) &&
1145 (Dhcp4Event
!= Dhcp4RcvdAck
)) {
1149 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1150 Mode
= Private
->PxeBc
.Mode
;
1151 Callback
= Private
->PxeBcCallback
;
1154 // Override the Maximum DHCP Message Size.
1156 MaxMsgSize
= PxeBcParseDhcp4Options (
1157 Packet
->Dhcp4
.Option
,
1158 GET_OPTION_BUFFER_LEN (Packet
),
1159 PXEBC_DHCP4_TAG_MAXMSG
1161 if (MaxMsgSize
!= NULL
) {
1162 Value
= HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE
- 8);
1163 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
1167 // Callback to user if any packets sent or received.
1169 if (Dhcp4Event
!= Dhcp4SelectOffer
&& Callback
!= NULL
) {
1170 Received
= (BOOLEAN
) (Dhcp4Event
== Dhcp4RcvdOffer
|| Dhcp4Event
== Dhcp4RcvdAck
);
1171 Status
= Callback
->Callback (
1176 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp4
1178 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1183 Status
= EFI_SUCCESS
;
1185 switch (Dhcp4Event
) {
1187 case Dhcp4SendDiscover
:
1189 // Cache the DHCPv4 discover packet to mode data directly.
1190 // It need to check SendGuid as well as Dhcp4SendRequest.
1192 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp4
, Packet
->Length
);
1194 case Dhcp4SendRequest
:
1195 if (Mode
->SendGUID
) {
1197 // Send the system Guid instead of the MAC address as the hardware address if required.
1199 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) Packet
->Dhcp4
.Header
.ClientHwAddr
))) {
1201 // Zero the Guid to indicate NOT programable if failed to get system Guid.
1203 ZeroMem (Packet
->Dhcp4
.Header
.ClientHwAddr
, sizeof (EFI_GUID
));
1205 Packet
->Dhcp4
.Header
.HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
1209 case Dhcp4RcvdOffer
:
1210 Status
= EFI_NOT_READY
;
1211 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1213 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
1214 // the OfferIndex and OfferCount.
1216 PxeBcCacheDhcp4Offer (Private
, Packet
);
1220 case Dhcp4SelectOffer
:
1222 // Select offer by the default policy or by order, and record the SelectIndex
1223 // and SelectProxyType.
1225 PxeBcSelectDhcp4Offer (Private
);
1227 if (Private
->SelectIndex
== 0) {
1228 Status
= EFI_ABORTED
;
1230 *NewPacket
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp4
.Packet
.Offer
;
1236 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
1237 // without verification.
1239 ASSERT (Private
->SelectIndex
!= 0);
1241 PxeBcCopyDhcp4Ack (Private
, Packet
, FALSE
);
1253 Build and send out the request packet for the bootfile, and parse the reply.
1255 @param[in] Private Pointer to PxeBc private data.
1256 @param[in] Type PxeBc option boot item type.
1257 @param[in] Layer Pointer to option boot item layer.
1258 @param[in] UseBis Use BIS or not.
1259 @param[in] DestIp Pointer to the server address.
1260 @param[in] IpCount The total count of the server address.
1261 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
1263 @retval EFI_SUCCESS Successfully discovered boot file.
1264 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
1265 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1266 @retval Others Failed to discover boot file.
1270 PxeBcDhcp4Discover (
1271 IN PXEBC_PRIVATE_DATA
*Private
,
1275 IN EFI_IP_ADDRESS
*DestIp
,
1277 IN EFI_PXE_BASE_CODE_SRVLIST
*SrvList
1280 EFI_PXE_BASE_CODE_UDP_PORT Sport
;
1281 EFI_PXE_BASE_CODE_MODE
*Mode
;
1282 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1283 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
1289 EFI_DHCP4_LISTEN_POINT ListenPoint
;
1290 EFI_DHCP4_PACKET
*Response
;
1291 UINT8 Buffer
[PXEBC_DHCP4_OPTION_MAX_SIZE
];
1292 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_OPTION_MAX_NUM
];
1294 EFI_DHCP4_PACKET_OPTION
*PxeOpt
;
1295 PXEBC_OPTION_BOOT_ITEM
*PxeBootItem
;
1299 Mode
= Private
->PxeBc
.Mode
;
1300 Dhcp4
= Private
->Dhcp4
;
1301 Status
= EFI_SUCCESS
;
1303 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
1306 // Use broadcast if destination address not specified.
1308 if (DestIp
== NULL
) {
1309 Sport
= PXEBC_DHCP4_S_PORT
;
1312 Sport
= PXEBC_BS_DISCOVER_PORT
;
1316 if (!UseBis
&& Layer
!= NULL
) {
1317 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1321 // Build all the options for the request packet.
1323 OptCount
= PxeBcBuildDhcp4Options (Private
, OptList
, Buffer
, TRUE
);
1325 if (Private
->IsDoDiscover
) {
1327 // Add vendor option of PXE_BOOT_ITEM
1329 VendorOptLen
= (UINT8
) ((sizeof (EFI_DHCP4_PACKET_OPTION
) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM
) + 1);
1330 OptList
[OptCount
] = AllocateZeroPool (VendorOptLen
);
1331 if (OptList
[OptCount
] == NULL
) {
1332 return EFI_OUT_OF_RESOURCES
;
1335 OptList
[OptCount
]->OpCode
= PXEBC_DHCP4_TAG_VENDOR
;
1336 OptList
[OptCount
]->Length
= (UINT8
) (VendorOptLen
- 2);
1337 PxeOpt
= (EFI_DHCP4_PACKET_OPTION
*) OptList
[OptCount
]->Data
;
1338 PxeOpt
->OpCode
= PXEBC_VENDOR_TAG_BOOT_ITEM
;
1339 PxeOpt
->Length
= (UINT8
) sizeof (PXEBC_OPTION_BOOT_ITEM
);
1340 PxeBootItem
= (PXEBC_OPTION_BOOT_ITEM
*) PxeOpt
->Data
;
1341 PxeBootItem
->Type
= HTONS (Type
);
1342 PxeOpt
->Data
[PxeOpt
->Length
] = PXEBC_DHCP4_TAG_EOP
;
1344 if (Layer
!= NULL
) {
1345 PxeBootItem
->Layer
= HTONS (*Layer
);
1352 // Build the request packet with seed packet and option list.
1354 Status
= Dhcp4
->Build (
1356 &Private
->SeedPacket
,
1364 // Free the vendor option of PXE_BOOT_ITEM.
1366 if (Private
->IsDoDiscover
) {
1367 FreePool (OptList
[OptCount
- 1]);
1370 if (EFI_ERROR (Status
)) {
1374 if (Mode
->SendGUID
) {
1375 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*) Token
.Packet
->Dhcp4
.Header
.ClientHwAddr
))) {
1377 // Zero the Guid to indicate NOT programable if failed to get system Guid.
1379 ZeroMem (Token
.Packet
->Dhcp4
.Header
.ClientHwAddr
, sizeof (EFI_GUID
));
1381 Token
.Packet
->Dhcp4
.Header
.HwAddrLen
= (UINT8
) sizeof (EFI_GUID
);
1385 // Set fields of the token for the request packet.
1387 Xid
= NET_RANDOM (NetRandomInitSeed ());
1388 Token
.Packet
->Dhcp4
.Header
.Xid
= HTONL (Xid
);
1389 Token
.Packet
->Dhcp4
.Header
.Reserved
= HTONS ((UINT16
) ((IsBCast
) ? 0x8000 : 0x0));
1390 CopyMem (&Token
.Packet
->Dhcp4
.Header
.ClientAddr
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1392 Token
.RemotePort
= Sport
;
1395 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
1397 CopyMem (&Token
.RemoteAddress
, DestIp
, sizeof (EFI_IPv4_ADDRESS
));
1400 CopyMem (&Token
.GatewayAddress
, &Private
->GatewayIp
, sizeof (EFI_IPv4_ADDRESS
));
1403 Token
.ListenPointCount
= 1;
1404 Token
.ListenPoints
= &ListenPoint
;
1405 Token
.ListenPoints
[0].ListenPort
= PXEBC_BS_DISCOVER_PORT
;
1406 CopyMem (&Token
.ListenPoints
[0].ListenAddress
, &Private
->StationIp
, sizeof(EFI_IPv4_ADDRESS
));
1407 CopyMem (&Token
.ListenPoints
[0].SubnetMask
, &Private
->SubnetMask
, sizeof(EFI_IPv4_ADDRESS
));
1411 // Send out the request packet to discover the bootfile.
1413 for (TryIndex
= 1; TryIndex
<= PXEBC_BOOT_REQUEST_RETRIES
; TryIndex
++) {
1415 Token
.TimeoutValue
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* TryIndex
);
1416 Token
.Packet
->Dhcp4
.Header
.Seconds
= (UINT16
) (PXEBC_BOOT_REQUEST_TIMEOUT
* (TryIndex
- 1));
1418 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
1419 if (Token
.Status
!= EFI_TIMEOUT
) {
1424 if (TryIndex
> PXEBC_BOOT_REQUEST_RETRIES
) {
1426 // No server response our PXE request
1428 Status
= EFI_TIMEOUT
;
1431 if (!EFI_ERROR (Status
)) {
1435 Response
= Token
.ResponseList
;
1437 // Find the right PXE Reply according to server address.
1439 while (RepIndex
< Token
.ResponseCount
) {
1441 while (SrvIndex
< IpCount
) {
1442 if (SrvList
[SrvIndex
].AcceptAnyResponse
) {
1445 if ((SrvList
[SrvIndex
].Type
== Type
) &&
1446 EFI_IP4_EQUAL (&Response
->Dhcp4
.Header
.ServerAddr
, &SrvList
[SrvIndex
].IpAddr
)) {
1452 if ((IpCount
!= SrvIndex
) || (IpCount
== 0)) {
1459 Response
= (EFI_DHCP4_PACKET
*) ((UINT8
*) Response
+ Response
->Size
);
1462 if (RepIndex
< Token
.ResponseCount
) {
1464 // Cache the right PXE reply packet here, set valid flag later.
1465 // Especially for PXE discover packet, store it into mode data here.
1467 if (Private
->IsDoDiscover
) {
1468 PxeBcCacheDhcp4Packet (&Private
->PxeReply
.Dhcp4
.Packet
.Ack
, Response
);
1469 CopyMem (&Mode
->PxeDiscover
, &Token
.Packet
->Dhcp4
, Token
.Packet
->Length
);
1471 PxeBcCacheDhcp4Packet (&Private
->ProxyOffer
.Dhcp4
.Packet
.Offer
, Response
);
1475 // Not found the right PXE reply packet.
1477 Status
= EFI_NOT_FOUND
;
1479 if (Token
.ResponseList
!= NULL
) {
1480 FreePool (Token
.ResponseList
);
1484 FreePool (Token
.Packet
);
1490 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1492 @param[in] Private Pointer to PxeBc private data.
1493 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL
1495 @retval EFI_SUCCESS The D.O.R.A process successfully finished.
1496 @retval Others Failed to finish the D.O.R.A process.
1501 IN PXEBC_PRIVATE_DATA
*Private
,
1502 IN EFI_DHCP4_PROTOCOL
*Dhcp4
1505 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1506 EFI_DHCP4_CONFIG_DATA Config
;
1507 EFI_DHCP4_MODE_DATA Mode
;
1508 EFI_DHCP4_PACKET_OPTION
*OptList
[PXEBC_DHCP4_OPTION_MAX_NUM
];
1509 UINT8 Buffer
[PXEBC_DHCP4_OPTION_MAX_SIZE
];
1513 ASSERT (Dhcp4
!= NULL
);
1515 Status
= EFI_SUCCESS
;
1516 PxeMode
= Private
->PxeBc
.Mode
;
1519 // Build option list for the request packet.
1521 OptCount
= PxeBcBuildDhcp4Options (Private
, OptList
, Buffer
, FALSE
);
1522 ASSERT (OptCount
> 0);
1524 ZeroMem (&Mode
, sizeof (EFI_DHCP4_MODE_DATA
));
1525 ZeroMem (&Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
1527 Config
.OptionCount
= OptCount
;
1528 Config
.OptionList
= OptList
;
1529 Config
.Dhcp4Callback
= PxeBcDhcp4CallBack
;
1530 Config
.CallbackContext
= Private
;
1531 Config
.DiscoverTryCount
= PXEBC_DHCP_RETRIES
;
1532 Config
.DiscoverTimeout
= mPxeDhcpTimeout
;
1535 // Configure the DHCPv4 instance for PXE boot.
1537 Status
= Dhcp4
->Configure (Dhcp4
, &Config
);
1538 if (EFI_ERROR (Status
)) {
1543 // Initialize the record fields for DHCPv4 offer in private data.
1545 Private
->IsProxyRecved
= FALSE
;
1546 Private
->OfferNum
= 0;
1547 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1548 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1551 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
1553 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
1554 if (EFI_ERROR (Status
)) {
1555 if (Status
== EFI_ICMP_ERROR
) {
1556 PxeMode
->IcmpErrorReceived
= TRUE
;
1562 // Get the acquired IPv4 address and store them.
1564 Status
= Dhcp4
->GetModeData (Dhcp4
, &Mode
);
1565 if (EFI_ERROR (Status
)) {
1569 ASSERT (Mode
.State
== Dhcp4Bound
);
1571 CopyMem (&Private
->StationIp
, &Mode
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
1572 CopyMem (&Private
->SubnetMask
, &Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1573 CopyMem (&Private
->GatewayIp
, &Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
1574 CopyMem (&PxeMode
->StationIp
, &Private
->StationIp
, sizeof (EFI_IPv4_ADDRESS
));
1575 CopyMem (&PxeMode
->SubnetMask
, &Private
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1577 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, &Private
->SubnetMask
);
1578 if (EFI_ERROR (Status
)) {
1583 // Check the selected offer whether BINL retry is needed.
1585 Status
= PxeBcHandleDhcp4Offer (Private
);
1587 AsciiPrint ("\n Station IP address is ");
1589 PxeBcShowIp4Addr (&Private
->StationIp
.v4
);
1593 if (EFI_ERROR (Status
)) {
1594 Dhcp4
->Stop (Dhcp4
);
1595 Dhcp4
->Configure (Dhcp4
, NULL
);
1597 ZeroMem (&Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
1598 Dhcp4
->Configure (Dhcp4
, &Config
);
1599 Private
->IsAddressOk
= TRUE
;