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 errata that will appear in chapter 21.3 of UEFI 2.3
260 // specification after 2.3 errata B and future UEFI Specifications after 2.3.
261 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
262 // As an example where the BOOTFILE_NAME is the EFI loader and
263 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
265 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
267 if (Length
<= PrefixLen
||
268 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
269 return EFI_NOT_FOUND
;
272 BootFile
= BootFile
+ PrefixLen
;
273 Length
= (UINT16
) (Length
- PrefixLen
);
275 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
276 if (TmpStr
== NULL
) {
277 return EFI_OUT_OF_RESOURCES
;
280 CopyMem (TmpStr
, BootFile
, Length
);
281 TmpStr
[Length
] = '\0';
284 // Get the part of SERVER_ADDRESS string.
286 ServerAddressOption
= TmpStr
;
287 if (*ServerAddressOption
!= PXEBC_ADDR_START_DELIMITER
) {
289 return EFI_INVALID_PARAMETER
;
292 ServerAddressOption
++;
293 ServerAddress
= ServerAddressOption
;
294 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
298 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
300 return EFI_INVALID_PARAMETER
;
303 *ServerAddress
= '\0';
306 // Convert the string of server address to Ipv6 address format and store it.
308 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
309 if (EFI_ERROR (Status
)) {
315 // Get the part of BOOTFILE_NAME string.
317 BootFileNamePtr
= (UINT8
*)((UINTN
)ServerAddress
+ 1);
318 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
320 return EFI_INVALID_PARAMETER
;
324 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
325 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
326 BootFileName
= (UINT8
*) AllocateZeroPool (BootFileNameLen
);
327 if (BootFileName
== NULL
) {
329 return EFI_OUT_OF_RESOURCES
;
332 CopyMem (BootFileName
, BootFileNamePtr
, BootFileNameLen
);
333 BootFileName
[BootFileNameLen
- 1] = '\0';
334 *FileName
= BootFileName
;
345 Parse the Boot File Parameter option.
347 @param[in] BootFilePara The pointer to boot file parameter option data.
348 @param[out] BootFileSize The pointer to the parsed boot file size.
350 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
351 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
355 PxeBcExtractBootFileParam (
356 IN CHAR8
*BootFilePara
,
357 OUT UINT16
*BootFileSize
365 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
366 Length
= NTOHS (Length
);
369 // The BootFile Size should be 1~5 byte ASCII strings
371 if (Length
< 1 || Length
> 5) {
372 return EFI_NOT_FOUND
;
376 // Extract the value of BootFile Size.
378 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
380 for (Index
= 0; Index
< Length
; Index
++) {
381 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
382 return EFI_NOT_FOUND
;
385 Size
= (Size
+ Digit
) * 10;
389 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
390 return EFI_NOT_FOUND
;
393 *BootFileSize
= (UINT16
) Size
;
399 Parse the cached DHCPv6 packet, including all the options.
401 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
403 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
404 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
408 PxeBcParseDhcp6Packet (
409 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
412 EFI_DHCP6_PACKET
*Offer
;
413 EFI_DHCP6_PACKET_OPTION
**Options
;
414 EFI_DHCP6_PACKET_OPTION
*Option
;
415 PXEBC_OFFER_TYPE OfferType
;
416 BOOLEAN IsProxyOffer
;
420 UINT32 EnterpriseNum
;
424 Offer
= &Cache6
->Packet
.Offer
;
425 Options
= Cache6
->OptList
;
427 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
429 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
431 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
434 // OpLen and OpCode here are both stored in network order, since they are from original packet.
436 while (Offset
< Length
) {
438 if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_IA_NA
) {
439 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
440 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_URL
) {
442 // The server sends this option to inform the client about an URL to a boot file.
444 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
445 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
) {
446 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
447 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_VENDOR_CLASS
) {
448 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
451 Offset
+= (NTOHS (Option
->OpLen
) + 4);
452 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
456 // The offer with assigned client address is a proxy offer.
457 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
459 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
460 if (Option
!= NULL
&& NTOHS(Option
->OpLen
) >= 12) {
461 Option
= PxeBcParseDhcp6Options (
463 NTOHS (Option
->OpLen
),
464 PXEBC_DHCP6_OPT_STATUS_CODE
466 if (Option
!= NULL
&& Option
->Data
[0] == 0) {
467 IsProxyOffer
= FALSE
;
472 // The offer with "PXEClient" is a pxe offer.
474 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
475 EnterpriseNum
= PXEBC_DHCP6_ENTERPRISE_NUM
;
476 if (Option
!= NULL
&&
477 NTOHS(Option
->OpLen
) >= 13 &&
478 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
479 CompareMem (&Option
->Data
[4], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
484 // Determine offer type of the dhcp6 packet.
488 // It's a binl offer only with PXEClient.
490 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
493 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
495 OfferType
= PxeOfferTypeDhcpOnly
;
498 Cache6
->OfferType
= OfferType
;
505 Cache the DHCPv6 ack packet, and parse it on demand.
507 @param[in] Private The pointer to PxeBc private data.
508 @param[in] Ack The pointer to the DHCPv6 ack packet.
509 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
514 IN PXEBC_PRIVATE_DATA
*Private
,
515 IN EFI_DHCP6_PACKET
*Ack
,
519 EFI_PXE_BASE_CODE_MODE
*Mode
;
521 Mode
= Private
->PxeBc
.Mode
;
523 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
527 // Parse the ack packet and store it into mode data if needed.
529 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
530 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
531 Mode
->DhcpAckReceived
= TRUE
;
537 Cache the DHCPv6 proxy offer packet according to the received order.
539 @param[in] Private The pointer to PxeBc private data.
540 @param[in] OfferIndex The received order of offer packets.
544 PxeBcCopyDhcp6Proxy (
545 IN PXEBC_PRIVATE_DATA
*Private
,
549 EFI_PXE_BASE_CODE_MODE
*Mode
;
550 EFI_DHCP6_PACKET
*Offer
;
552 ASSERT (OfferIndex
< Private
->OfferNum
);
553 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
555 Mode
= Private
->PxeBc
.Mode
;
556 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
559 // Cache the proxy offer packet and parse it.
561 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
562 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
565 // Store this packet into mode data.
567 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
568 Mode
->ProxyOfferReceived
= TRUE
;
573 Retry to request bootfile name by the BINL offer.
575 @param[in] Private The pointer to PxeBc private data.
576 @param[in] Index The received order of offer packets.
578 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
579 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
583 PxeBcRetryDhcp6Binl (
584 IN PXEBC_PRIVATE_DATA
*Private
,
588 EFI_PXE_BASE_CODE_MODE
*Mode
;
589 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
590 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
591 EFI_IP_ADDRESS ServerIp
;
594 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
595 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
596 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
598 Mode
= Private
->PxeBc
.Mode
;
599 Private
->IsDoDiscover
= FALSE
;
600 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
602 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
604 // Parse out the next server address from the last offer, and store it
606 Status
= PxeBcExtractBootFileUrl (
609 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
610 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
612 if (EFI_ERROR (Status
)) {
617 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
619 Status
= PxeBcDhcp6Discover (
626 if (EFI_ERROR (Status
)) {
630 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
631 Status
= PxeBcParseDhcp6Packet (Cache6
);
632 if (EFI_ERROR (Status
)) {
636 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
637 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
638 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
640 // This BINL ack doesn't have discovery option set or multicast option set
641 // or bootfile name specified.
643 return EFI_DEVICE_ERROR
;
646 Mode
->ProxyOfferReceived
= TRUE
;
648 &Mode
->ProxyOffer
.Dhcpv6
,
649 &Cache6
->Packet
.Offer
.Dhcp6
,
650 Cache6
->Packet
.Offer
.Length
658 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
660 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
661 @param[in] RcvdOffer The pointer to the received offer packet.
665 PxeBcCacheDhcp6Offer (
666 IN PXEBC_PRIVATE_DATA
*Private
,
667 IN EFI_DHCP6_PACKET
*RcvdOffer
670 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
671 EFI_DHCP6_PACKET
*Offer
;
672 PXEBC_OFFER_TYPE OfferType
;
674 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
675 Offer
= &Cache6
->Packet
.Offer
;
678 // Cache the content of DHCPv6 packet firstly.
680 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
683 // Validate the DHCPv6 packet, and parse the options and offer type.
685 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
690 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
692 OfferType
= Cache6
->OfferType
;
693 ASSERT (OfferType
< PxeOfferTypeMax
);
694 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
696 if (IS_PROXY_OFFER (OfferType
)) {
698 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
700 Private
->IsProxyRecved
= TRUE
;
702 if (OfferType
== PxeOfferTypeProxyBinl
) {
704 // Cache all proxy BINL offers.
706 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
707 Private
->OfferCount
[OfferType
]++;
708 } else if (Private
->OfferCount
[OfferType
] > 0) {
710 // Only cache the first PXE10/WFM11a offer, and discard the others.
712 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
713 Private
->OfferCount
[OfferType
] = 1;
719 // It's a DHCPv6 offer with yiaddr, and cache them all.
721 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
722 Private
->OfferCount
[OfferType
]++;
730 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
732 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
736 PxeBcSelectDhcp6Offer (
737 IN PXEBC_PRIVATE_DATA
*Private
742 PXEBC_OFFER_TYPE OfferType
;
744 Private
->SelectIndex
= 0;
746 if (Private
->IsOfferSorted
) {
748 // Select offer by default policy.
750 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
752 // 1. DhcpPxe10 offer
754 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
756 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
758 // 2. DhcpWfm11a offer
760 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
762 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
763 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
765 // 3. DhcpOnly offer and ProxyPxe10 offer.
767 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
768 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
770 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
771 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
773 // 4. DhcpOnly offer and ProxyWfm11a offer.
775 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
776 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
778 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
780 // 5. DhcpBinl offer.
782 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
784 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
785 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
787 // 6. DhcpOnly offer and ProxyBinl offer.
789 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
790 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
794 // 7. DhcpOnly offer with bootfilename.
796 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
797 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
798 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
799 Private
->SelectIndex
= OfferIndex
+ 1;
806 // Select offer by received order.
808 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
810 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
812 if (IS_PROXY_OFFER (OfferType
)) {
819 if (!Private
->IsProxyRecved
&&
820 OfferType
== PxeOfferTypeDhcpOnly
&&
821 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
823 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
828 Private
->SelectIndex
= Index
+ 1;
836 Handle the DHCPv6 offer packet.
838 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
840 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
841 @retval EFI_NO_RESPONSE No response to the following request packet.
845 PxeBcHandleDhcp6Offer (
846 IN PXEBC_PRIVATE_DATA
*Private
849 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
851 PXEBC_OFFER_TYPE OfferType
;
856 ASSERT (Private
->SelectIndex
> 0);
857 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
858 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
859 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
860 Status
= EFI_SUCCESS
;
862 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
864 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
866 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
867 Status
= EFI_NO_RESPONSE
;
869 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
871 if (Private
->IsProxyRecved
) {
873 // DhcpOnly offer is selected, so need try to request bootfilename.
876 if (Private
->IsOfferSorted
) {
878 // The proxy offer should be determined if select by default policy.
879 // IsOfferSorted means all offers are labeled by OfferIndex.
881 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
883 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
885 // Try all the cached ProxyBinl offer one by one to request bootfilename.
887 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
889 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
890 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
894 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
895 Status
= EFI_NO_RESPONSE
;
899 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
901 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
905 // The proxy offer should not be determined if select by received order.
907 Status
= EFI_NO_RESPONSE
;
909 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
911 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
913 if (!IS_PROXY_OFFER (OfferType
)) {
915 // Skip non proxy dhcp offers.
920 if (OfferType
== PxeOfferTypeProxyBinl
) {
922 // Try all the cached ProxyBinl offer one by one to request bootfilename.
924 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
929 Private
->SelectProxyType
= OfferType
;
931 Status
= EFI_SUCCESS
;
936 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
938 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
940 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
944 // Othewise, the bootfilename must be included in DhcpOnly offer.
946 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
950 if (!EFI_ERROR (Status
)) {
952 // All PXE boot information is ready by now.
954 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
955 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
963 Unregister the address by Ip6Config protocol.
965 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
969 PxeBcUnregisterIp6Address (
970 IN PXEBC_PRIVATE_DATA
*Private
973 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
975 // PXE driver change the policy of IP6 driver, it's a chance to recover.
976 // Keep the point and there is no enough requirements to do recovery.
983 Register the ready address by Ip6Config protocol.
985 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
986 @param[in] Address The pointer to the ready address.
988 @retval EFI_SUCCESS Registered the address succesfully.
989 @retval Others Failed to register the address.
993 PxeBcRegisterIp6Address (
994 IN PXEBC_PRIVATE_DATA
*Private
,
995 IN EFI_IPv6_ADDRESS
*Address
998 EFI_IP6_PROTOCOL
*Ip6
;
999 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1000 EFI_IP6_CONFIG_POLICY Policy
;
1001 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1003 EFI_EVENT TimeOutEvt
;
1004 EFI_EVENT MappedEvt
;
1007 Status
= EFI_SUCCESS
;
1010 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1011 Ip6Cfg
= Private
->Ip6Cfg
;
1014 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1015 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1018 // Get and store the current policy of IP6 driver.
1020 Status
= Ip6Cfg
->GetData (
1022 Ip6ConfigDataTypePolicy
,
1026 if (EFI_ERROR (Status
)) {
1031 // There is no channel between IP6 and PXE driver about address setting,
1032 // so it has to set the new address by Ip6ConfigProtocol manually.
1034 Policy
= Ip6ConfigPolicyManual
;
1035 Status
= Ip6Cfg
->SetData (
1037 Ip6ConfigDataTypePolicy
,
1038 sizeof(EFI_IP6_CONFIG_POLICY
),
1041 if (EFI_ERROR (Status
)) {
1043 // There is no need to recover later.
1045 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1050 // Create a timer as setting address timeout event since DAD in IP6 driver.
1052 Status
= gBS
->CreateEvent (
1059 if (EFI_ERROR (Status
)) {
1064 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1066 Status
= gBS
->CreateEvent (
1070 &Private
->IsAddressOk
,
1073 if (EFI_ERROR (Status
)) {
1077 Status
= Ip6Cfg
->RegisterDataNotify (
1079 Ip6ConfigDataTypeManualAddress
,
1082 if (EFI_ERROR(Status
)) {
1086 Status
= Ip6Cfg
->SetData (
1088 Ip6ConfigDataTypeManualAddress
,
1089 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1092 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1097 // Start the 5 secondes timer to wait for setting address.
1099 Status
= EFI_NO_MAPPING
;
1100 gBS
->SetTimer (TimeOutEvt
, TimerRelative
, PXEBC_DHCP6_MAPPING_TIMEOUT
);
1102 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1104 if (Private
->IsAddressOk
) {
1105 Status
= EFI_SUCCESS
;
1111 if (MappedEvt
!= NULL
) {
1112 Ip6Cfg
->UnregisterDataNotify (
1114 Ip6ConfigDataTypeManualAddress
,
1117 gBS
->CloseEvent (MappedEvt
);
1119 if (TimeOutEvt
!= NULL
) {
1120 gBS
->CloseEvent (TimeOutEvt
);
1127 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1128 to intercept events that occurred in the configuration process.
1130 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1131 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1132 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1133 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1135 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1136 @param[out] NewPacket The packet that is used to replace the Packet above.
1138 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1139 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1140 driver will continue to wait for more packets.
1141 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1146 PxeBcDhcp6CallBack (
1147 IN EFI_DHCP6_PROTOCOL
*This
,
1149 IN EFI_DHCP6_STATE CurrentState
,
1150 IN EFI_DHCP6_EVENT Dhcp6Event
,
1151 IN EFI_DHCP6_PACKET
*Packet
,
1152 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1155 PXEBC_PRIVATE_DATA
*Private
;
1156 EFI_PXE_BASE_CODE_MODE
*Mode
;
1157 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1158 EFI_DHCP6_PACKET
*SelectAd
;
1162 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1163 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1164 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1165 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1166 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1170 ASSERT (Packet
!= NULL
);
1172 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1173 Mode
= Private
->PxeBc
.Mode
;
1174 Callback
= Private
->PxeBcCallback
;
1177 // Callback to user when any traffic ocurred if has.
1179 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1180 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1181 Status
= Callback
->Callback (
1186 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1188 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1193 Status
= EFI_SUCCESS
;
1195 switch (Dhcp6Event
) {
1197 case Dhcp6SendSolicit
:
1199 // Cache the dhcp discover packet to mode data directly.
1201 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1204 case Dhcp6RcvdAdvertise
:
1205 Status
= EFI_NOT_READY
;
1206 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1208 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1209 // the OfferIndex and OfferCount.
1211 PxeBcCacheDhcp6Offer (Private
, Packet
);
1215 case Dhcp6SendRequest
:
1217 // Store the request packet as seed packet for discover.
1219 if (Private
->Dhcp6Request
!= NULL
) {
1220 FreePool (Private
->Dhcp6Request
);
1222 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1223 if (Private
->Dhcp6Request
!= NULL
) {
1224 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1228 case Dhcp6SelectAdvertise
:
1230 // Select offer by the default policy or by order, and record the SelectIndex
1231 // and SelectProxyType.
1233 PxeBcSelectDhcp6Offer (Private
);
1235 if (Private
->SelectIndex
== 0) {
1236 Status
= EFI_ABORTED
;
1238 ASSERT (NewPacket
!= NULL
);
1239 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1240 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1241 ASSERT (*NewPacket
!= NULL
);
1242 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1246 case Dhcp6RcvdReply
:
1248 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1249 // without verification.
1251 ASSERT (Private
->SelectIndex
!= 0);
1252 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1264 Build and send out the request packet for the bootfile, and parse the reply.
1266 @param[in] Private The pointer to PxeBc private data.
1267 @param[in] Type PxeBc option boot item type.
1268 @param[in] Layer The pointer to option boot item layer.
1269 @param[in] UseBis Use BIS or not.
1270 @param[in] DestIp The pointer to the server address.
1272 @retval EFI_SUCCESS Successfully discovered the boot file.
1273 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1274 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1275 @retval Others Failed to discover the boot file.
1279 PxeBcDhcp6Discover (
1280 IN PXEBC_PRIVATE_DATA
*Private
,
1284 IN EFI_IP_ADDRESS
*DestIp
1287 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
1288 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
1289 EFI_PXE_BASE_CODE_MODE
*Mode
;
1290 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1291 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
1293 EFI_DHCP6_PACKET
*Request
;
1295 EFI_DHCP6_PACKET
*Reply
;
1305 PxeBc
= &Private
->PxeBc
;
1307 Request
= Private
->Dhcp6Request
;
1308 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
1309 DestPort
= PXEBC_BS_DISCOVER_PORT
;
1312 if (!UseBis
&& Layer
!= NULL
) {
1313 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1316 if (Request
== NULL
) {
1317 return EFI_DEVICE_ERROR
;
1320 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
1321 if (Discover
== NULL
) {
1322 return EFI_OUT_OF_RESOURCES
;
1326 // Build the discover packet by the cached request packet before.
1328 Xid
= NET_RANDOM (NetRandomInitSeed ());
1329 Discover
->TransactionId
= HTONL (Xid
);
1330 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
1331 RequestOpt
= Request
->Dhcp6
.Option
;
1332 DiscoverOpt
= Discover
->DhcpOptions
;
1333 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
1334 RequestLen
= DiscoverLen
;
1336 while (RequestLen
< Request
->Length
) {
1337 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
1338 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
1339 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
1340 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
1342 // Copy all the options except IA option.
1344 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
1345 DiscoverOpt
+= (OpLen
+ 4);
1346 DiscoverLen
+= (OpLen
+ 4);
1348 RequestOpt
+= (OpLen
+ 4);
1349 RequestLen
+= (OpLen
+ 4);
1352 Status
= PxeBc
->UdpWrite (
1358 &Private
->StationIp
,
1365 if (EFI_ERROR (Status
)) {
1370 // Cache the right PXE reply packet here, set valid flag later.
1371 // Especially for PXE discover packet, store it into mode data here.
1373 if (Private
->IsDoDiscover
) {
1374 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
1375 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
1377 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1379 ReadSize
= (UINTN
) Reply
->Size
;
1381 Status
= PxeBc
->UdpRead (
1384 &Private
->StationIp
,
1391 (VOID
*) &Reply
->Dhcp6
1393 if (EFI_ERROR (Status
)) {
1402 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1404 @param[in] Private The pointer to PxeBc private data.
1405 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1407 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1408 @retval Others Failed to finish the S.A.R.R. process.
1413 IN PXEBC_PRIVATE_DATA
*Private
,
1414 IN EFI_DHCP6_PROTOCOL
*Dhcp6
1417 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1418 EFI_DHCP6_CONFIG_DATA Config
;
1419 EFI_DHCP6_MODE_DATA Mode
;
1420 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
1421 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
1422 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
1426 Status
= EFI_SUCCESS
;
1427 PxeMode
= Private
->PxeBc
.Mode
;
1430 // Build option list for the request packet.
1432 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
1433 ASSERT (OptCount
> 0);
1435 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
1436 if (Retransmit
== NULL
) {
1437 return EFI_OUT_OF_RESOURCES
;
1440 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
1441 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1443 Config
.OptionCount
= OptCount
;
1444 Config
.OptionList
= OptList
;
1445 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
1446 Config
.CallbackContext
= Private
;
1447 Config
.IaInfoEvent
= NULL
;
1448 Config
.RapidCommit
= FALSE
;
1449 Config
.ReconfigureAccept
= FALSE
;
1450 Config
.IaDescriptor
.IaId
= 1;
1451 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
1452 Config
.SolicitRetransmission
= Retransmit
;
1453 Retransmit
->Irt
= 4;
1454 Retransmit
->Mrc
= 4;
1455 Retransmit
->Mrt
= 32;
1456 Retransmit
->Mrd
= 60;
1459 // Configure the DHCPv6 instance for PXE boot.
1461 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
1462 if (EFI_ERROR (Status
)) {
1463 FreePool (Retransmit
);
1468 // Initialize the record fields for DHCPv6 offer in private data.
1470 Private
->IsProxyRecved
= FALSE
;
1471 Private
->OfferNum
= 0;
1472 Private
->SelectIndex
= 0;
1473 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1474 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1478 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1480 Status
= Dhcp6
->Start (Dhcp6
);
1481 if (EFI_ERROR (Status
)) {
1482 if (Status
== EFI_ICMP_ERROR
) {
1483 PxeMode
->IcmpErrorReceived
= TRUE
;
1485 Dhcp6
->Configure (Dhcp6
, NULL
);
1490 // Get the acquired IPv6 address and store them.
1492 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1493 if (EFI_ERROR (Status
)) {
1494 Dhcp6
->Stop (Dhcp6
);
1498 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1499 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1500 CopyMem (&PxeMode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1502 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1503 if (EFI_ERROR (Status
)) {
1504 Dhcp6
->Stop (Dhcp6
);
1508 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, NULL
);
1509 if (EFI_ERROR (Status
)) {
1510 PxeBcUnregisterIp6Address (Private
);
1511 Dhcp6
->Stop (Dhcp6
);
1516 // Check the selected offer whether BINL retry is needed.
1518 Status
= PxeBcHandleDhcp6Offer (Private
);
1519 if (EFI_ERROR (Status
)) {
1520 PxeBcUnregisterIp6Address (Private
);
1521 Dhcp6
->Stop (Dhcp6
);
1525 AsciiPrint ("\n Station IP address is ");
1527 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);