2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2010, 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"
20 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
22 @param[in] Buffer The pointer to the option buffer.
23 @param[in] Length Length of the option buffer.
24 @param[in] OptTag The required option tag.
26 @retval NULL Failed to parse the required option.
27 @retval Others The postion of the required option in buffer.
30 EFI_DHCP6_PACKET_OPTION
*
31 PxeBcParseDhcp6Options (
37 EFI_DHCP6_PACKET_OPTION
*Option
;
40 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
44 // OpLen and OpCode here are both stored in network order.
46 while (Offset
< Length
) {
48 if (NTOHS (Option
->OpCode
) == OptTag
) {
53 Offset
+= (NTOHS(Option
->OpLen
) + 4);
54 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
62 Build the options buffer for the DHCPv6 request packet.
64 @param[in] Private The pointer to PxeBc private data.
65 @param[out] OptList The pointer to the option pointer array.
66 @param[in] Buffer The pointer to the buffer to contain the option list.
68 @return Index The count of the built-in options.
72 PxeBcBuildDhcp6Options (
73 IN PXEBC_PRIVATE_DATA
*Private
,
74 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
78 PXEBC_DHCP6_OPTION_ENTRY OptEnt
;
83 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
86 // Append client option request option
88 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ORO
);
89 OptList
[Index
]->OpLen
= HTONS (4);
90 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
91 OptEnt
.Oro
->OpCode
[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL
);
92 OptEnt
.Oro
->OpCode
[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
);
94 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
97 // Append client network device interface option
99 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_UNDI
);
100 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_UNDI
));
101 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
103 if (Private
->Nii
!= NULL
) {
104 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
105 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
106 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
108 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
109 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
110 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
113 OptEnt
.Undi
->Reserved
= 0;
115 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
118 // Append client system architecture option
120 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ARCH
);
121 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
122 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
123 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
124 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
126 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
129 // Append vendor class option to store the PXE class identifier.
131 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS
);
132 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
133 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
134 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
135 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
137 &OptEnt
.VendorClass
->ClassId
,
138 DEFAULT_CLASS_ID_DATA
,
139 sizeof (PXEBC_CLASS_ID
)
141 PxeBcUintnToAscDecWithFormat (
142 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
143 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
144 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
147 if (Private
->Nii
!= NULL
) {
149 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
150 Private
->Nii
->StringId
,
151 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
153 PxeBcUintnToAscDecWithFormat (
154 Private
->Nii
->MajorVer
,
155 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
156 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
158 PxeBcUintnToAscDecWithFormat (
159 Private
->Nii
->MinorVer
,
160 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
161 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
172 Cache the DHCPv6 packet.
174 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
175 @param[in] Src The pointer to the DHCPv6 packet to be cached.
179 PxeBcCacheDhcp6Packet (
180 IN EFI_DHCP6_PACKET
*Dst
,
181 IN EFI_DHCP6_PACKET
*Src
184 ASSERT (Dst
->Size
>= Src
->Length
);
186 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
187 Dst
->Length
= Src
->Length
;
192 Free all the nodes in the list for boot file.
194 @param[in] Head The pointer to the head of list.
198 PxeBcFreeBootFileOption (
203 LIST_ENTRY
*NextEntry
;
204 PXEBC_DHCP6_OPTION_NODE
*Node
;
206 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
207 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
208 RemoveEntryList (Entry
);
215 Parse the Boot File URL option.
217 @param[out] FileName The pointer to the boot file name.
218 @param[in, out] SrvAddr The pointer to the boot server address.
219 @param[in] BootFile The pointer to the boot file URL option data.
220 @param[in] Length The length of the boot file URL option data.
222 @retval EFI_ABORTED User cancel operation.
223 @retval EFI_SUCCESS Selected the boot menu successfully.
224 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
228 PxeBcExtractBootFileUrl (
229 OUT UINT8
**FileName
,
230 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
236 UINT8
*BootFileNamePtr
;
238 UINT16 BootFileNameLen
;
240 CHAR8
*ServerAddressOption
;
241 CHAR8
*ServerAddress
;
245 // The format of the Boot File URL option is:
248 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
249 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
250 // | OPT_BOOTFILE_URL | option-len |
251 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
253 // . bootfile-url (variable length) .
255 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
259 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
260 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
261 // As an example where the BOOTFILE_NAME is the EFI loader and
262 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
264 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
266 if (Length
<= PrefixLen
||
267 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
268 return EFI_NOT_FOUND
;
271 BootFile
= BootFile
+ PrefixLen
;
272 Length
= (UINT16
) (Length
- PrefixLen
);
274 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
275 if (TmpStr
== NULL
) {
276 return EFI_OUT_OF_RESOURCES
;
279 CopyMem (TmpStr
, BootFile
, Length
);
280 TmpStr
[Length
] = '\0';
283 // Get the part of SERVER_ADDRESS string.
285 ServerAddressOption
= TmpStr
;
286 if (*ServerAddressOption
!= PXEBC_ADDR_START_DELIMITER
) {
288 return EFI_INVALID_PARAMETER
;
291 ServerAddressOption
++;
292 ServerAddress
= ServerAddressOption
;
293 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
297 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
299 return EFI_INVALID_PARAMETER
;
302 *ServerAddress
= '\0';
305 // Convert the string of server address to Ipv6 address format and store it.
307 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
308 if (EFI_ERROR (Status
)) {
314 // Get the part of BOOTFILE_NAME string.
316 BootFileNamePtr
= (UINT8
*)((UINTN
)ServerAddress
+ 1);
317 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
319 return EFI_INVALID_PARAMETER
;
323 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
324 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
325 BootFileName
= (UINT8
*) AllocateZeroPool (BootFileNameLen
);
326 if (BootFileName
== NULL
) {
328 return EFI_OUT_OF_RESOURCES
;
331 CopyMem (BootFileName
, BootFileNamePtr
, BootFileNameLen
);
332 BootFileName
[BootFileNameLen
- 1] = '\0';
333 *FileName
= BootFileName
;
344 Parse the Boot File Parameter option.
346 @param[in] BootFilePara The pointer to boot file parameter option data.
347 @param[out] BootFileSize The pointer to the parsed boot file size.
349 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
350 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
354 PxeBcExtractBootFileParam (
355 IN CHAR8
*BootFilePara
,
356 OUT UINT16
*BootFileSize
364 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
365 Length
= NTOHS (Length
);
368 // The BootFile Size should be 1~5 byte ASCII strings
370 if (Length
< 1 || Length
> 5) {
371 return EFI_NOT_FOUND
;
375 // Extract the value of BootFile Size.
377 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
379 for (Index
= 0; Index
< Length
; Index
++) {
380 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
381 return EFI_NOT_FOUND
;
384 Size
= (Size
+ Digit
) * 10;
388 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
389 return EFI_NOT_FOUND
;
392 *BootFileSize
= (UINT16
) Size
;
398 Parse the cached DHCPv6 packet, including all the options.
400 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
402 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
403 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
407 PxeBcParseDhcp6Packet (
408 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
411 EFI_DHCP6_PACKET
*Offer
;
412 EFI_DHCP6_PACKET_OPTION
**Options
;
413 EFI_DHCP6_PACKET_OPTION
*Option
;
414 PXEBC_OFFER_TYPE OfferType
;
415 BOOLEAN IsProxyOffer
;
419 UINT32 EnterpriseNum
;
423 Offer
= &Cache6
->Packet
.Offer
;
424 Options
= Cache6
->OptList
;
426 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
428 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
430 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
433 // OpLen and OpCode here are both stored in network order, since they are from original packet.
435 while (Offset
< Length
) {
437 if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_IA_NA
) {
438 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
439 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_URL
) {
441 // The server sends this option to inform the client about an URL to a boot file.
443 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
444 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
) {
445 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
446 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_VENDOR_CLASS
) {
447 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
450 Offset
+= (NTOHS (Option
->OpLen
) + 4);
451 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
455 // The offer with assigned client address is a proxy offer.
456 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
458 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
459 if (Option
!= NULL
&& NTOHS(Option
->OpLen
) >= 12) {
460 Option
= PxeBcParseDhcp6Options (
462 NTOHS (Option
->OpLen
),
463 PXEBC_DHCP6_OPT_STATUS_CODE
465 if (Option
!= NULL
&& Option
->Data
[0] == 0) {
466 IsProxyOffer
= FALSE
;
471 // The offer with "PXEClient" is a pxe offer.
473 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
474 EnterpriseNum
= PXEBC_DHCP6_ENTERPRISE_NUM
;
475 if (Option
!= NULL
&&
476 NTOHS(Option
->OpLen
) >= 13 &&
477 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
478 CompareMem (&Option
->Data
[4], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
483 // Determine offer type of the dhcp6 packet.
487 // It's a binl offer only with PXEClient.
489 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
492 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
494 OfferType
= PxeOfferTypeDhcpOnly
;
497 Cache6
->OfferType
= OfferType
;
504 Cache the DHCPv6 ack packet, and parse it on demand.
506 @param[in] Private The pointer to PxeBc private data.
507 @param[in] Ack The pointer to the DHCPv6 ack packet.
508 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
513 IN PXEBC_PRIVATE_DATA
*Private
,
514 IN EFI_DHCP6_PACKET
*Ack
,
518 EFI_PXE_BASE_CODE_MODE
*Mode
;
520 Mode
= Private
->PxeBc
.Mode
;
522 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
526 // Parse the ack packet and store it into mode data if needed.
528 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
529 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
530 Mode
->DhcpAckReceived
= TRUE
;
536 Cache the DHCPv6 proxy offer packet according to the received order.
538 @param[in] Private The pointer to PxeBc private data.
539 @param[in] OfferIndex The received order of offer packets.
543 PxeBcCopyDhcp6Proxy (
544 IN PXEBC_PRIVATE_DATA
*Private
,
548 EFI_PXE_BASE_CODE_MODE
*Mode
;
549 EFI_DHCP6_PACKET
*Offer
;
551 ASSERT (OfferIndex
< Private
->OfferNum
);
552 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
554 Mode
= Private
->PxeBc
.Mode
;
555 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
558 // Cache the proxy offer packet and parse it.
560 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
561 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
564 // Store this packet into mode data.
566 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
567 Mode
->ProxyOfferReceived
= TRUE
;
572 Retry to request bootfile name by the BINL offer.
574 @param[in] Private The pointer to PxeBc private data.
575 @param[in] Index The received order of offer packets.
577 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
578 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
582 PxeBcRetryDhcp6Binl (
583 IN PXEBC_PRIVATE_DATA
*Private
,
587 EFI_PXE_BASE_CODE_MODE
*Mode
;
588 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
589 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
590 EFI_IP_ADDRESS ServerIp
;
593 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
594 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
595 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
597 Mode
= Private
->PxeBc
.Mode
;
598 Private
->IsDoDiscover
= FALSE
;
599 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
601 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
603 // Parse out the next server address from the last offer, and store it
605 Status
= PxeBcExtractBootFileUrl (
608 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
609 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
611 if (EFI_ERROR (Status
)) {
616 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
618 Status
= PxeBcDhcp6Discover (
625 if (EFI_ERROR (Status
)) {
629 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
630 Status
= PxeBcParseDhcp6Packet (Cache6
);
631 if (EFI_ERROR (Status
)) {
635 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
636 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
637 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
639 // This BINL ack doesn't have discovery option set or multicast option set
640 // or bootfile name specified.
642 return EFI_DEVICE_ERROR
;
645 Mode
->ProxyOfferReceived
= TRUE
;
647 &Mode
->ProxyOffer
.Dhcpv6
,
648 &Cache6
->Packet
.Offer
.Dhcp6
,
649 Cache6
->Packet
.Offer
.Length
657 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
659 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
660 @param[in] RcvdOffer The pointer to the received offer packet.
664 PxeBcCacheDhcp6Offer (
665 IN PXEBC_PRIVATE_DATA
*Private
,
666 IN EFI_DHCP6_PACKET
*RcvdOffer
669 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
670 EFI_DHCP6_PACKET
*Offer
;
671 PXEBC_OFFER_TYPE OfferType
;
673 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
674 Offer
= &Cache6
->Packet
.Offer
;
677 // Cache the content of DHCPv6 packet firstly.
679 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
682 // Validate the DHCPv6 packet, and parse the options and offer type.
684 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
689 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
691 OfferType
= Cache6
->OfferType
;
692 ASSERT (OfferType
< PxeOfferTypeMax
);
693 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
695 if (IS_PROXY_OFFER (OfferType
)) {
697 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
699 Private
->IsProxyRecved
= TRUE
;
701 if (OfferType
== PxeOfferTypeProxyBinl
) {
703 // Cache all proxy BINL offers.
705 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
706 Private
->OfferCount
[OfferType
]++;
707 } else if (Private
->OfferCount
[OfferType
] > 0) {
709 // Only cache the first PXE10/WFM11a offer, and discard the others.
711 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
712 Private
->OfferCount
[OfferType
] = 1;
718 // It's a DHCPv6 offer with yiaddr, and cache them all.
720 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
721 Private
->OfferCount
[OfferType
]++;
729 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
731 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
735 PxeBcSelectDhcp6Offer (
736 IN PXEBC_PRIVATE_DATA
*Private
741 PXEBC_OFFER_TYPE OfferType
;
743 Private
->SelectIndex
= 0;
745 if (Private
->IsOfferSorted
) {
747 // Select offer by default policy.
749 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
751 // 1. DhcpPxe10 offer
753 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
755 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
757 // 2. DhcpWfm11a offer
759 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
761 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
762 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
764 // 3. DhcpOnly offer and ProxyPxe10 offer.
766 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
767 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
769 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
770 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
772 // 4. DhcpOnly offer and ProxyWfm11a offer.
774 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
775 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
777 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
779 // 5. DhcpBinl offer.
781 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
783 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
784 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
786 // 6. DhcpOnly offer and ProxyBinl offer.
788 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
789 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
793 // 7. DhcpOnly offer with bootfilename.
795 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
796 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
797 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
798 Private
->SelectIndex
= OfferIndex
+ 1;
805 // Select offer by received order.
807 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
809 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
811 if (IS_PROXY_OFFER (OfferType
)) {
818 if (!Private
->IsProxyRecved
&&
819 OfferType
== PxeOfferTypeDhcpOnly
&&
820 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
822 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
827 Private
->SelectIndex
= Index
+ 1;
835 Handle the DHCPv6 offer packet.
837 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
839 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
840 @retval EFI_NO_RESPONSE No response to the following request packet.
844 PxeBcHandleDhcp6Offer (
845 IN PXEBC_PRIVATE_DATA
*Private
848 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
850 PXEBC_OFFER_TYPE OfferType
;
855 ASSERT (Private
->SelectIndex
> 0);
856 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
857 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
858 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
859 Status
= EFI_SUCCESS
;
861 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
863 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
865 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
866 Status
= EFI_NO_RESPONSE
;
868 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
870 if (Private
->IsProxyRecved
) {
872 // DhcpOnly offer is selected, so need try to request bootfilename.
875 if (Private
->IsOfferSorted
) {
877 // The proxy offer should be determined if select by default policy.
878 // IsOfferSorted means all offers are labeled by OfferIndex.
880 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
882 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
884 // Try all the cached ProxyBinl offer one by one to request bootfilename.
886 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
888 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
889 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
893 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
894 Status
= EFI_NO_RESPONSE
;
898 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
900 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
904 // The proxy offer should not be determined if select by received order.
906 Status
= EFI_NO_RESPONSE
;
908 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
910 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
912 if (!IS_PROXY_OFFER (OfferType
)) {
914 // Skip non proxy dhcp offers.
919 if (OfferType
== PxeOfferTypeProxyBinl
) {
921 // Try all the cached ProxyBinl offer one by one to request bootfilename.
923 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
928 Private
->SelectProxyType
= OfferType
;
930 Status
= EFI_SUCCESS
;
935 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
937 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
939 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
943 // Othewise, the bootfilename must be included in DhcpOnly offer.
945 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
949 if (!EFI_ERROR (Status
)) {
951 // All PXE boot information is ready by now.
953 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
954 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
962 Unregister the address by Ip6Config protocol.
964 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
968 PxeBcUnregisterIp6Address (
969 IN PXEBC_PRIVATE_DATA
*Private
972 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
974 // PXE driver change the policy of IP6 driver, it's a chance to recover.
975 // Keep the point and there is no enough requirements to do recovery.
982 Register the ready address by Ip6Config protocol.
984 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
985 @param[in] Address The pointer to the ready address.
987 @retval EFI_SUCCESS Registered the address succesfully.
988 @retval Others Failed to register the address.
992 PxeBcRegisterIp6Address (
993 IN PXEBC_PRIVATE_DATA
*Private
,
994 IN EFI_IPv6_ADDRESS
*Address
997 EFI_IP6_PROTOCOL
*Ip6
;
998 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
999 EFI_IP6_CONFIG_POLICY Policy
;
1000 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1002 EFI_EVENT TimeOutEvt
;
1003 EFI_EVENT MappedEvt
;
1006 Status
= EFI_SUCCESS
;
1009 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1010 Ip6Cfg
= Private
->Ip6Cfg
;
1013 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1014 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1017 // Get and store the current policy of IP6 driver.
1019 Status
= Ip6Cfg
->GetData (
1021 Ip6ConfigDataTypePolicy
,
1025 if (EFI_ERROR (Status
)) {
1030 // There is no channel between IP6 and PXE driver about address setting,
1031 // so it has to set the new address by Ip6ConfigProtocol manually.
1033 Policy
= Ip6ConfigPolicyManual
;
1034 Status
= Ip6Cfg
->SetData (
1036 Ip6ConfigDataTypePolicy
,
1037 sizeof(EFI_IP6_CONFIG_POLICY
),
1040 if (EFI_ERROR (Status
)) {
1042 // There is no need to recover later.
1044 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1049 // Create a timer as setting address timeout event since DAD in IP6 driver.
1051 Status
= gBS
->CreateEvent (
1058 if (EFI_ERROR (Status
)) {
1063 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1065 Status
= gBS
->CreateEvent (
1069 &Private
->IsAddressOk
,
1072 if (EFI_ERROR (Status
)) {
1076 Status
= Ip6Cfg
->RegisterDataNotify (
1078 Ip6ConfigDataTypeManualAddress
,
1081 if (EFI_ERROR(Status
)) {
1085 Status
= Ip6Cfg
->SetData (
1087 Ip6ConfigDataTypeManualAddress
,
1088 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1091 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1096 // Start the 5 secondes timer to wait for setting address.
1098 Status
= EFI_NO_MAPPING
;
1099 gBS
->SetTimer (TimeOutEvt
, TimerRelative
, PXEBC_DHCP6_MAPPING_TIMEOUT
);
1101 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1103 if (Private
->IsAddressOk
) {
1104 Status
= EFI_SUCCESS
;
1110 if (MappedEvt
!= NULL
) {
1111 Ip6Cfg
->UnregisterDataNotify (
1113 Ip6ConfigDataTypeManualAddress
,
1116 gBS
->CloseEvent (MappedEvt
);
1118 if (TimeOutEvt
!= NULL
) {
1119 gBS
->CloseEvent (TimeOutEvt
);
1126 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1127 to intercept events that occurred in the configuration process.
1129 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1130 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1131 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1132 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1134 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1135 @param[out] NewPacket The packet that is used to replace the Packet above.
1137 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1138 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1139 driver will continue to wait for more packets.
1140 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1145 PxeBcDhcp6CallBack (
1146 IN EFI_DHCP6_PROTOCOL
*This
,
1148 IN EFI_DHCP6_STATE CurrentState
,
1149 IN EFI_DHCP6_EVENT Dhcp6Event
,
1150 IN EFI_DHCP6_PACKET
*Packet
,
1151 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1154 PXEBC_PRIVATE_DATA
*Private
;
1155 EFI_PXE_BASE_CODE_MODE
*Mode
;
1156 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1157 EFI_DHCP6_PACKET
*SelectAd
;
1161 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1162 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1163 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1164 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1165 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1169 ASSERT (Packet
!= NULL
);
1171 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1172 Mode
= Private
->PxeBc
.Mode
;
1173 Callback
= Private
->PxeBcCallback
;
1176 // Callback to user when any traffic ocurred if has.
1178 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1179 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1180 Status
= Callback
->Callback (
1185 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1187 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1192 Status
= EFI_SUCCESS
;
1194 switch (Dhcp6Event
) {
1196 case Dhcp6SendSolicit
:
1198 // Cache the dhcp discover packet to mode data directly.
1200 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1203 case Dhcp6RcvdAdvertise
:
1204 Status
= EFI_NOT_READY
;
1205 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1207 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1208 // the OfferIndex and OfferCount.
1210 PxeBcCacheDhcp6Offer (Private
, Packet
);
1214 case Dhcp6SendRequest
:
1216 // Store the request packet as seed packet for discover.
1218 if (Private
->Dhcp6Request
!= NULL
) {
1219 FreePool (Private
->Dhcp6Request
);
1221 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1222 if (Private
->Dhcp6Request
!= NULL
) {
1223 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1227 case Dhcp6SelectAdvertise
:
1229 // Select offer by the default policy or by order, and record the SelectIndex
1230 // and SelectProxyType.
1232 PxeBcSelectDhcp6Offer (Private
);
1234 if (Private
->SelectIndex
== 0) {
1235 Status
= EFI_ABORTED
;
1237 ASSERT (NewPacket
!= NULL
);
1238 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1239 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1240 ASSERT (*NewPacket
!= NULL
);
1241 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1245 case Dhcp6RcvdReply
:
1247 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1248 // without verification.
1250 ASSERT (Private
->SelectIndex
!= 0);
1251 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1263 Build and send out the request packet for the bootfile, and parse the reply.
1265 @param[in] Private The pointer to PxeBc private data.
1266 @param[in] Type PxeBc option boot item type.
1267 @param[in] Layer The pointer to option boot item layer.
1268 @param[in] UseBis Use BIS or not.
1269 @param[in] DestIp The pointer to the server address.
1271 @retval EFI_SUCCESS Successfully discovered the boot file.
1272 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1273 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1274 @retval Others Failed to discover the boot file.
1278 PxeBcDhcp6Discover (
1279 IN PXEBC_PRIVATE_DATA
*Private
,
1283 IN EFI_IP_ADDRESS
*DestIp
1286 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
1287 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
1288 EFI_PXE_BASE_CODE_MODE
*Mode
;
1289 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1290 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
1292 EFI_DHCP6_PACKET
*Request
;
1294 EFI_DHCP6_PACKET
*Reply
;
1304 PxeBc
= &Private
->PxeBc
;
1306 Request
= Private
->Dhcp6Request
;
1307 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
1308 DestPort
= PXEBC_BS_DISCOVER_PORT
;
1311 if (!UseBis
&& Layer
!= NULL
) {
1312 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1315 if (Request
== NULL
) {
1316 return EFI_DEVICE_ERROR
;
1319 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
1320 if (Discover
== NULL
) {
1321 return EFI_OUT_OF_RESOURCES
;
1325 // Build the discover packet by the cached request packet before.
1327 Xid
= NET_RANDOM (NetRandomInitSeed ());
1328 Discover
->TransactionId
= HTONL (Xid
);
1329 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
1330 RequestOpt
= Request
->Dhcp6
.Option
;
1331 DiscoverOpt
= Discover
->DhcpOptions
;
1332 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
1333 RequestLen
= DiscoverLen
;
1335 while (RequestLen
< Request
->Length
) {
1336 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
1337 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
1338 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
1339 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
1341 // Copy all the options except IA option.
1343 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
1344 DiscoverOpt
+= (OpLen
+ 4);
1345 DiscoverLen
+= (OpLen
+ 4);
1347 RequestOpt
+= (OpLen
+ 4);
1348 RequestLen
+= (OpLen
+ 4);
1351 Status
= PxeBc
->UdpWrite (
1357 &Private
->StationIp
,
1364 if (EFI_ERROR (Status
)) {
1369 // Cache the right PXE reply packet here, set valid flag later.
1370 // Especially for PXE discover packet, store it into mode data here.
1372 if (Private
->IsDoDiscover
) {
1373 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
1374 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
1376 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1378 ReadSize
= (UINTN
) Reply
->Size
;
1380 Status
= PxeBc
->UdpRead (
1383 &Private
->StationIp
,
1390 (VOID
*) &Reply
->Dhcp6
1392 if (EFI_ERROR (Status
)) {
1401 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1403 @param[in] Private The pointer to PxeBc private data.
1404 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1406 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1407 @retval Others Failed to finish the S.A.R.R. process.
1412 IN PXEBC_PRIVATE_DATA
*Private
,
1413 IN EFI_DHCP6_PROTOCOL
*Dhcp6
1416 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1417 EFI_DHCP6_CONFIG_DATA Config
;
1418 EFI_DHCP6_MODE_DATA Mode
;
1419 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
1420 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
1421 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
1425 Status
= EFI_SUCCESS
;
1426 PxeMode
= Private
->PxeBc
.Mode
;
1429 // Build option list for the request packet.
1431 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
1432 ASSERT (OptCount
> 0);
1434 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
1435 if (Retransmit
== NULL
) {
1436 return EFI_OUT_OF_RESOURCES
;
1439 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
1440 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1442 Config
.OptionCount
= OptCount
;
1443 Config
.OptionList
= OptList
;
1444 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
1445 Config
.CallbackContext
= Private
;
1446 Config
.IaInfoEvent
= NULL
;
1447 Config
.RapidCommit
= FALSE
;
1448 Config
.ReconfigureAccept
= FALSE
;
1449 Config
.IaDescriptor
.IaId
= 1;
1450 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
1451 Config
.SolicitRetransmission
= Retransmit
;
1452 Retransmit
->Irt
= 4;
1453 Retransmit
->Mrc
= 4;
1454 Retransmit
->Mrt
= 32;
1455 Retransmit
->Mrd
= 60;
1458 // Configure the DHCPv6 instance for PXE boot.
1460 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
1461 if (EFI_ERROR (Status
)) {
1462 FreePool (Retransmit
);
1467 // Initialize the record fields for DHCPv6 offer in private data.
1469 Private
->IsProxyRecved
= FALSE
;
1470 Private
->OfferNum
= 0;
1471 Private
->SelectIndex
= 0;
1472 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1473 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1477 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1479 Status
= Dhcp6
->Start (Dhcp6
);
1480 if (EFI_ERROR (Status
)) {
1481 if (Status
== EFI_ICMP_ERROR
) {
1482 PxeMode
->IcmpErrorReceived
= TRUE
;
1484 Dhcp6
->Configure (Dhcp6
, NULL
);
1489 // Get the acquired IPv6 address and store them.
1491 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1492 if (EFI_ERROR (Status
)) {
1493 Dhcp6
->Stop (Dhcp6
);
1497 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1498 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1499 CopyMem (&PxeMode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1501 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1502 if (EFI_ERROR (Status
)) {
1503 Dhcp6
->Stop (Dhcp6
);
1507 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, NULL
);
1508 if (EFI_ERROR (Status
)) {
1509 PxeBcUnregisterIp6Address (Private
);
1510 Dhcp6
->Stop (Dhcp6
);
1515 // Check the selected offer whether BINL retry is needed.
1517 Status
= PxeBcHandleDhcp6Offer (Private
);
1518 if (EFI_ERROR (Status
)) {
1519 PxeBcUnregisterIp6Address (Private
);
1520 Dhcp6
->Stop (Dhcp6
);
1524 AsciiPrint ("\n Station IP address is ");
1526 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);