2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "PxeBcImpl.h"
14 // Well-known multi-cast address defined in section-24.1 of rfc-3315
16 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
18 EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress
= {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
21 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
23 @param[in] Buffer The pointer to the option buffer.
24 @param[in] Length Length of the option buffer.
25 @param[in] OptTag The required option tag.
27 @retval NULL Failed to parse the required option.
28 @retval Others The postion of the required option in buffer.
31 EFI_DHCP6_PACKET_OPTION
*
32 PxeBcParseDhcp6Options (
38 EFI_DHCP6_PACKET_OPTION
*Option
;
41 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
45 // OpLen and OpCode here are both stored in network order.
47 while (Offset
< Length
) {
49 if (NTOHS (Option
->OpCode
) == OptTag
) {
54 Offset
+= (NTOHS(Option
->OpLen
) + 4);
55 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
63 Build the options buffer for the DHCPv6 request packet.
65 @param[in] Private The pointer to PxeBc private data.
66 @param[out] OptList The pointer to the option pointer array.
67 @param[in] Buffer The pointer to the buffer to contain the option list.
69 @return Index The count of the built-in options.
73 PxeBcBuildDhcp6Options (
74 IN PXEBC_PRIVATE_DATA
*Private
,
75 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
79 PXEBC_DHCP6_OPTION_ENTRY OptEnt
;
84 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
87 // Append client option request option
89 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ORO
);
90 OptList
[Index
]->OpLen
= HTONS (8);
91 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
92 OptEnt
.Oro
->OpCode
[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL
);
93 OptEnt
.Oro
->OpCode
[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM
);
94 OptEnt
.Oro
->OpCode
[2] = HTONS(DHCP6_OPT_DNS_SERVERS
);
95 OptEnt
.Oro
->OpCode
[3] = HTONS(DHCP6_OPT_VENDOR_CLASS
);
97 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
100 // Append client network device interface option
102 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
103 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
104 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
106 if (Private
->Nii
!= NULL
) {
107 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
108 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
109 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
111 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
112 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
113 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
117 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
120 // Append client system architecture option
122 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
123 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
124 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
125 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
126 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
128 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
131 // Append vendor class option to store the PXE class identifier.
133 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
134 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
135 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
136 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
137 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
139 &OptEnt
.VendorClass
->ClassId
,
140 DEFAULT_CLASS_ID_DATA
,
141 sizeof (PXEBC_CLASS_ID
)
143 PxeBcUintnToAscDecWithFormat (
144 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
145 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
146 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
149 if (Private
->Nii
!= NULL
) {
151 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
152 Private
->Nii
->StringId
,
153 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
155 PxeBcUintnToAscDecWithFormat (
156 Private
->Nii
->MajorVer
,
157 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
158 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
160 PxeBcUintnToAscDecWithFormat (
161 Private
->Nii
->MinorVer
,
162 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
163 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
174 Cache the DHCPv6 packet.
176 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
177 @param[in] Src The pointer to the DHCPv6 packet to be cached.
179 @retval EFI_SUCCESS Packet is copied.
180 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
184 PxeBcCacheDhcp6Packet (
185 IN EFI_DHCP6_PACKET
*Dst
,
186 IN EFI_DHCP6_PACKET
*Src
189 if (Dst
->Size
< Src
->Length
) {
190 return EFI_BUFFER_TOO_SMALL
;
193 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
194 Dst
->Length
= Src
->Length
;
200 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.
202 @param[in] Private Pointer to PxeBc private data.
203 @param[in] HostName Pointer to buffer containing hostname.
204 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
206 @retval EFI_SUCCESS Operation succeeded.
207 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
208 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
209 @retval Others Other errors as indicated.
214 IN PXEBC_PRIVATE_DATA
*Private
,
216 OUT EFI_IPv6_ADDRESS
*IpAddress
220 EFI_DNS6_PROTOCOL
*Dns6
;
221 EFI_DNS6_CONFIG_DATA Dns6ConfigData
;
222 EFI_DNS6_COMPLETION_TOKEN Token
;
223 EFI_HANDLE Dns6Handle
;
224 EFI_IPv6_ADDRESS
*DnsServerList
;
229 DnsServerList
= Private
->DnsServer
;
230 ZeroMem (&Token
, sizeof (EFI_DNS6_COMPLETION_TOKEN
));
233 // Create a DNSv6 child instance and get the protocol.
235 Status
= NetLibCreateServiceChild (
238 &gEfiDns6ServiceBindingProtocolGuid
,
241 if (EFI_ERROR (Status
)) {
245 Status
= gBS
->OpenProtocol (
247 &gEfiDns6ProtocolGuid
,
251 EFI_OPEN_PROTOCOL_BY_DRIVER
253 if (EFI_ERROR (Status
)) {
258 // Configure DNS6 instance for the DNS server address and protocol.
260 ZeroMem (&Dns6ConfigData
, sizeof (EFI_DNS6_CONFIG_DATA
));
261 Dns6ConfigData
.DnsServerCount
= 1;
262 Dns6ConfigData
.DnsServerList
= DnsServerList
;
263 Dns6ConfigData
.EnableDnsCache
= TRUE
;
264 Dns6ConfigData
.Protocol
= EFI_IP_PROTO_UDP
;
265 IP6_COPY_ADDRESS (&Dns6ConfigData
.StationIp
, &Private
->TmpStationIp
.v6
);
266 Status
= Dns6
->Configure (
270 if (EFI_ERROR (Status
)) {
274 Token
.Status
= EFI_NOT_READY
;
277 // Create event to set the IsDone flag when name resolution is finished.
279 Status
= gBS
->CreateEvent (
286 if (EFI_ERROR (Status
)) {
291 // Start asynchronous name resolution.
293 Status
= Dns6
->HostNameToIp (Dns6
, HostName
, &Token
);
294 if (EFI_ERROR (Status
)) {
303 // Name resolution is done, check result.
305 Status
= Token
.Status
;
306 if (!EFI_ERROR (Status
)) {
307 if (Token
.RspData
.H2AData
== NULL
) {
308 Status
= EFI_DEVICE_ERROR
;
311 if (Token
.RspData
.H2AData
->IpCount
== 0 || Token
.RspData
.H2AData
->IpList
== NULL
) {
312 Status
= EFI_DEVICE_ERROR
;
316 // We just return the first IPv6 address from DNS protocol.
318 IP6_COPY_ADDRESS (IpAddress
, Token
.RspData
.H2AData
->IpList
);
319 Status
= EFI_SUCCESS
;
325 if (Token
.Event
!= NULL
) {
326 gBS
->CloseEvent (Token
.Event
);
328 if (Token
.RspData
.H2AData
!= NULL
) {
329 if (Token
.RspData
.H2AData
->IpList
!= NULL
) {
330 FreePool (Token
.RspData
.H2AData
->IpList
);
332 FreePool (Token
.RspData
.H2AData
);
336 Dns6
->Configure (Dns6
, NULL
);
340 &gEfiDns6ProtocolGuid
,
346 if (Dns6Handle
!= NULL
) {
347 NetLibDestroyServiceChild (
350 &gEfiDns6ServiceBindingProtocolGuid
,
355 if (DnsServerList
!= NULL
) {
356 FreePool (DnsServerList
);
363 Parse the Boot File URL option.
365 @param[in] Private Pointer to PxeBc private data.
366 @param[out] FileName The pointer to the boot file name.
367 @param[in, out] SrvAddr The pointer to the boot server address.
368 @param[in] BootFile The pointer to the boot file URL option data.
369 @param[in] Length The length of the boot file URL option data.
371 @retval EFI_ABORTED User cancel operation.
372 @retval EFI_SUCCESS Selected the boot menu successfully.
373 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
377 PxeBcExtractBootFileUrl (
378 IN PXEBC_PRIVATE_DATA
*Private
,
379 OUT UINT8
**FileName
,
380 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
386 CHAR8
*BootFileNamePtr
;
388 UINT16 BootFileNameLen
;
391 CHAR8
*ServerAddressOption
;
392 CHAR8
*ServerAddress
;
395 BOOLEAN IpExpressedUrl
;
399 IpExpressedUrl
= TRUE
;
401 // The format of the Boot File URL option is:
404 // 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
405 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406 // | OPT_BOOTFILE_URL | option-len |
407 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409 // . bootfile-url (variable length) .
411 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
415 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be
416 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME
417 // As an example where the BOOTFILE_NAME is the EFI loader and
418 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
420 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
422 if (Length
<= PrefixLen
||
423 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
424 return EFI_NOT_FOUND
;
427 BootFile
= BootFile
+ PrefixLen
;
428 Length
= (UINT16
) (Length
- PrefixLen
);
430 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
431 if (TmpStr
== NULL
) {
432 return EFI_OUT_OF_RESOURCES
;
435 CopyMem (TmpStr
, BootFile
, Length
);
436 TmpStr
[Length
] = '\0';
439 // Get the part of SERVER_ADDRESS string.
441 ServerAddressOption
= TmpStr
;
442 if (*ServerAddressOption
== PXEBC_ADDR_START_DELIMITER
) {
443 ServerAddressOption
++;
444 ServerAddress
= ServerAddressOption
;
445 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
449 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
451 return EFI_INVALID_PARAMETER
;
454 *ServerAddress
= '\0';
457 // Convert the string of server address to Ipv6 address format and store it.
459 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
460 if (EFI_ERROR (Status
)) {
466 IpExpressedUrl
= FALSE
;
467 ServerAddress
= ServerAddressOption
;
468 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
472 if (*ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
474 return EFI_INVALID_PARAMETER
;
476 *ServerAddress
= '\0';
478 Len
= AsciiStrSize (ServerAddressOption
);
479 HostName
= AllocateZeroPool (Len
* sizeof (CHAR16
));
480 if (HostName
== NULL
) {
482 return EFI_OUT_OF_RESOURCES
;
484 AsciiStrToUnicodeStrS (
491 // Perform DNS resolution.
493 Status
= PxeBcDns6 (Private
,HostName
, SrvAddr
);
494 if (EFI_ERROR (Status
)) {
501 // Get the part of BOOTFILE_NAME string.
503 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
504 if (IpExpressedUrl
) {
505 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
507 return EFI_INVALID_PARAMETER
;
512 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
513 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
515 // Remove trailing mode=octet if present and ignore. All other modes are
516 // invalid for netboot6, so reject them.
518 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
519 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
521 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
523 return EFI_INVALID_PARAMETER
;
527 // Extract boot file name from URL.
529 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
530 if (BootFileName
== NULL
) {
532 return EFI_OUT_OF_RESOURCES
;
534 *FileName
= (UINT8
*) BootFileName
;
537 // Decode percent-encoding in boot file name.
539 while (*BootFileNamePtr
!= '\0') {
540 if (*BootFileNamePtr
== '%') {
541 TmpChar
= *(BootFileNamePtr
+ 3);
542 *(BootFileNamePtr
+ 3) = '\0';
543 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
545 *(BootFileNamePtr
+ 3) = TmpChar
;
546 BootFileNamePtr
+= 3;
548 *BootFileName
= *BootFileNamePtr
;
553 *BootFileName
= '\0';
563 Parse the Boot File Parameter option.
565 @param[in] BootFilePara The pointer to boot file parameter option data.
566 @param[out] BootFileSize The pointer to the parsed boot file size.
568 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
569 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
573 PxeBcExtractBootFileParam (
574 IN CHAR8
*BootFilePara
,
575 OUT UINT16
*BootFileSize
583 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
584 Length
= NTOHS (Length
);
587 // The BootFile Size should be 1~5 byte ASCII strings
589 if (Length
< 1 || Length
> 5) {
590 return EFI_NOT_FOUND
;
594 // Extract the value of BootFile Size.
596 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
598 for (Index
= 0; Index
< Length
; Index
++) {
599 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
600 return EFI_NOT_FOUND
;
603 Size
= (Size
+ Digit
) * 10;
607 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
608 return EFI_NOT_FOUND
;
611 *BootFileSize
= (UINT16
) Size
;
617 Parse the cached DHCPv6 packet, including all the options.
619 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
621 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
622 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
626 PxeBcParseDhcp6Packet (
627 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
630 EFI_DHCP6_PACKET
*Offer
;
631 EFI_DHCP6_PACKET_OPTION
**Options
;
632 EFI_DHCP6_PACKET_OPTION
*Option
;
633 PXEBC_OFFER_TYPE OfferType
;
634 BOOLEAN IsProxyOffer
;
638 UINT32 EnterpriseNum
;
642 Offer
= &Cache6
->Packet
.Offer
;
643 Options
= Cache6
->OptList
;
645 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
647 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
649 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
652 // OpLen and OpCode here are both stored in network order, since they are from original packet.
654 while (Offset
< Length
) {
656 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
657 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
658 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
660 // The server sends this option to inform the client about an URL to a boot file.
662 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
663 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
664 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
665 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
666 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
667 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
668 Options
[PXEBC_DHCP6_IDX_DNS_SERVER
] = Option
;
671 Offset
+= (NTOHS (Option
->OpLen
) + 4);
672 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
676 // The offer with assigned client address is NOT a proxy offer.
677 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
679 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
680 if (Option
!= NULL
) {
681 Option
= PxeBcParseDhcp6Options (
683 NTOHS (Option
->OpLen
),
684 DHCP6_OPT_STATUS_CODE
686 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
687 IsProxyOffer
= FALSE
;
692 // The offer with "PXEClient" is a pxe offer.
694 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
695 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
697 if (Option
!= NULL
&&
698 NTOHS(Option
->OpLen
) >= 13 &&
699 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
700 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
705 // Determine offer type of the dhcp6 packet.
709 // It's a binl offer only with PXEClient.
711 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
714 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
716 OfferType
= PxeOfferTypeDhcpOnly
;
719 Cache6
->OfferType
= OfferType
;
726 Cache the DHCPv6 ack packet, and parse it on demand.
728 @param[in] Private The pointer to PxeBc private data.
729 @param[in] Ack The pointer to the DHCPv6 ack packet.
730 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
732 @retval EFI_SUCCESS Cache and parse the packet successfully.
733 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
738 IN PXEBC_PRIVATE_DATA
*Private
,
739 IN EFI_DHCP6_PACKET
*Ack
,
743 EFI_PXE_BASE_CODE_MODE
*Mode
;
746 Mode
= Private
->PxeBc
.Mode
;
748 Status
= PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
749 if (EFI_ERROR (Status
)) {
755 // Parse the ack packet and store it into mode data if needed.
757 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
758 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
759 Mode
->DhcpAckReceived
= TRUE
;
767 Cache the DHCPv6 proxy offer packet according to the received order.
769 @param[in] Private The pointer to PxeBc private data.
770 @param[in] OfferIndex The received order of offer packets.
772 @retval EFI_SUCCESS Cache and parse the packet successfully.
773 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
777 PxeBcCopyDhcp6Proxy (
778 IN PXEBC_PRIVATE_DATA
*Private
,
782 EFI_PXE_BASE_CODE_MODE
*Mode
;
783 EFI_DHCP6_PACKET
*Offer
;
786 ASSERT (OfferIndex
< Private
->OfferNum
);
787 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
789 Mode
= Private
->PxeBc
.Mode
;
790 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
793 // Cache the proxy offer packet and parse it.
795 Status
= PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
796 if (EFI_ERROR(Status
)) {
799 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
802 // Store this packet into mode data.
804 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
805 Mode
->ProxyOfferReceived
= TRUE
;
811 Seek the address of the first byte of the option header.
813 @param[in] Buf The pointer to the buffer.
814 @param[in] SeekLen The length to seek.
815 @param[in] OptType The option type.
817 @retval NULL If it failed to seek the option.
818 @retval others The position to the option.
822 PxeBcDhcp6SeekOption (
836 while (Cursor
< Buf
+ SeekLen
) {
837 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
838 if (OpCode
== HTONS (OptType
)) {
842 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
843 Cursor
+= (DataLen
+ 4);
851 Build and send out the request packet for the bootfile, and parse the reply.
853 @param[in] Private The pointer to PxeBc private data.
854 @param[in] Index PxeBc option boot item type.
856 @retval EFI_SUCCESS Successfully discovered the boot file.
857 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
858 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
859 @retval Others Failed to discover the boot file.
863 PxeBcRequestBootService (
864 IN PXEBC_PRIVATE_DATA
*Private
,
868 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
869 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
870 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
871 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
873 EFI_DHCP6_PACKET
*Request
;
875 EFI_DHCP6_PACKET
*Reply
;
883 EFI_DHCP6_PACKET
*IndexOffer
;
886 PxeBc
= &Private
->PxeBc
;
887 Request
= Private
->Dhcp6Request
;
888 IndexOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
889 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
890 DestPort
= PXEBC_BS_DISCOVER_PORT
;
893 if (Request
== NULL
) {
894 return EFI_DEVICE_ERROR
;
897 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
898 if (Discover
== NULL
) {
899 return EFI_OUT_OF_RESOURCES
;
903 // Build the request packet by the cached request packet before.
905 Discover
->TransactionId
= IndexOffer
->Dhcp6
.Header
.TransactionId
;
906 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
907 RequestOpt
= Request
->Dhcp6
.Option
;
908 DiscoverOpt
= Discover
->DhcpOptions
;
909 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
910 RequestLen
= DiscoverLen
;
913 // Find Server ID Option from ProxyOffer.
915 if (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
) {
916 Option
= PxeBcDhcp6SeekOption (
917 IndexOffer
->Dhcp6
.Option
,
918 IndexOffer
->Length
- 4,
921 if (Option
== NULL
) {
922 return EFI_NOT_FOUND
;
926 // Add Server ID Option.
928 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
929 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
930 DiscoverOpt
+= (OpLen
+ 4);
931 DiscoverLen
+= (OpLen
+ 4);
934 while (RequestLen
< Request
->Length
) {
935 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
936 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
937 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
938 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
939 OpCode
!= DHCP6_OPT_SERVER_ID
942 // Copy all the options except IA option and Server ID
944 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
945 DiscoverOpt
+= (OpLen
+ 4);
946 DiscoverLen
+= (OpLen
+ 4);
948 RequestOpt
+= (OpLen
+ 4);
949 RequestLen
+= (OpLen
+ 4);
953 // Update Elapsed option in the package
955 Option
= PxeBcDhcp6SeekOption (
956 Discover
->DhcpOptions
,
957 (UINT32
)(RequestLen
- 4),
958 DHCP6_OPT_ELAPSED_TIME
960 if (Option
!= NULL
) {
961 CalcElapsedTime (Private
);
962 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
965 Status
= PxeBc
->UdpWrite (
979 if (EFI_ERROR (Status
)) {
984 // Cache the right PXE reply packet here, set valid flag later.
985 // Especially for PXE discover packet, store it into mode data here.
987 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
988 ReadSize
= (UINTN
) Reply
->Size
;
991 // Start Udp6Read instance
993 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
994 if (EFI_ERROR (Status
)) {
998 Status
= PxeBc
->UdpRead (
1000 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
1008 (VOID
*) &Reply
->Dhcp6
1011 // Stop Udp6Read instance
1013 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1015 if (EFI_ERROR (Status
)) {
1022 Reply
->Length
= (UINT32
) ReadSize
;
1027 if (Discover
!= NULL
) {
1028 FreePool (Discover
);
1036 Retry to request bootfile name by the BINL offer.
1038 @param[in] Private The pointer to PxeBc private data.
1039 @param[in] Index The received order of offer packets.
1041 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
1042 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
1046 PxeBcRetryDhcp6Binl (
1047 IN PXEBC_PRIVATE_DATA
*Private
,
1051 EFI_PXE_BASE_CODE_MODE
*Mode
;
1052 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
1053 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1056 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1057 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
1058 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
1060 Mode
= Private
->PxeBc
.Mode
;
1061 Private
->IsDoDiscover
= FALSE
;
1062 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
1063 if (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1065 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
1068 &Private
->ServerIp
.v6
,
1069 &mAllDhcpRelayAndServersAddress
,
1070 sizeof (EFI_IPv6_ADDRESS
)
1073 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1075 // Parse out the next server address from the last offer, and store it
1077 Status
= PxeBcExtractBootFileUrl (
1079 &Private
->BootFileName
,
1080 &Private
->ServerIp
.v6
,
1081 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
1082 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
1084 if (EFI_ERROR (Status
)) {
1090 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
1092 Status
= PxeBcRequestBootService (Private
, Index
);
1094 if (EFI_ERROR (Status
)) {
1098 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
1099 Status
= PxeBcParseDhcp6Packet (Cache6
);
1100 if (EFI_ERROR (Status
)) {
1104 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
1105 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
1106 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1108 // This BINL ack doesn't have discovery option set or multicast option set
1109 // or bootfile name specified.
1111 return EFI_DEVICE_ERROR
;
1114 Mode
->ProxyOfferReceived
= TRUE
;
1116 &Mode
->ProxyOffer
.Dhcpv6
,
1117 &Cache6
->Packet
.Offer
.Dhcp6
,
1118 Cache6
->Packet
.Offer
.Length
1126 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
1128 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1129 @param[in] RcvdOffer The pointer to the received offer packet.
1131 @retval EFI_SUCCESS Cache and parse the packet successfully.
1132 @retval Others Operation failed.
1135 PxeBcCacheDhcp6Offer (
1136 IN PXEBC_PRIVATE_DATA
*Private
,
1137 IN EFI_DHCP6_PACKET
*RcvdOffer
1140 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1141 EFI_DHCP6_PACKET
*Offer
;
1142 PXEBC_OFFER_TYPE OfferType
;
1145 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
1146 Offer
= &Cache6
->Packet
.Offer
;
1149 // Cache the content of DHCPv6 packet firstly.
1151 Status
= PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
1152 if (EFI_ERROR (Status
)) {
1157 // Validate the DHCPv6 packet, and parse the options and offer type.
1159 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
1164 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
1166 OfferType
= Cache6
->OfferType
;
1167 ASSERT (OfferType
< PxeOfferTypeMax
);
1168 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
1170 if (IS_PROXY_OFFER (OfferType
)) {
1172 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
1174 Private
->IsProxyRecved
= TRUE
;
1176 if (OfferType
== PxeOfferTypeProxyBinl
) {
1178 // Cache all proxy BINL offers.
1180 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1181 Private
->OfferCount
[OfferType
]++;
1182 } else if ((OfferType
== PxeOfferTypeProxyPxe10
|| OfferType
== PxeOfferTypeProxyWfm11a
) &&
1183 Private
->OfferCount
[OfferType
] < 1) {
1185 // Only cache the first PXE10/WFM11a offer, and discard the others.
1187 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
1188 Private
->OfferCount
[OfferType
] = 1;
1194 // It's a DHCPv6 offer with yiaddr, and cache them all.
1196 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1197 Private
->OfferCount
[OfferType
]++;
1200 Private
->OfferNum
++;
1207 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
1209 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1213 PxeBcSelectDhcp6Offer (
1214 IN PXEBC_PRIVATE_DATA
*Private
1219 PXEBC_OFFER_TYPE OfferType
;
1221 Private
->SelectIndex
= 0;
1223 if (Private
->IsOfferSorted
) {
1225 // Select offer by default policy.
1227 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1229 // 1. DhcpPxe10 offer
1231 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
1233 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
1235 // 2. DhcpWfm11a offer
1237 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1239 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1240 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1242 // 3. DhcpOnly offer and ProxyPxe10 offer.
1244 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1245 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1247 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1248 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1250 // 4. DhcpOnly offer and ProxyWfm11a offer.
1252 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1253 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1255 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1257 // 5. DhcpBinl offer.
1259 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1261 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1262 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1264 // 6. DhcpOnly offer and ProxyBinl offer.
1266 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1267 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1271 // 7. DhcpOnly offer with bootfilename.
1273 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1274 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1275 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1276 Private
->SelectIndex
= OfferIndex
+ 1;
1283 // Select offer by received order.
1285 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1287 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1289 if (IS_PROXY_OFFER (OfferType
)) {
1291 // Skip proxy offers
1296 if (!Private
->IsProxyRecved
&&
1297 OfferType
== PxeOfferTypeDhcpOnly
&&
1298 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1300 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1305 Private
->SelectIndex
= Index
+ 1;
1313 Handle the DHCPv6 offer packet.
1315 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1317 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1318 @retval EFI_NO_RESPONSE No response to the following request packet.
1319 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1320 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1324 PxeBcHandleDhcp6Offer (
1325 IN PXEBC_PRIVATE_DATA
*Private
1328 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1330 PXEBC_OFFER_TYPE OfferType
;
1335 ASSERT (Private
->SelectIndex
> 0);
1336 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1337 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1338 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1339 Status
= EFI_SUCCESS
;
1342 // First try to cache DNS server address if DHCP6 offer provides.
1344 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1345 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1346 if (Private
->DnsServer
== NULL
) {
1347 return EFI_OUT_OF_RESOURCES
;
1349 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1352 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1354 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1356 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1357 Status
= EFI_NO_RESPONSE
;
1359 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1361 if (Private
->IsProxyRecved
) {
1363 // DhcpOnly offer is selected, so need try to request bootfilename.
1366 if (Private
->IsOfferSorted
) {
1368 // The proxy offer should be determined if select by default policy.
1369 // IsOfferSorted means all offers are labeled by OfferIndex.
1371 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1373 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1375 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1377 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1379 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1380 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1384 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1385 Status
= EFI_NO_RESPONSE
;
1389 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1391 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1395 // The proxy offer should not be determined if select by received order.
1397 Status
= EFI_NO_RESPONSE
;
1399 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1401 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1403 if (!IS_PROXY_OFFER (OfferType
)) {
1405 // Skip non proxy dhcp offers.
1410 if (OfferType
== PxeOfferTypeProxyBinl
) {
1412 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1414 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1419 Private
->SelectProxyType
= OfferType
;
1421 Status
= EFI_SUCCESS
;
1426 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1428 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1430 Status
= PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1434 // Othewise, the bootfilename must be included in DhcpOnly offer.
1436 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1440 if (!EFI_ERROR (Status
)) {
1442 // All PXE boot information is ready by now.
1444 Status
= PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1445 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1453 Unregister the address by Ip6Config protocol.
1455 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1459 PxeBcUnregisterIp6Address (
1460 IN PXEBC_PRIVATE_DATA
*Private
1463 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1465 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1466 // Keep the point and there is no enough requirements to do recovery.
1472 Check whether IP driver could route the message which will be sent to ServerIp address.
1474 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1475 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1477 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1478 @param[in] TimeOutInSecond Timeout value in seconds.
1479 @param[out] GatewayAddr Pointer to store the gateway IP address.
1481 @retval EFI_SUCCESS Found a valid gateway address successfully.
1482 @retval EFI_TIMEOUT The operation is time out.
1483 @retval Other Unexpect error happened.
1487 PxeBcCheckRouteTable (
1488 IN PXEBC_PRIVATE_DATA
*Private
,
1489 IN UINTN TimeOutInSecond
,
1490 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1494 EFI_IP6_PROTOCOL
*Ip6
;
1495 EFI_IP6_MODE_DATA Ip6ModeData
;
1497 EFI_EVENT TimeOutEvt
;
1499 BOOLEAN GatewayIsFound
;
1501 ASSERT (GatewayAddr
!= NULL
);
1502 ASSERT (Private
!= NULL
);
1505 GatewayIsFound
= FALSE
;
1508 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1511 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1512 if (EFI_ERROR (Status
)) {
1517 // Find out the gateway address which can route the message which send to ServerIp.
1519 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1520 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1521 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1522 GatewayIsFound
= TRUE
;
1527 if (Ip6ModeData
.AddressList
!= NULL
) {
1528 FreePool (Ip6ModeData
.AddressList
);
1530 if (Ip6ModeData
.GroupTable
!= NULL
) {
1531 FreePool (Ip6ModeData
.GroupTable
);
1533 if (Ip6ModeData
.RouteTable
!= NULL
) {
1534 FreePool (Ip6ModeData
.RouteTable
);
1536 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1537 FreePool (Ip6ModeData
.NeighborCache
);
1539 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1540 FreePool (Ip6ModeData
.PrefixTable
);
1542 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1543 FreePool (Ip6ModeData
.IcmpTypeList
);
1546 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
1553 // Delay 1 second then recheck it again.
1555 if (TimeOutEvt
== NULL
) {
1556 Status
= gBS
->CreateEvent (
1563 if (EFI_ERROR (Status
)) {
1568 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
1569 if (EFI_ERROR (Status
)) {
1572 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1578 if (TimeOutEvt
!= NULL
) {
1579 gBS
->CloseEvent (TimeOutEvt
);
1582 if (GatewayIsFound
) {
1583 Status
= EFI_SUCCESS
;
1584 } else if (RetryCount
== TimeOutInSecond
) {
1585 Status
= EFI_TIMEOUT
;
1592 Register the ready station address and gateway by Ip6Config protocol.
1594 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1595 @param[in] Address The pointer to the ready address.
1597 @retval EFI_SUCCESS Registered the address succesfully.
1598 @retval Others Failed to register the address.
1602 PxeBcRegisterIp6Address (
1603 IN PXEBC_PRIVATE_DATA
*Private
,
1604 IN EFI_IPv6_ADDRESS
*Address
1607 EFI_IP6_PROTOCOL
*Ip6
;
1608 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1609 EFI_IP6_CONFIG_POLICY Policy
;
1610 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1611 EFI_IPv6_ADDRESS GatewayAddr
;
1613 EFI_EVENT MappedEvt
;
1616 EFI_IPv6_ADDRESS
*Ip6Addr
;
1619 Status
= EFI_SUCCESS
;
1622 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1623 Ip6Cfg
= Private
->Ip6Cfg
;
1627 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1628 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1630 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1631 if (EFI_ERROR (Status
)) {
1636 // Retrieve the gateway address from IP6 route table.
1638 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1639 if (EFI_ERROR (Status
)) {
1644 // There is no channel between IP6 and PXE driver about address setting,
1645 // so it has to set the new address by Ip6ConfigProtocol manually.
1647 Policy
= Ip6ConfigPolicyManual
;
1648 Status
= Ip6Cfg
->SetData (
1650 Ip6ConfigDataTypePolicy
,
1651 sizeof(EFI_IP6_CONFIG_POLICY
),
1654 if (EFI_ERROR (Status
)) {
1656 // There is no need to recover later.
1658 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1663 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1665 Status
= gBS
->CreateEvent (
1669 &Private
->IsAddressOk
,
1672 if (EFI_ERROR (Status
)) {
1676 Private
->IsAddressOk
= FALSE
;
1677 Status
= Ip6Cfg
->RegisterDataNotify (
1679 Ip6ConfigDataTypeManualAddress
,
1682 if (EFI_ERROR(Status
)) {
1686 Status
= Ip6Cfg
->SetData (
1688 Ip6ConfigDataTypeManualAddress
,
1689 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1692 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1694 } else if (Status
== EFI_NOT_READY
) {
1696 // Poll the network until the asynchronous process is finished.
1698 while (!Private
->IsAddressOk
) {
1702 // Check whether the IP6 address setting is successed.
1705 Status
= Ip6Cfg
->GetData (
1707 Ip6ConfigDataTypeManualAddress
,
1711 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
1712 Status
= EFI_DEVICE_ERROR
;
1716 Ip6Addr
= AllocatePool (DataSize
);
1717 if (Ip6Addr
== NULL
) {
1718 return EFI_OUT_OF_RESOURCES
;
1720 Status
= Ip6Cfg
->GetData (
1722 Ip6ConfigDataTypeManualAddress
,
1726 if (EFI_ERROR (Status
)) {
1727 Status
= EFI_DEVICE_ERROR
;
1731 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1732 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1736 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1737 Status
= EFI_ABORTED
;
1743 // Set the default gateway address back if needed.
1745 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1746 Status
= Ip6Cfg
->SetData (
1748 Ip6ConfigDataTypeGateway
,
1749 sizeof (EFI_IPv6_ADDRESS
),
1752 if (EFI_ERROR (Status
)) {
1758 if (MappedEvt
!= NULL
) {
1759 Ip6Cfg
->UnregisterDataNotify (
1761 Ip6ConfigDataTypeManualAddress
,
1764 gBS
->CloseEvent (MappedEvt
);
1766 if (Ip6Addr
!= NULL
) {
1773 Set the IP6 policy to Automatic.
1775 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1777 @retval EFI_SUCCESS Switch the IP policy succesfully.
1778 @retval Others Unexpect error happened.
1783 IN PXEBC_PRIVATE_DATA
*Private
1786 EFI_IP6_CONFIG_POLICY Policy
;
1788 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1791 Ip6Cfg
= Private
->Ip6Cfg
;
1792 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1795 // Get and store the current policy of IP6 driver.
1797 Status
= Ip6Cfg
->GetData (
1799 Ip6ConfigDataTypePolicy
,
1803 if (EFI_ERROR (Status
)) {
1807 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1808 Policy
= Ip6ConfigPolicyAutomatic
;
1809 Status
= Ip6Cfg
->SetData (
1811 Ip6ConfigDataTypePolicy
,
1812 sizeof(EFI_IP6_CONFIG_POLICY
),
1815 if (EFI_ERROR (Status
)) {
1817 // There is no need to recover later.
1819 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1827 This function will register the station IP address and flush IP instance to start using the new IP address.
1829 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1831 @retval EFI_SUCCESS The new IP address has been configured successfully.
1832 @retval Others Failed to configure the address.
1836 PxeBcSetIp6Address (
1837 IN PXEBC_PRIVATE_DATA
*Private
1841 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1843 Dhcp6
= Private
->Dhcp6
;
1845 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1846 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1848 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1849 if (EFI_ERROR (Status
)) {
1850 Dhcp6
->Stop (Dhcp6
);
1854 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1855 if (EFI_ERROR (Status
)) {
1856 PxeBcUnregisterIp6Address (Private
);
1857 Dhcp6
->Stop (Dhcp6
);
1861 AsciiPrint ("\n Station IP address is ");
1862 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1868 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1869 to intercept events that occurred in the configuration process.
1871 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1872 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1873 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1874 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1876 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1877 @param[out] NewPacket The packet that is used to replace the Packet above.
1879 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1880 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1881 driver will continue to wait for more packets.
1882 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1887 PxeBcDhcp6CallBack (
1888 IN EFI_DHCP6_PROTOCOL
*This
,
1890 IN EFI_DHCP6_STATE CurrentState
,
1891 IN EFI_DHCP6_EVENT Dhcp6Event
,
1892 IN EFI_DHCP6_PACKET
*Packet
,
1893 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1896 PXEBC_PRIVATE_DATA
*Private
;
1897 EFI_PXE_BASE_CODE_MODE
*Mode
;
1898 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1899 EFI_DHCP6_PACKET
*SelectAd
;
1903 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1904 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1905 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1906 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1907 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1911 ASSERT (Packet
!= NULL
);
1913 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1914 Mode
= Private
->PxeBc
.Mode
;
1915 Callback
= Private
->PxeBcCallback
;
1918 // Callback to user when any traffic ocurred if has.
1920 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1921 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1922 Status
= Callback
->Callback (
1927 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1929 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1934 Status
= EFI_SUCCESS
;
1936 switch (Dhcp6Event
) {
1938 case Dhcp6SendSolicit
:
1939 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1941 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1943 Status
= EFI_ABORTED
;
1948 // Record the first Solicate msg time
1950 if (Private
->SolicitTimes
== 0) {
1951 CalcElapsedTime (Private
);
1952 Private
->SolicitTimes
++;
1955 // Cache the dhcp discover packet to mode data directly.
1957 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1960 case Dhcp6RcvdAdvertise
:
1961 Status
= EFI_NOT_READY
;
1962 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1964 // Ignore the incoming packets which exceed the maximum length.
1968 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1970 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1971 // the OfferIndex and OfferCount.
1973 PxeBcCacheDhcp6Offer (Private
, Packet
);
1977 case Dhcp6SendRequest
:
1978 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1980 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1982 Status
= EFI_ABORTED
;
1987 // Store the request packet as seed packet for discover.
1989 if (Private
->Dhcp6Request
!= NULL
) {
1990 FreePool (Private
->Dhcp6Request
);
1992 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1993 if (Private
->Dhcp6Request
!= NULL
) {
1994 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1998 case Dhcp6SelectAdvertise
:
2000 // Select offer by the default policy or by order, and record the SelectIndex
2001 // and SelectProxyType.
2003 PxeBcSelectDhcp6Offer (Private
);
2005 if (Private
->SelectIndex
== 0) {
2006 Status
= EFI_ABORTED
;
2008 ASSERT (NewPacket
!= NULL
);
2009 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
2010 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
2011 ASSERT (*NewPacket
!= NULL
);
2012 if (*NewPacket
== NULL
) {
2015 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
2019 case Dhcp6RcvdReply
:
2021 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
2022 // without verification.
2024 ASSERT (Private
->SelectIndex
!= 0);
2025 Status
= PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
2026 if (EFI_ERROR (Status
)) {
2027 Status
= EFI_ABORTED
;
2040 Build and send out the request packet for the bootfile, and parse the reply.
2042 @param[in] Private The pointer to PxeBc private data.
2043 @param[in] Type PxeBc option boot item type.
2044 @param[in] Layer The pointer to option boot item layer.
2045 @param[in] UseBis Use BIS or not.
2046 @param[in] DestIp The pointer to the server address.
2048 @retval EFI_SUCCESS Successfully discovered the boot file.
2049 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2050 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2051 @retval Others Failed to discover the boot file.
2055 PxeBcDhcp6Discover (
2056 IN PXEBC_PRIVATE_DATA
*Private
,
2060 IN EFI_IP_ADDRESS
*DestIp
2063 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2064 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2065 EFI_PXE_BASE_CODE_MODE
*Mode
;
2066 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2067 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2069 EFI_DHCP6_PACKET
*Request
;
2071 EFI_DHCP6_PACKET
*Reply
;
2080 PxeBc
= &Private
->PxeBc
;
2082 Request
= Private
->Dhcp6Request
;
2083 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2084 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2086 if (!UseBis
&& Layer
!= NULL
) {
2087 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2090 if (Request
== NULL
) {
2091 return EFI_DEVICE_ERROR
;
2094 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2095 if (Discover
== NULL
) {
2096 return EFI_OUT_OF_RESOURCES
;
2100 // Build the discover packet by the cached request packet before.
2102 Xid
= NET_RANDOM (NetRandomInitSeed ());
2103 Discover
->TransactionId
= HTONL (Xid
);
2104 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2105 RequestOpt
= Request
->Dhcp6
.Option
;
2106 DiscoverOpt
= Discover
->DhcpOptions
;
2107 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2108 RequestLen
= DiscoverLen
;
2110 while (RequestLen
< Request
->Length
) {
2111 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
2112 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
2113 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
2114 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
2116 // Copy all the options except IA option.
2118 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2119 DiscoverOpt
+= (OpLen
+ 4);
2120 DiscoverLen
+= (OpLen
+ 4);
2122 RequestOpt
+= (OpLen
+ 4);
2123 RequestLen
+= (OpLen
+ 4);
2126 Status
= PxeBc
->UdpWrite (
2132 &Private
->StationIp
,
2139 if (EFI_ERROR (Status
)) {
2144 // Cache the right PXE reply packet here, set valid flag later.
2145 // Especially for PXE discover packet, store it into mode data here.
2147 if (Private
->IsDoDiscover
) {
2148 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2149 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2151 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2153 ReadSize
= (UINTN
) Reply
->Size
;
2156 // Start Udp6Read instance
2158 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2159 if (EFI_ERROR (Status
)) {
2163 Status
= PxeBc
->UdpRead (
2165 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2173 (VOID
*) &Reply
->Dhcp6
2176 // Stop Udp6Read instance
2178 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2179 if (EFI_ERROR (Status
)) {
2186 if (Discover
!= NULL
) {
2187 FreePool (Discover
);
2195 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2197 @param[in] Private The pointer to PxeBc private data.
2198 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2200 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2201 @retval Others Failed to finish the S.A.R.R. process.
2206 IN PXEBC_PRIVATE_DATA
*Private
,
2207 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2210 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2211 EFI_DHCP6_CONFIG_DATA Config
;
2212 EFI_DHCP6_MODE_DATA Mode
;
2213 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2214 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2215 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2218 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2219 EFI_STATUS TimerStatus
;
2221 UINT64 GetMappingTimeOut
;
2223 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2225 Status
= EFI_SUCCESS
;
2226 PxeMode
= Private
->PxeBc
.Mode
;
2227 Ip6Cfg
= Private
->Ip6Cfg
;
2231 // Build option list for the request packet.
2233 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2234 ASSERT (OptCount
> 0);
2236 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2237 if (Retransmit
== NULL
) {
2238 return EFI_OUT_OF_RESOURCES
;
2241 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2242 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2244 Config
.OptionCount
= OptCount
;
2245 Config
.OptionList
= OptList
;
2246 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2247 Config
.CallbackContext
= Private
;
2248 Config
.IaInfoEvent
= NULL
;
2249 Config
.RapidCommit
= FALSE
;
2250 Config
.ReconfigureAccept
= FALSE
;
2251 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2252 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2253 Config
.SolicitRetransmission
= Retransmit
;
2254 Retransmit
->Irt
= 4;
2255 Retransmit
->Mrc
= 4;
2256 Retransmit
->Mrt
= 32;
2257 Retransmit
->Mrd
= 60;
2260 // Configure the DHCPv6 instance for PXE boot.
2262 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2263 FreePool (Retransmit
);
2264 if (EFI_ERROR (Status
)) {
2269 // Initialize the record fields for DHCPv6 offer in private data.
2271 Private
->IsProxyRecved
= FALSE
;
2272 Private
->OfferNum
= 0;
2273 Private
->SelectIndex
= 0;
2274 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2275 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2279 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2281 Status
= Dhcp6
->Start (Dhcp6
);
2282 if (Status
== EFI_NO_MAPPING
) {
2284 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2285 // and wait for duplicate address detection to finish.
2287 Dhcp6
->Stop (Dhcp6
);
2290 // Get Duplicate Address Detection Transmits count.
2292 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2293 Status
= Ip6Cfg
->GetData (
2295 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2299 if (EFI_ERROR (Status
)) {
2300 Dhcp6
->Configure (Dhcp6
, NULL
);
2304 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2305 if (EFI_ERROR (Status
)) {
2306 Dhcp6
->Configure (Dhcp6
, NULL
);
2310 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2311 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2312 if (EFI_ERROR (Status
)) {
2313 gBS
->CloseEvent (Timer
);
2314 Dhcp6
->Configure (Dhcp6
, NULL
);
2320 TimerStatus
= gBS
->CheckEvent (Timer
);
2321 if (!EFI_ERROR (TimerStatus
)) {
2322 Status
= Dhcp6
->Start (Dhcp6
);
2324 } while (TimerStatus
== EFI_NOT_READY
);
2326 gBS
->CloseEvent (Timer
);
2328 if (EFI_ERROR (Status
)) {
2329 if (Status
== EFI_ICMP_ERROR
) {
2330 PxeMode
->IcmpErrorReceived
= TRUE
;
2332 Dhcp6
->Configure (Dhcp6
, NULL
);
2337 // Get the acquired IPv6 address and store them.
2339 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2340 if (EFI_ERROR (Status
)) {
2341 Dhcp6
->Stop (Dhcp6
);
2345 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2347 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2348 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2349 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2350 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2351 // to find a valid router address.
2353 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2354 if (Mode
.ClientId
!= NULL
) {
2355 FreePool (Mode
.ClientId
);
2357 if (Mode
.Ia
!= NULL
) {
2361 // Check the selected offer whether BINL retry is needed.
2363 Status
= PxeBcHandleDhcp6Offer (Private
);
2364 if (EFI_ERROR (Status
)) {
2365 Dhcp6
->Stop (Dhcp6
);