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
)3);
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
;
114 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
117 // Append client system architecture option
119 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ARCH
);
120 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
121 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
122 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
123 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
125 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
128 // Append vendor class option to store the PXE class identifier.
130 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS
);
131 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
132 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
133 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
134 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
136 &OptEnt
.VendorClass
->ClassId
,
137 DEFAULT_CLASS_ID_DATA
,
138 sizeof (PXEBC_CLASS_ID
)
140 PxeBcUintnToAscDecWithFormat (
141 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
142 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
143 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
146 if (Private
->Nii
!= NULL
) {
148 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
149 Private
->Nii
->StringId
,
150 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
152 PxeBcUintnToAscDecWithFormat (
153 Private
->Nii
->MajorVer
,
154 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
155 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
157 PxeBcUintnToAscDecWithFormat (
158 Private
->Nii
->MinorVer
,
159 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
160 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
171 Cache the DHCPv6 packet.
173 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
174 @param[in] Src The pointer to the DHCPv6 packet to be cached.
178 PxeBcCacheDhcp6Packet (
179 IN EFI_DHCP6_PACKET
*Dst
,
180 IN EFI_DHCP6_PACKET
*Src
183 ASSERT (Dst
->Size
>= Src
->Length
);
185 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
186 Dst
->Length
= Src
->Length
;
191 Free all the nodes in the list for boot file.
193 @param[in] Head The pointer to the head of list.
197 PxeBcFreeBootFileOption (
202 LIST_ENTRY
*NextEntry
;
203 PXEBC_DHCP6_OPTION_NODE
*Node
;
205 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
206 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
207 RemoveEntryList (Entry
);
214 Parse the Boot File URL option.
216 @param[out] FileName The pointer to the boot file name.
217 @param[in, out] SrvAddr The pointer to the boot server address.
218 @param[in] BootFile The pointer to the boot file URL option data.
219 @param[in] Length The length of the boot file URL option data.
221 @retval EFI_ABORTED User cancel operation.
222 @retval EFI_SUCCESS Selected the boot menu successfully.
223 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
227 PxeBcExtractBootFileUrl (
228 OUT UINT8
**FileName
,
229 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
235 UINT8
*BootFileNamePtr
;
237 UINT16 BootFileNameLen
;
239 CHAR8
*ServerAddressOption
;
240 CHAR8
*ServerAddress
;
244 // The format of the Boot File URL option is:
247 // 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
248 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
249 // | OPT_BOOTFILE_URL | option-len |
250 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
252 // . bootfile-url (variable length) .
254 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
258 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
259 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
260 // As an example where the BOOTFILE_NAME is the EFI loader and
261 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
263 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
265 if (Length
<= PrefixLen
||
266 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
267 return EFI_NOT_FOUND
;
270 BootFile
= BootFile
+ PrefixLen
;
271 Length
= (UINT16
) (Length
- PrefixLen
);
273 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
274 if (TmpStr
== NULL
) {
275 return EFI_OUT_OF_RESOURCES
;
278 CopyMem (TmpStr
, BootFile
, Length
);
279 TmpStr
[Length
] = '\0';
282 // Get the part of SERVER_ADDRESS string.
284 ServerAddressOption
= TmpStr
;
285 if (*ServerAddressOption
!= PXEBC_ADDR_START_DELIMITER
) {
287 return EFI_INVALID_PARAMETER
;
290 ServerAddressOption
++;
291 ServerAddress
= ServerAddressOption
;
292 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
296 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
298 return EFI_INVALID_PARAMETER
;
301 *ServerAddress
= '\0';
304 // Convert the string of server address to Ipv6 address format and store it.
306 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
307 if (EFI_ERROR (Status
)) {
313 // Get the part of BOOTFILE_NAME string.
315 BootFileNamePtr
= (UINT8
*)((UINTN
)ServerAddress
+ 1);
316 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
318 return EFI_INVALID_PARAMETER
;
322 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
323 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
324 BootFileName
= (UINT8
*) AllocateZeroPool (BootFileNameLen
);
325 if (BootFileName
== NULL
) {
327 return EFI_OUT_OF_RESOURCES
;
330 CopyMem (BootFileName
, BootFileNamePtr
, BootFileNameLen
);
331 BootFileName
[BootFileNameLen
- 1] = '\0';
332 *FileName
= BootFileName
;
343 Parse the Boot File Parameter option.
345 @param[in] BootFilePara The pointer to boot file parameter option data.
346 @param[out] BootFileSize The pointer to the parsed boot file size.
348 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
349 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
353 PxeBcExtractBootFileParam (
354 IN CHAR8
*BootFilePara
,
355 OUT UINT16
*BootFileSize
363 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
364 Length
= NTOHS (Length
);
367 // The BootFile Size should be 1~5 byte ASCII strings
369 if (Length
< 1 || Length
> 5) {
370 return EFI_NOT_FOUND
;
374 // Extract the value of BootFile Size.
376 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
378 for (Index
= 0; Index
< Length
; Index
++) {
379 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
380 return EFI_NOT_FOUND
;
383 Size
= (Size
+ Digit
) * 10;
387 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
388 return EFI_NOT_FOUND
;
391 *BootFileSize
= (UINT16
) Size
;
397 Parse the cached DHCPv6 packet, including all the options.
399 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
401 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
402 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
406 PxeBcParseDhcp6Packet (
407 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
410 EFI_DHCP6_PACKET
*Offer
;
411 EFI_DHCP6_PACKET_OPTION
**Options
;
412 EFI_DHCP6_PACKET_OPTION
*Option
;
413 PXEBC_OFFER_TYPE OfferType
;
414 BOOLEAN IsProxyOffer
;
418 UINT32 EnterpriseNum
;
422 Offer
= &Cache6
->Packet
.Offer
;
423 Options
= Cache6
->OptList
;
425 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
427 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
429 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
432 // OpLen and OpCode here are both stored in network order, since they are from original packet.
434 while (Offset
< Length
) {
436 if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_IA_NA
) {
437 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
438 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_URL
) {
440 // The server sends this option to inform the client about an URL to a boot file.
442 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
443 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
) {
444 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
445 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_VENDOR_CLASS
) {
446 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
449 Offset
+= (NTOHS (Option
->OpLen
) + 4);
450 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
454 // The offer with assigned client address is a proxy offer.
455 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
457 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
458 if (Option
!= NULL
&& NTOHS(Option
->OpLen
) >= 12) {
459 Option
= PxeBcParseDhcp6Options (
461 NTOHS (Option
->OpLen
),
462 PXEBC_DHCP6_OPT_STATUS_CODE
464 if (Option
!= NULL
&& Option
->Data
[0] == 0) {
465 IsProxyOffer
= FALSE
;
470 // The offer with "PXEClient" is a pxe offer.
472 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
473 EnterpriseNum
= PXEBC_DHCP6_ENTERPRISE_NUM
;
474 if (Option
!= NULL
&&
475 NTOHS(Option
->OpLen
) >= 13 &&
476 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
477 CompareMem (&Option
->Data
[4], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
482 // Determine offer type of the dhcp6 packet.
486 // It's a binl offer only with PXEClient.
488 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
491 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
493 OfferType
= PxeOfferTypeDhcpOnly
;
496 Cache6
->OfferType
= OfferType
;
503 Cache the DHCPv6 ack packet, and parse it on demand.
505 @param[in] Private The pointer to PxeBc private data.
506 @param[in] Ack The pointer to the DHCPv6 ack packet.
507 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
512 IN PXEBC_PRIVATE_DATA
*Private
,
513 IN EFI_DHCP6_PACKET
*Ack
,
517 EFI_PXE_BASE_CODE_MODE
*Mode
;
519 Mode
= Private
->PxeBc
.Mode
;
521 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
525 // Parse the ack packet and store it into mode data if needed.
527 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
528 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
529 Mode
->DhcpAckReceived
= TRUE
;
535 Cache the DHCPv6 proxy offer packet according to the received order.
537 @param[in] Private The pointer to PxeBc private data.
538 @param[in] OfferIndex The received order of offer packets.
542 PxeBcCopyDhcp6Proxy (
543 IN PXEBC_PRIVATE_DATA
*Private
,
547 EFI_PXE_BASE_CODE_MODE
*Mode
;
548 EFI_DHCP6_PACKET
*Offer
;
550 ASSERT (OfferIndex
< Private
->OfferNum
);
551 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
553 Mode
= Private
->PxeBc
.Mode
;
554 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
557 // Cache the proxy offer packet and parse it.
559 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
560 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
563 // Store this packet into mode data.
565 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
566 Mode
->ProxyOfferReceived
= TRUE
;
571 Retry to request bootfile name by the BINL offer.
573 @param[in] Private The pointer to PxeBc private data.
574 @param[in] Index The received order of offer packets.
576 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
577 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
581 PxeBcRetryDhcp6Binl (
582 IN PXEBC_PRIVATE_DATA
*Private
,
586 EFI_PXE_BASE_CODE_MODE
*Mode
;
587 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
588 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
589 EFI_IP_ADDRESS ServerIp
;
592 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
593 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
594 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
596 Mode
= Private
->PxeBc
.Mode
;
597 Private
->IsDoDiscover
= FALSE
;
598 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
600 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
602 // Parse out the next server address from the last offer, and store it
604 Status
= PxeBcExtractBootFileUrl (
607 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
608 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
610 if (EFI_ERROR (Status
)) {
615 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
617 Status
= PxeBcDhcp6Discover (
624 if (EFI_ERROR (Status
)) {
628 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
629 Status
= PxeBcParseDhcp6Packet (Cache6
);
630 if (EFI_ERROR (Status
)) {
634 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
635 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
636 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
638 // This BINL ack doesn't have discovery option set or multicast option set
639 // or bootfile name specified.
641 return EFI_DEVICE_ERROR
;
644 Mode
->ProxyOfferReceived
= TRUE
;
646 &Mode
->ProxyOffer
.Dhcpv6
,
647 &Cache6
->Packet
.Offer
.Dhcp6
,
648 Cache6
->Packet
.Offer
.Length
656 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
658 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
659 @param[in] RcvdOffer The pointer to the received offer packet.
663 PxeBcCacheDhcp6Offer (
664 IN PXEBC_PRIVATE_DATA
*Private
,
665 IN EFI_DHCP6_PACKET
*RcvdOffer
668 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
669 EFI_DHCP6_PACKET
*Offer
;
670 PXEBC_OFFER_TYPE OfferType
;
672 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
673 Offer
= &Cache6
->Packet
.Offer
;
676 // Cache the content of DHCPv6 packet firstly.
678 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
681 // Validate the DHCPv6 packet, and parse the options and offer type.
683 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
688 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
690 OfferType
= Cache6
->OfferType
;
691 ASSERT (OfferType
< PxeOfferTypeMax
);
692 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
694 if (IS_PROXY_OFFER (OfferType
)) {
696 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
698 Private
->IsProxyRecved
= TRUE
;
700 if (OfferType
== PxeOfferTypeProxyBinl
) {
702 // Cache all proxy BINL offers.
704 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
705 Private
->OfferCount
[OfferType
]++;
706 } else if (Private
->OfferCount
[OfferType
] > 0) {
708 // Only cache the first PXE10/WFM11a offer, and discard the others.
710 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
711 Private
->OfferCount
[OfferType
] = 1;
717 // It's a DHCPv6 offer with yiaddr, and cache them all.
719 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
720 Private
->OfferCount
[OfferType
]++;
728 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
730 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
734 PxeBcSelectDhcp6Offer (
735 IN PXEBC_PRIVATE_DATA
*Private
740 PXEBC_OFFER_TYPE OfferType
;
742 Private
->SelectIndex
= 0;
744 if (Private
->IsOfferSorted
) {
746 // Select offer by default policy.
748 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
750 // 1. DhcpPxe10 offer
752 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
754 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
756 // 2. DhcpWfm11a offer
758 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
760 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
761 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
763 // 3. DhcpOnly offer and ProxyPxe10 offer.
765 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
766 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
768 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
769 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
771 // 4. DhcpOnly offer and ProxyWfm11a offer.
773 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
774 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
776 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
778 // 5. DhcpBinl offer.
780 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
782 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
783 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
785 // 6. DhcpOnly offer and ProxyBinl offer.
787 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
788 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
792 // 7. DhcpOnly offer with bootfilename.
794 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
795 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
796 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
797 Private
->SelectIndex
= OfferIndex
+ 1;
804 // Select offer by received order.
806 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
808 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
810 if (IS_PROXY_OFFER (OfferType
)) {
817 if (!Private
->IsProxyRecved
&&
818 OfferType
== PxeOfferTypeDhcpOnly
&&
819 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
821 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
826 Private
->SelectIndex
= Index
+ 1;
834 Handle the DHCPv6 offer packet.
836 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
838 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
839 @retval EFI_NO_RESPONSE No response to the following request packet.
843 PxeBcHandleDhcp6Offer (
844 IN PXEBC_PRIVATE_DATA
*Private
847 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
849 PXEBC_OFFER_TYPE OfferType
;
854 ASSERT (Private
->SelectIndex
> 0);
855 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
856 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
857 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
858 Status
= EFI_SUCCESS
;
860 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
862 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
864 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
865 Status
= EFI_NO_RESPONSE
;
867 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
869 if (Private
->IsProxyRecved
) {
871 // DhcpOnly offer is selected, so need try to request bootfilename.
874 if (Private
->IsOfferSorted
) {
876 // The proxy offer should be determined if select by default policy.
877 // IsOfferSorted means all offers are labeled by OfferIndex.
879 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
881 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
883 // Try all the cached ProxyBinl offer one by one to request bootfilename.
885 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
887 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
888 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
892 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
893 Status
= EFI_NO_RESPONSE
;
897 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
899 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
903 // The proxy offer should not be determined if select by received order.
905 Status
= EFI_NO_RESPONSE
;
907 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
909 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
911 if (!IS_PROXY_OFFER (OfferType
)) {
913 // Skip non proxy dhcp offers.
918 if (OfferType
== PxeOfferTypeProxyBinl
) {
920 // Try all the cached ProxyBinl offer one by one to request bootfilename.
922 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
927 Private
->SelectProxyType
= OfferType
;
929 Status
= EFI_SUCCESS
;
934 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
936 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
938 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
942 // Othewise, the bootfilename must be included in DhcpOnly offer.
944 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
948 if (!EFI_ERROR (Status
)) {
950 // All PXE boot information is ready by now.
952 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
953 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
961 Unregister the address by Ip6Config protocol.
963 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
967 PxeBcUnregisterIp6Address (
968 IN PXEBC_PRIVATE_DATA
*Private
971 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
973 // PXE driver change the policy of IP6 driver, it's a chance to recover.
974 // Keep the point and there is no enough requirements to do recovery.
981 Register the ready address by Ip6Config protocol.
983 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
984 @param[in] Address The pointer to the ready address.
986 @retval EFI_SUCCESS Registered the address succesfully.
987 @retval Others Failed to register the address.
991 PxeBcRegisterIp6Address (
992 IN PXEBC_PRIVATE_DATA
*Private
,
993 IN EFI_IPv6_ADDRESS
*Address
996 EFI_IP6_PROTOCOL
*Ip6
;
997 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
998 EFI_IP6_CONFIG_POLICY Policy
;
999 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1001 EFI_EVENT TimeOutEvt
;
1002 EFI_EVENT MappedEvt
;
1005 Status
= EFI_SUCCESS
;
1008 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1009 Ip6Cfg
= Private
->Ip6Cfg
;
1012 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1013 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1016 // Get and store the current policy of IP6 driver.
1018 Status
= Ip6Cfg
->GetData (
1020 Ip6ConfigDataTypePolicy
,
1024 if (EFI_ERROR (Status
)) {
1029 // There is no channel between IP6 and PXE driver about address setting,
1030 // so it has to set the new address by Ip6ConfigProtocol manually.
1032 Policy
= Ip6ConfigPolicyManual
;
1033 Status
= Ip6Cfg
->SetData (
1035 Ip6ConfigDataTypePolicy
,
1036 sizeof(EFI_IP6_CONFIG_POLICY
),
1039 if (EFI_ERROR (Status
)) {
1041 // There is no need to recover later.
1043 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1048 // Create a timer as setting address timeout event since DAD in IP6 driver.
1050 Status
= gBS
->CreateEvent (
1057 if (EFI_ERROR (Status
)) {
1062 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1064 Status
= gBS
->CreateEvent (
1068 &Private
->IsAddressOk
,
1071 if (EFI_ERROR (Status
)) {
1075 Status
= Ip6Cfg
->RegisterDataNotify (
1077 Ip6ConfigDataTypeManualAddress
,
1080 if (EFI_ERROR(Status
)) {
1084 Status
= Ip6Cfg
->SetData (
1086 Ip6ConfigDataTypeManualAddress
,
1087 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1090 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1095 // Start the 5 secondes timer to wait for setting address.
1097 Status
= EFI_NO_MAPPING
;
1098 gBS
->SetTimer (TimeOutEvt
, TimerRelative
, PXEBC_DHCP6_MAPPING_TIMEOUT
);
1100 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1102 if (Private
->IsAddressOk
) {
1103 Status
= EFI_SUCCESS
;
1109 if (MappedEvt
!= NULL
) {
1110 Ip6Cfg
->UnregisterDataNotify (
1112 Ip6ConfigDataTypeManualAddress
,
1115 gBS
->CloseEvent (MappedEvt
);
1117 if (TimeOutEvt
!= NULL
) {
1118 gBS
->CloseEvent (TimeOutEvt
);
1125 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1126 to intercept events that occurred in the configuration process.
1128 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1129 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1130 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1131 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1133 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1134 @param[out] NewPacket The packet that is used to replace the Packet above.
1136 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1137 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1138 driver will continue to wait for more packets.
1139 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1144 PxeBcDhcp6CallBack (
1145 IN EFI_DHCP6_PROTOCOL
*This
,
1147 IN EFI_DHCP6_STATE CurrentState
,
1148 IN EFI_DHCP6_EVENT Dhcp6Event
,
1149 IN EFI_DHCP6_PACKET
*Packet
,
1150 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1153 PXEBC_PRIVATE_DATA
*Private
;
1154 EFI_PXE_BASE_CODE_MODE
*Mode
;
1155 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1156 EFI_DHCP6_PACKET
*SelectAd
;
1160 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1161 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1162 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1163 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1164 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1168 ASSERT (Packet
!= NULL
);
1170 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1171 Mode
= Private
->PxeBc
.Mode
;
1172 Callback
= Private
->PxeBcCallback
;
1175 // Callback to user when any traffic ocurred if has.
1177 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1178 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1179 Status
= Callback
->Callback (
1184 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1186 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1191 Status
= EFI_SUCCESS
;
1193 switch (Dhcp6Event
) {
1195 case Dhcp6SendSolicit
:
1197 // Cache the dhcp discover packet to mode data directly.
1199 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1202 case Dhcp6RcvdAdvertise
:
1203 Status
= EFI_NOT_READY
;
1204 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1206 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1207 // the OfferIndex and OfferCount.
1209 PxeBcCacheDhcp6Offer (Private
, Packet
);
1213 case Dhcp6SendRequest
:
1215 // Store the request packet as seed packet for discover.
1217 if (Private
->Dhcp6Request
!= NULL
) {
1218 FreePool (Private
->Dhcp6Request
);
1220 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1221 if (Private
->Dhcp6Request
!= NULL
) {
1222 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1226 case Dhcp6SelectAdvertise
:
1228 // Select offer by the default policy or by order, and record the SelectIndex
1229 // and SelectProxyType.
1231 PxeBcSelectDhcp6Offer (Private
);
1233 if (Private
->SelectIndex
== 0) {
1234 Status
= EFI_ABORTED
;
1236 ASSERT (NewPacket
!= NULL
);
1237 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1238 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1239 ASSERT (*NewPacket
!= NULL
);
1240 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1244 case Dhcp6RcvdReply
:
1246 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1247 // without verification.
1249 ASSERT (Private
->SelectIndex
!= 0);
1250 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1262 Build and send out the request packet for the bootfile, and parse the reply.
1264 @param[in] Private The pointer to PxeBc private data.
1265 @param[in] Type PxeBc option boot item type.
1266 @param[in] Layer The pointer to option boot item layer.
1267 @param[in] UseBis Use BIS or not.
1268 @param[in] DestIp The pointer to the server address.
1270 @retval EFI_SUCCESS Successfully discovered the boot file.
1271 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1272 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1273 @retval Others Failed to discover the boot file.
1277 PxeBcDhcp6Discover (
1278 IN PXEBC_PRIVATE_DATA
*Private
,
1282 IN EFI_IP_ADDRESS
*DestIp
1285 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
1286 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
1287 EFI_PXE_BASE_CODE_MODE
*Mode
;
1288 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1289 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
1291 EFI_DHCP6_PACKET
*Request
;
1293 EFI_DHCP6_PACKET
*Reply
;
1303 PxeBc
= &Private
->PxeBc
;
1305 Request
= Private
->Dhcp6Request
;
1306 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
1307 DestPort
= PXEBC_BS_DISCOVER_PORT
;
1310 if (!UseBis
&& Layer
!= NULL
) {
1311 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1314 if (Request
== NULL
) {
1315 return EFI_DEVICE_ERROR
;
1318 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
1319 if (Discover
== NULL
) {
1320 return EFI_OUT_OF_RESOURCES
;
1324 // Build the discover packet by the cached request packet before.
1326 Xid
= NET_RANDOM (NetRandomInitSeed ());
1327 Discover
->TransactionId
= HTONL (Xid
);
1328 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
1329 RequestOpt
= Request
->Dhcp6
.Option
;
1330 DiscoverOpt
= Discover
->DhcpOptions
;
1331 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
1332 RequestLen
= DiscoverLen
;
1334 while (RequestLen
< Request
->Length
) {
1335 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
1336 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
1337 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
1338 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
1340 // Copy all the options except IA option.
1342 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
1343 DiscoverOpt
+= (OpLen
+ 4);
1344 DiscoverLen
+= (OpLen
+ 4);
1346 RequestOpt
+= (OpLen
+ 4);
1347 RequestLen
+= (OpLen
+ 4);
1350 Status
= PxeBc
->UdpWrite (
1356 &Private
->StationIp
,
1363 if (EFI_ERROR (Status
)) {
1368 // Cache the right PXE reply packet here, set valid flag later.
1369 // Especially for PXE discover packet, store it into mode data here.
1371 if (Private
->IsDoDiscover
) {
1372 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
1373 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
1375 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1377 ReadSize
= (UINTN
) Reply
->Size
;
1379 Status
= PxeBc
->UdpRead (
1382 &Private
->StationIp
,
1389 (VOID
*) &Reply
->Dhcp6
1391 if (EFI_ERROR (Status
)) {
1400 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1402 @param[in] Private The pointer to PxeBc private data.
1403 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1405 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1406 @retval Others Failed to finish the S.A.R.R. process.
1411 IN PXEBC_PRIVATE_DATA
*Private
,
1412 IN EFI_DHCP6_PROTOCOL
*Dhcp6
1415 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1416 EFI_DHCP6_CONFIG_DATA Config
;
1417 EFI_DHCP6_MODE_DATA Mode
;
1418 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
1419 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
1420 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
1424 Status
= EFI_SUCCESS
;
1425 PxeMode
= Private
->PxeBc
.Mode
;
1428 // Build option list for the request packet.
1430 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
1431 ASSERT (OptCount
> 0);
1433 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
1434 if (Retransmit
== NULL
) {
1435 return EFI_OUT_OF_RESOURCES
;
1438 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
1439 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1441 Config
.OptionCount
= OptCount
;
1442 Config
.OptionList
= OptList
;
1443 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
1444 Config
.CallbackContext
= Private
;
1445 Config
.IaInfoEvent
= NULL
;
1446 Config
.RapidCommit
= FALSE
;
1447 Config
.ReconfigureAccept
= FALSE
;
1448 Config
.IaDescriptor
.IaId
= 1;
1449 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
1450 Config
.SolicitRetransmission
= Retransmit
;
1451 Retransmit
->Irt
= 4;
1452 Retransmit
->Mrc
= 4;
1453 Retransmit
->Mrt
= 32;
1454 Retransmit
->Mrd
= 60;
1457 // Configure the DHCPv6 instance for PXE boot.
1459 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
1460 if (EFI_ERROR (Status
)) {
1461 FreePool (Retransmit
);
1466 // Initialize the record fields for DHCPv6 offer in private data.
1468 Private
->IsProxyRecved
= FALSE
;
1469 Private
->OfferNum
= 0;
1470 Private
->SelectIndex
= 0;
1471 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1472 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1476 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1478 Status
= Dhcp6
->Start (Dhcp6
);
1479 if (EFI_ERROR (Status
)) {
1480 if (Status
== EFI_ICMP_ERROR
) {
1481 PxeMode
->IcmpErrorReceived
= TRUE
;
1483 Dhcp6
->Configure (Dhcp6
, NULL
);
1488 // Get the acquired IPv6 address and store them.
1490 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1491 if (EFI_ERROR (Status
)) {
1492 Dhcp6
->Stop (Dhcp6
);
1496 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1497 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1498 CopyMem (&PxeMode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1500 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1501 if (EFI_ERROR (Status
)) {
1502 Dhcp6
->Stop (Dhcp6
);
1506 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, NULL
);
1507 if (EFI_ERROR (Status
)) {
1508 PxeBcUnregisterIp6Address (Private
);
1509 Dhcp6
->Stop (Dhcp6
);
1514 // Check the selected offer whether BINL retry is needed.
1516 Status
= PxeBcHandleDhcp6Offer (Private
);
1517 if (EFI_ERROR (Status
)) {
1518 PxeBcUnregisterIp6Address (Private
);
1519 Dhcp6
->Stop (Dhcp6
);
1523 AsciiPrint ("\n Station IP address is ");
1525 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);