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
= {
19 { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 }
23 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
25 @param[in] Buffer The pointer to the option buffer.
26 @param[in] Length Length of the option buffer.
27 @param[in] OptTag The required option tag.
29 @retval NULL Failed to parse the required option.
30 @retval Others The position of the required option in buffer.
33 EFI_DHCP6_PACKET_OPTION
*
34 PxeBcParseDhcp6Options (
40 EFI_DHCP6_PACKET_OPTION
*Option
;
43 Option
= (EFI_DHCP6_PACKET_OPTION
*)Buffer
;
47 // OpLen and OpCode here are both stored in network order.
49 while (Offset
< Length
) {
50 if (NTOHS (Option
->OpCode
) == OptTag
) {
54 Offset
+= (NTOHS (Option
->OpLen
) + 4);
55 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 (DHCP6_OPT_ORO
);
89 OptList
[Index
]->OpLen
= HTONS (8);
90 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*)OptList
[Index
]->Data
;
91 OptEnt
.Oro
->OpCode
[0] = HTONS (DHCP6_OPT_BOOT_FILE_URL
);
92 OptEnt
.Oro
->OpCode
[1] = HTONS (DHCP6_OPT_BOOT_FILE_PARAM
);
93 OptEnt
.Oro
->OpCode
[2] = HTONS (DHCP6_OPT_DNS_SERVERS
);
94 OptEnt
.Oro
->OpCode
[3] = HTONS (DHCP6_OPT_VENDOR_CLASS
);
96 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
99 // Append client network device interface option
101 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
102 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
103 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*)OptList
[Index
]->Data
;
105 if (Private
->Nii
!= NULL
) {
106 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
107 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
108 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
110 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
111 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
112 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
116 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
119 // Append client system architecture option
121 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
122 OptList
[Index
]->OpLen
= HTONS ((UINT16
)sizeof (PXEBC_DHCP6_OPTION_ARCH
));
123 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*)OptList
[Index
]->Data
;
124 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
125 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
127 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
130 // Append vendor class option to store the PXE class identifier.
132 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
133 OptList
[Index
]->OpLen
= HTONS ((UINT16
)sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
134 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*)OptList
[Index
]->Data
;
135 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
136 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
)sizeof (PXEBC_CLASS_ID
));
138 &OptEnt
.VendorClass
->ClassId
,
139 DEFAULT_CLASS_ID_DATA
,
140 sizeof (PXEBC_CLASS_ID
)
142 PxeBcUintnToAscDecWithFormat (
143 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
144 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
145 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
148 if (Private
->Nii
!= NULL
) {
150 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
151 Private
->Nii
->StringId
,
152 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
154 PxeBcUintnToAscDecWithFormat (
155 Private
->Nii
->MajorVer
,
156 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
157 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
159 PxeBcUintnToAscDecWithFormat (
160 Private
->Nii
->MinorVer
,
161 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
162 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.
177 @retval EFI_SUCCESS Packet is copied.
178 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
182 PxeBcCacheDhcp6Packet (
183 IN EFI_DHCP6_PACKET
*Dst
,
184 IN EFI_DHCP6_PACKET
*Src
187 if (Dst
->Size
< Src
->Length
) {
188 return EFI_BUFFER_TOO_SMALL
;
191 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
192 Dst
->Length
= Src
->Length
;
198 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.
200 @param[in] Private Pointer to PxeBc private data.
201 @param[in] HostName Pointer to buffer containing hostname.
202 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
204 @retval EFI_SUCCESS Operation succeeded.
205 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
206 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
207 @retval Others Other errors as indicated.
212 IN PXEBC_PRIVATE_DATA
*Private
,
214 OUT EFI_IPv6_ADDRESS
*IpAddress
218 EFI_DNS6_PROTOCOL
*Dns6
;
219 EFI_DNS6_CONFIG_DATA Dns6ConfigData
;
220 EFI_DNS6_COMPLETION_TOKEN Token
;
221 EFI_HANDLE Dns6Handle
;
222 EFI_IPv6_ADDRESS
*DnsServerList
;
227 DnsServerList
= Private
->DnsServer
;
228 ZeroMem (&Token
, sizeof (EFI_DNS6_COMPLETION_TOKEN
));
231 // Create a DNSv6 child instance and get the protocol.
233 Status
= NetLibCreateServiceChild (
236 &gEfiDns6ServiceBindingProtocolGuid
,
239 if (EFI_ERROR (Status
)) {
243 Status
= gBS
->OpenProtocol (
245 &gEfiDns6ProtocolGuid
,
249 EFI_OPEN_PROTOCOL_BY_DRIVER
251 if (EFI_ERROR (Status
)) {
256 // Configure DNS6 instance for the DNS server address and protocol.
258 ZeroMem (&Dns6ConfigData
, sizeof (EFI_DNS6_CONFIG_DATA
));
259 Dns6ConfigData
.DnsServerCount
= 1;
260 Dns6ConfigData
.DnsServerList
= DnsServerList
;
261 Dns6ConfigData
.EnableDnsCache
= TRUE
;
262 Dns6ConfigData
.Protocol
= EFI_IP_PROTO_UDP
;
263 IP6_COPY_ADDRESS (&Dns6ConfigData
.StationIp
, &Private
->TmpStationIp
.v6
);
264 Status
= Dns6
->Configure (
268 if (EFI_ERROR (Status
)) {
272 Token
.Status
= EFI_NOT_READY
;
275 // Create event to set the IsDone flag when name resolution is finished.
277 Status
= gBS
->CreateEvent (
284 if (EFI_ERROR (Status
)) {
289 // Start asynchronous name resolution.
291 Status
= Dns6
->HostNameToIp (Dns6
, HostName
, &Token
);
292 if (EFI_ERROR (Status
)) {
301 // Name resolution is done, check result.
303 Status
= Token
.Status
;
304 if (!EFI_ERROR (Status
)) {
305 if (Token
.RspData
.H2AData
== NULL
) {
306 Status
= EFI_DEVICE_ERROR
;
310 if ((Token
.RspData
.H2AData
->IpCount
== 0) || (Token
.RspData
.H2AData
->IpList
== NULL
)) {
311 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
);
329 if (Token
.RspData
.H2AData
!= NULL
) {
330 if (Token
.RspData
.H2AData
->IpList
!= NULL
) {
331 FreePool (Token
.RspData
.H2AData
->IpList
);
334 FreePool (Token
.RspData
.H2AData
);
338 Dns6
->Configure (Dns6
, NULL
);
342 &gEfiDns6ProtocolGuid
,
348 if (Dns6Handle
!= NULL
) {
349 NetLibDestroyServiceChild (
352 &gEfiDns6ServiceBindingProtocolGuid
,
357 if (DnsServerList
!= NULL
) {
358 FreePool (DnsServerList
);
365 Parse the Boot File URL option.
367 @param[in] Private Pointer to PxeBc private data.
368 @param[out] FileName The pointer to the boot file name.
369 @param[in, out] SrvAddr The pointer to the boot server address.
370 @param[in] BootFile The pointer to the boot file URL option data.
371 @param[in] Length The length of the boot file URL option data.
373 @retval EFI_ABORTED User cancel operation.
374 @retval EFI_SUCCESS Selected the boot menu successfully.
375 @retval EFI_NOT_READY Read the input key from the keyboard has not finish.
379 PxeBcExtractBootFileUrl (
380 IN PXEBC_PRIVATE_DATA
*Private
,
381 OUT UINT8
**FileName
,
382 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
388 CHAR8
*BootFileNamePtr
;
390 UINT16 BootFileNameLen
;
393 CHAR8
*ServerAddressOption
;
394 CHAR8
*ServerAddress
;
397 BOOLEAN IpExpressedUrl
;
401 IpExpressedUrl
= TRUE
;
403 // The format of the Boot File URL option is:
406 // 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
407 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408 // | OPT_BOOTFILE_URL | option-len |
409 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 // . bootfile-url (variable length) .
413 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be
418 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME
419 // As an example where the BOOTFILE_NAME is the EFI loader and
420 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
422 PrefixLen
= (UINT16
)AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
424 if ((Length
<= PrefixLen
) ||
425 (CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0))
427 return EFI_NOT_FOUND
;
430 BootFile
= BootFile
+ PrefixLen
;
431 Length
= (UINT16
)(Length
- PrefixLen
);
433 TmpStr
= (CHAR8
*)AllocateZeroPool (Length
+ 1);
434 if (TmpStr
== NULL
) {
435 return EFI_OUT_OF_RESOURCES
;
438 CopyMem (TmpStr
, BootFile
, Length
);
439 TmpStr
[Length
] = '\0';
442 // Get the part of SERVER_ADDRESS string.
444 ServerAddressOption
= TmpStr
;
445 if (*ServerAddressOption
== PXEBC_ADDR_START_DELIMITER
) {
446 ServerAddressOption
++;
447 ServerAddress
= ServerAddressOption
;
448 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
452 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
454 return EFI_INVALID_PARAMETER
;
457 *ServerAddress
= '\0';
460 // Convert the string of server address to Ipv6 address format and store it.
462 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
463 if (EFI_ERROR (Status
)) {
468 IpExpressedUrl
= FALSE
;
469 ServerAddress
= ServerAddressOption
;
470 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
474 if (*ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
476 return EFI_INVALID_PARAMETER
;
479 *ServerAddress
= '\0';
481 Len
= AsciiStrSize (ServerAddressOption
);
482 HostName
= AllocateZeroPool (Len
* sizeof (CHAR16
));
483 if (HostName
== NULL
) {
485 return EFI_OUT_OF_RESOURCES
;
488 AsciiStrToUnicodeStrS (
495 // Perform DNS resolution.
497 Status
= PxeBcDns6 (Private
, HostName
, SrvAddr
);
498 if (EFI_ERROR (Status
)) {
505 // Get the part of BOOTFILE_NAME string.
507 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
508 if (IpExpressedUrl
) {
509 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
511 return EFI_INVALID_PARAMETER
;
517 BootFileNameLen
= (UINT16
)(Length
- (UINT16
)((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
518 if ((BootFileNameLen
!= 0) || (FileName
!= NULL
)) {
520 // Remove trailing mode=octet if present and ignore. All other modes are
521 // invalid for netboot6, so reject them.
523 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
524 if ((ModeStr
!= NULL
) && (*(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0')) {
526 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
528 return EFI_INVALID_PARAMETER
;
532 // Extract boot file name from URL.
534 BootFileName
= (CHAR8
*)AllocateZeroPool (BootFileNameLen
);
535 if (BootFileName
== NULL
) {
537 return EFI_OUT_OF_RESOURCES
;
540 *FileName
= (UINT8
*)BootFileName
;
543 // Decode percent-encoding in boot file name.
545 while (*BootFileNamePtr
!= '\0') {
546 if (*BootFileNamePtr
== '%') {
547 TmpChar
= *(BootFileNamePtr
+ 3);
548 *(BootFileNamePtr
+ 3) = '\0';
549 *BootFileName
= (UINT8
)AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
551 *(BootFileNamePtr
+ 3) = TmpChar
;
552 BootFileNamePtr
+= 3;
554 *BootFileName
= *BootFileNamePtr
;
560 *BootFileName
= '\0';
569 Parse the Boot File Parameter option.
571 @param[in] BootFilePara The pointer to boot file parameter option data.
572 @param[out] BootFileSize The pointer to the parsed boot file size.
574 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
575 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
579 PxeBcExtractBootFileParam (
580 IN CHAR8
*BootFilePara
,
581 OUT UINT16
*BootFileSize
589 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
590 Length
= NTOHS (Length
);
593 // The BootFile Size should be 1~5 byte ASCII strings
595 if ((Length
< 1) || (Length
> 5)) {
596 return EFI_NOT_FOUND
;
600 // Extract the value of BootFile Size.
602 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
604 for (Index
= 0; Index
< Length
; Index
++) {
605 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
606 return EFI_NOT_FOUND
;
609 Size
= (Size
+ Digit
) * 10;
613 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
614 return EFI_NOT_FOUND
;
617 *BootFileSize
= (UINT16
)Size
;
622 Parse the cached DHCPv6 packet, including all the options.
624 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
626 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
627 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
631 PxeBcParseDhcp6Packet (
632 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
635 EFI_DHCP6_PACKET
*Offer
;
636 EFI_DHCP6_PACKET_OPTION
**Options
;
637 EFI_DHCP6_PACKET_OPTION
*Option
;
638 PXEBC_OFFER_TYPE OfferType
;
639 BOOLEAN IsProxyOffer
;
643 UINT32 EnterpriseNum
;
647 Offer
= &Cache6
->Packet
.Offer
;
648 Options
= Cache6
->OptList
;
650 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
652 Option
= (EFI_DHCP6_PACKET_OPTION
*)(Offer
->Dhcp6
.Option
);
654 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
657 // OpLen and OpCode here are both stored in network order, since they are from original packet.
659 while (Offset
< Length
) {
660 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
661 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
662 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
664 // The server sends this option to inform the client about an URL to a boot file.
666 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
667 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
668 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
669 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
670 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
671 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
672 Options
[PXEBC_DHCP6_IDX_DNS_SERVER
] = Option
;
675 Offset
+= (NTOHS (Option
->OpLen
) + 4);
676 Option
= (EFI_DHCP6_PACKET_OPTION
*)(Offer
->Dhcp6
.Option
+ Offset
);
680 // The offer with assigned client address is NOT a proxy offer.
681 // An ia_na option, embedded with valid ia_addr option and a status_code of success.
683 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
684 if (Option
!= NULL
) {
685 Option
= PxeBcParseDhcp6Options (
687 NTOHS (Option
->OpLen
),
688 DHCP6_OPT_STATUS_CODE
690 if (((Option
!= NULL
) && (Option
->Data
[0] == 0)) || (Option
== NULL
)) {
691 IsProxyOffer
= FALSE
;
696 // The offer with "PXEClient" is a pxe offer.
698 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
699 EnterpriseNum
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
701 if ((Option
!= NULL
) &&
702 (NTOHS (Option
->OpLen
) >= 13) &&
703 (CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0) &&
704 (CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0))
710 // Determine offer type of the dhcp6 packet.
714 // It's a binl offer only with PXEClient.
716 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
719 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
721 OfferType
= PxeOfferTypeDhcpOnly
;
724 Cache6
->OfferType
= OfferType
;
730 Cache the DHCPv6 ack packet, and parse it on demand.
732 @param[in] Private The pointer to PxeBc private data.
733 @param[in] Ack The pointer to the DHCPv6 ack packet.
734 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
736 @retval EFI_SUCCESS Cache and parse the packet successfully.
737 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
742 IN PXEBC_PRIVATE_DATA
*Private
,
743 IN EFI_DHCP6_PACKET
*Ack
,
747 EFI_PXE_BASE_CODE_MODE
*Mode
;
750 Mode
= Private
->PxeBc
.Mode
;
752 Status
= PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
753 if (EFI_ERROR (Status
)) {
759 // Parse the ack packet and store it into mode data if needed.
761 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
762 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
763 Mode
->DhcpAckReceived
= TRUE
;
770 Cache the DHCPv6 proxy offer packet according to the received order.
772 @param[in] Private The pointer to PxeBc private data.
773 @param[in] OfferIndex The received order of offer packets.
775 @retval EFI_SUCCESS Cache and parse the packet successfully.
776 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
780 PxeBcCopyDhcp6Proxy (
781 IN PXEBC_PRIVATE_DATA
*Private
,
785 EFI_PXE_BASE_CODE_MODE
*Mode
;
786 EFI_DHCP6_PACKET
*Offer
;
789 ASSERT (OfferIndex
< Private
->OfferNum
);
790 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
792 Mode
= Private
->PxeBc
.Mode
;
793 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
796 // Cache the proxy offer packet and parse it.
798 Status
= PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
799 if (EFI_ERROR (Status
)) {
803 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
806 // Store this packet into mode data.
808 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
809 Mode
->ProxyOfferReceived
= TRUE
;
815 Seek the address of the first byte of the option header.
817 @param[in] Buf The pointer to the buffer.
818 @param[in] SeekLen The length to seek.
819 @param[in] OptType The option type.
821 @retval NULL If it failed to seek the option.
822 @retval others The position to the option.
826 PxeBcDhcp6SeekOption (
840 while (Cursor
< Buf
+ SeekLen
) {
841 OpCode
= ReadUnaligned16 ((UINT16
*)Cursor
);
842 if (OpCode
== HTONS (OptType
)) {
847 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*)(Cursor
+ 2)));
848 Cursor
+= (DataLen
+ 4);
855 Build and send out the request packet for the bootfile, and parse the reply.
857 @param[in] Private The pointer to PxeBc private data.
858 @param[in] Index PxeBc option boot item type.
860 @retval EFI_SUCCESS Successfully discovered the boot file.
861 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
862 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
863 @retval Others Failed to discover the boot file.
867 PxeBcRequestBootService (
868 IN PXEBC_PRIVATE_DATA
*Private
,
872 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
873 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
874 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
875 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
877 EFI_DHCP6_PACKET
*Request
;
879 EFI_DHCP6_PACKET
*Reply
;
887 EFI_DHCP6_PACKET
*IndexOffer
;
890 PxeBc
= &Private
->PxeBc
;
891 Request
= Private
->Dhcp6Request
;
892 IndexOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
893 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
894 DestPort
= PXEBC_BS_DISCOVER_PORT
;
897 if (Request
== NULL
) {
898 return EFI_DEVICE_ERROR
;
901 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
902 if (Discover
== NULL
) {
903 return EFI_OUT_OF_RESOURCES
;
907 // Build the request packet by the cached request packet before.
909 Discover
->TransactionId
= IndexOffer
->Dhcp6
.Header
.TransactionId
;
910 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
911 RequestOpt
= Request
->Dhcp6
.Option
;
912 DiscoverOpt
= Discover
->DhcpOptions
;
913 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
914 RequestLen
= DiscoverLen
;
917 // Find Server ID Option from ProxyOffer.
919 if (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
) {
920 Option
= PxeBcDhcp6SeekOption (
921 IndexOffer
->Dhcp6
.Option
,
922 IndexOffer
->Length
- 4,
925 if (Option
== NULL
) {
926 return EFI_NOT_FOUND
;
930 // Add Server ID Option.
932 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*)Option
)->OpLen
);
933 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
934 DiscoverOpt
+= (OpLen
+ 4);
935 DiscoverLen
+= (OpLen
+ 4);
938 while (RequestLen
< Request
->Length
) {
939 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*)RequestOpt
)->OpCode
);
940 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*)RequestOpt
)->OpLen
);
941 if ((OpCode
!= EFI_DHCP6_IA_TYPE_NA
) &&
942 (OpCode
!= EFI_DHCP6_IA_TYPE_TA
) &&
943 (OpCode
!= DHCP6_OPT_SERVER_ID
)
947 // Copy all the options except IA option and Server ID
949 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
950 DiscoverOpt
+= (OpLen
+ 4);
951 DiscoverLen
+= (OpLen
+ 4);
954 RequestOpt
+= (OpLen
+ 4);
955 RequestLen
+= (OpLen
+ 4);
959 // Update Elapsed option in the package
961 Option
= PxeBcDhcp6SeekOption (
962 Discover
->DhcpOptions
,
963 (UINT32
)(RequestLen
- 4),
964 DHCP6_OPT_ELAPSED_TIME
966 if (Option
!= NULL
) {
967 CalcElapsedTime (Private
);
968 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS ((UINT16
)Private
->ElapsedTime
));
971 Status
= PxeBc
->UdpWrite (
985 if (EFI_ERROR (Status
)) {
990 // Cache the right PXE reply packet here, set valid flag later.
991 // Especially for PXE discover packet, store it into mode data here.
993 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
994 ReadSize
= (UINTN
)Reply
->Size
;
997 // Start Udp6Read instance
999 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
1000 if (EFI_ERROR (Status
)) {
1004 Status
= PxeBc
->UdpRead (
1006 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
1014 (VOID
*)&Reply
->Dhcp6
1017 // Stop Udp6Read instance
1019 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1021 if (EFI_ERROR (Status
)) {
1028 Reply
->Length
= (UINT32
)ReadSize
;
1033 if (Discover
!= NULL
) {
1034 FreePool (Discover
);
1041 Retry to request bootfile name by the BINL offer.
1043 @param[in] Private The pointer to PxeBc private data.
1044 @param[in] Index The received order of offer packets.
1046 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
1047 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
1051 PxeBcRetryDhcp6Binl (
1052 IN PXEBC_PRIVATE_DATA
*Private
,
1056 EFI_PXE_BASE_CODE_MODE
*Mode
;
1057 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
1058 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1061 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1063 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
1064 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
1067 Mode
= Private
->PxeBc
.Mode
;
1068 Private
->IsDoDiscover
= FALSE
;
1069 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
1070 if (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1072 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
1075 &Private
->ServerIp
.v6
,
1076 &mAllDhcpRelayAndServersAddress
,
1077 sizeof (EFI_IPv6_ADDRESS
)
1080 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1082 // Parse out the next server address from the last offer, and store it
1084 Status
= PxeBcExtractBootFileUrl (
1086 &Private
->BootFileName
,
1087 &Private
->ServerIp
.v6
,
1088 (CHAR8
*)(Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
1089 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
1091 if (EFI_ERROR (Status
)) {
1097 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
1099 Status
= PxeBcRequestBootService (Private
, Index
);
1101 if (EFI_ERROR (Status
)) {
1105 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
1106 Status
= PxeBcParseDhcp6Packet (Cache6
);
1107 if (EFI_ERROR (Status
)) {
1111 if ((Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
) &&
1112 (Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
) &&
1113 (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
))
1116 // This BINL ack doesn't have discovery option set or multicast option set
1117 // or bootfile name specified.
1119 return EFI_DEVICE_ERROR
;
1122 Mode
->ProxyOfferReceived
= TRUE
;
1124 &Mode
->ProxyOffer
.Dhcpv6
,
1125 &Cache6
->Packet
.Offer
.Dhcp6
,
1126 Cache6
->Packet
.Offer
.Length
1133 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
1135 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1136 @param[in] RcvdOffer The pointer to the received offer packet.
1138 @retval EFI_SUCCESS Cache and parse the packet successfully.
1139 @retval Others Operation failed.
1142 PxeBcCacheDhcp6Offer (
1143 IN PXEBC_PRIVATE_DATA
*Private
,
1144 IN EFI_DHCP6_PACKET
*RcvdOffer
1147 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1148 EFI_DHCP6_PACKET
*Offer
;
1149 PXEBC_OFFER_TYPE OfferType
;
1152 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
1153 Offer
= &Cache6
->Packet
.Offer
;
1156 // Cache the content of DHCPv6 packet firstly.
1158 Status
= PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
1159 if (EFI_ERROR (Status
)) {
1164 // Validate the DHCPv6 packet, and parse the options and offer type.
1166 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
1171 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
1173 OfferType
= Cache6
->OfferType
;
1174 ASSERT (OfferType
< PxeOfferTypeMax
);
1175 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
1177 if (IS_PROXY_OFFER (OfferType
)) {
1179 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
1181 Private
->IsProxyRecved
= TRUE
;
1183 if (OfferType
== PxeOfferTypeProxyBinl
) {
1185 // Cache all proxy BINL offers.
1187 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1188 Private
->OfferCount
[OfferType
]++;
1189 } else if (((OfferType
== PxeOfferTypeProxyPxe10
) || (OfferType
== PxeOfferTypeProxyWfm11a
)) &&
1190 (Private
->OfferCount
[OfferType
] < 1))
1193 // Only cache the first PXE10/WFM11a offer, and discard the others.
1195 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
1196 Private
->OfferCount
[OfferType
] = 1;
1202 // It's a DHCPv6 offer with yiaddr, and cache them all.
1204 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1205 Private
->OfferCount
[OfferType
]++;
1208 Private
->OfferNum
++;
1214 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
1216 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1220 PxeBcSelectDhcp6Offer (
1221 IN PXEBC_PRIVATE_DATA
*Private
1226 PXEBC_OFFER_TYPE OfferType
;
1228 Private
->SelectIndex
= 0;
1230 if (Private
->IsOfferSorted
) {
1232 // Select offer by default policy.
1234 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1236 // 1. DhcpPxe10 offer
1238 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
1239 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
1241 // 2. DhcpWfm11a offer
1243 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1244 } else if ((Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0) &&
1245 (Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0))
1248 // 3. DhcpOnly offer and ProxyPxe10 offer.
1250 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1251 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1252 } else if ((Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0) &&
1253 (Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0))
1256 // 4. DhcpOnly offer and ProxyWfm11a offer.
1258 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1259 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1260 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1262 // 5. DhcpBinl offer.
1264 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1265 } else if ((Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0) &&
1266 (Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0))
1269 // 6. DhcpOnly offer and ProxyBinl offer.
1271 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1272 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1275 // 7. DhcpOnly offer with bootfilename.
1277 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1278 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1279 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1280 Private
->SelectIndex
= OfferIndex
+ 1;
1287 // Select offer by received order.
1289 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1290 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1292 if (IS_PROXY_OFFER (OfferType
)) {
1294 // Skip proxy offers
1299 if (!Private
->IsProxyRecved
&&
1300 (OfferType
== PxeOfferTypeDhcpOnly
) &&
1301 (Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
))
1304 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1309 Private
->SelectIndex
= Index
+ 1;
1316 Handle the DHCPv6 offer packet.
1318 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1320 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1321 @retval EFI_NO_RESPONSE No response to the following request packet.
1322 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1323 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1327 PxeBcHandleDhcp6Offer (
1328 IN PXEBC_PRIVATE_DATA
*Private
1331 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1333 PXEBC_OFFER_TYPE OfferType
;
1338 ASSERT (Private
->SelectIndex
> 0);
1339 SelectIndex
= (UINT32
)(Private
->SelectIndex
- 1);
1340 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1341 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1342 Status
= EFI_SUCCESS
;
1345 // First try to cache DNS server address if DHCP6 offer provides.
1347 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1348 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1349 if (Private
->DnsServer
== NULL
) {
1350 return EFI_OUT_OF_RESOURCES
;
1353 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1356 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1358 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1360 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1361 Status
= EFI_NO_RESPONSE
;
1363 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1364 if (Private
->IsProxyRecved
) {
1366 // DhcpOnly offer is selected, so need try to request bootfilename.
1369 if (Private
->IsOfferSorted
) {
1371 // The proxy offer should be determined if select by default policy.
1372 // IsOfferSorted means all offers are labeled by OfferIndex.
1374 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1376 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1378 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1380 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1381 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1382 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1387 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1388 Status
= EFI_NO_RESPONSE
;
1392 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1394 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1398 // The proxy offer should not be determined if select by received order.
1400 Status
= EFI_NO_RESPONSE
;
1402 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1403 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1405 if (!IS_PROXY_OFFER (OfferType
)) {
1407 // Skip non proxy dhcp offers.
1412 if (OfferType
== PxeOfferTypeProxyBinl
) {
1414 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1416 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1421 Private
->SelectProxyType
= OfferType
;
1423 Status
= EFI_SUCCESS
;
1428 if (!EFI_ERROR (Status
) && (Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
)) {
1430 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1432 Status
= PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1436 // Otherwise, the bootfilename must be included in DhcpOnly offer.
1438 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1442 if (!EFI_ERROR (Status
)) {
1444 // All PXE boot information is ready by now.
1446 Status
= PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1447 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1454 Unregister the address by Ip6Config protocol.
1456 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1460 PxeBcUnregisterIp6Address (
1461 IN PXEBC_PRIVATE_DATA
*Private
1464 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1466 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1467 // Keep the point and there is no enough requirements to do recovery.
1473 Check whether IP driver could route the message which will be sent to ServerIp address.
1475 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1476 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1478 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1479 @param[in] TimeOutInSecond Timeout value in seconds.
1480 @param[out] GatewayAddr Pointer to store the gateway IP address.
1482 @retval EFI_SUCCESS Found a valid gateway address successfully.
1483 @retval EFI_TIMEOUT The operation is time out.
1484 @retval Other Unexpected error happened.
1488 PxeBcCheckRouteTable (
1489 IN PXEBC_PRIVATE_DATA
*Private
,
1490 IN UINTN TimeOutInSecond
,
1491 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1495 EFI_IP6_PROTOCOL
*Ip6
;
1496 EFI_IP6_MODE_DATA Ip6ModeData
;
1498 EFI_EVENT TimeOutEvt
;
1500 BOOLEAN GatewayIsFound
;
1502 ASSERT (GatewayAddr
!= NULL
);
1503 ASSERT (Private
!= NULL
);
1506 GatewayIsFound
= FALSE
;
1509 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1512 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1513 if (EFI_ERROR (Status
)) {
1518 // Find out the gateway address which can route the message which send to ServerIp.
1520 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1521 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1522 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1523 GatewayIsFound
= TRUE
;
1528 if (Ip6ModeData
.AddressList
!= NULL
) {
1529 FreePool (Ip6ModeData
.AddressList
);
1532 if (Ip6ModeData
.GroupTable
!= NULL
) {
1533 FreePool (Ip6ModeData
.GroupTable
);
1536 if (Ip6ModeData
.RouteTable
!= NULL
) {
1537 FreePool (Ip6ModeData
.RouteTable
);
1540 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1541 FreePool (Ip6ModeData
.NeighborCache
);
1544 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1545 FreePool (Ip6ModeData
.PrefixTable
);
1548 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1549 FreePool (Ip6ModeData
.IcmpTypeList
);
1552 if (GatewayIsFound
|| (RetryCount
== TimeOutInSecond
)) {
1559 // Delay 1 second then recheck it again.
1561 if (TimeOutEvt
== NULL
) {
1562 Status
= gBS
->CreateEvent (
1569 if (EFI_ERROR (Status
)) {
1574 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
1575 if (EFI_ERROR (Status
)) {
1579 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1585 if (TimeOutEvt
!= NULL
) {
1586 gBS
->CloseEvent (TimeOutEvt
);
1589 if (GatewayIsFound
) {
1590 Status
= EFI_SUCCESS
;
1591 } else if (RetryCount
== TimeOutInSecond
) {
1592 Status
= EFI_TIMEOUT
;
1599 Register the ready station address and gateway by Ip6Config protocol.
1601 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1602 @param[in] Address The pointer to the ready address.
1604 @retval EFI_SUCCESS Registered the address successfully.
1605 @retval Others Failed to register the address.
1609 PxeBcRegisterIp6Address (
1610 IN PXEBC_PRIVATE_DATA
*Private
,
1611 IN EFI_IPv6_ADDRESS
*Address
1614 EFI_IP6_PROTOCOL
*Ip6
;
1615 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1616 EFI_IP6_CONFIG_POLICY Policy
;
1617 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1618 EFI_IPv6_ADDRESS GatewayAddr
;
1620 EFI_EVENT MappedEvt
;
1623 EFI_IPv6_ADDRESS
*Ip6Addr
;
1626 Status
= EFI_SUCCESS
;
1629 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1630 Ip6Cfg
= Private
->Ip6Cfg
;
1634 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1635 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1637 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1638 if (EFI_ERROR (Status
)) {
1643 // Retrieve the gateway address from IP6 route table.
1645 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1646 if (EFI_ERROR (Status
)) {
1651 // There is no channel between IP6 and PXE driver about address setting,
1652 // so it has to set the new address by Ip6ConfigProtocol manually.
1654 Policy
= Ip6ConfigPolicyManual
;
1655 Status
= Ip6Cfg
->SetData (
1657 Ip6ConfigDataTypePolicy
,
1658 sizeof (EFI_IP6_CONFIG_POLICY
),
1661 if (EFI_ERROR (Status
)) {
1663 // There is no need to recover later.
1665 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1670 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1672 Status
= gBS
->CreateEvent (
1676 &Private
->IsAddressOk
,
1679 if (EFI_ERROR (Status
)) {
1683 Private
->IsAddressOk
= FALSE
;
1684 Status
= Ip6Cfg
->RegisterDataNotify (
1686 Ip6ConfigDataTypeManualAddress
,
1689 if (EFI_ERROR (Status
)) {
1693 Status
= Ip6Cfg
->SetData (
1695 Ip6ConfigDataTypeManualAddress
,
1696 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1699 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1701 } else if (Status
== EFI_NOT_READY
) {
1703 // Poll the network until the asynchronous process is finished.
1705 while (!Private
->IsAddressOk
) {
1710 // Check whether the IP6 address setting is successed.
1713 Status
= Ip6Cfg
->GetData (
1715 Ip6ConfigDataTypeManualAddress
,
1719 if ((Status
!= EFI_BUFFER_TOO_SMALL
) || (DataSize
== 0)) {
1720 Status
= EFI_DEVICE_ERROR
;
1724 Ip6Addr
= AllocatePool (DataSize
);
1725 if (Ip6Addr
== NULL
) {
1726 return EFI_OUT_OF_RESOURCES
;
1729 Status
= Ip6Cfg
->GetData (
1731 Ip6ConfigDataTypeManualAddress
,
1735 if (EFI_ERROR (Status
)) {
1736 Status
= EFI_DEVICE_ERROR
;
1740 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1741 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1746 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1747 Status
= EFI_ABORTED
;
1753 // Set the default gateway address back if needed.
1755 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1756 Status
= Ip6Cfg
->SetData (
1758 Ip6ConfigDataTypeGateway
,
1759 sizeof (EFI_IPv6_ADDRESS
),
1762 if (EFI_ERROR (Status
)) {
1768 if (MappedEvt
!= NULL
) {
1769 Ip6Cfg
->UnregisterDataNotify (
1771 Ip6ConfigDataTypeManualAddress
,
1774 gBS
->CloseEvent (MappedEvt
);
1777 if (Ip6Addr
!= NULL
) {
1785 Set the IP6 policy to Automatic.
1787 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1789 @retval EFI_SUCCESS Switch the IP policy successfully.
1790 @retval Others Unexpected error happened.
1795 IN PXEBC_PRIVATE_DATA
*Private
1798 EFI_IP6_CONFIG_POLICY Policy
;
1800 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1803 Ip6Cfg
= Private
->Ip6Cfg
;
1804 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1807 // Get and store the current policy of IP6 driver.
1809 Status
= Ip6Cfg
->GetData (
1811 Ip6ConfigDataTypePolicy
,
1815 if (EFI_ERROR (Status
)) {
1819 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1820 Policy
= Ip6ConfigPolicyAutomatic
;
1821 Status
= Ip6Cfg
->SetData (
1823 Ip6ConfigDataTypePolicy
,
1824 sizeof (EFI_IP6_CONFIG_POLICY
),
1827 if (EFI_ERROR (Status
)) {
1829 // There is no need to recover later.
1831 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1839 This function will register the station IP address and flush IP instance to start using the new IP address.
1841 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1843 @retval EFI_SUCCESS The new IP address has been configured successfully.
1844 @retval Others Failed to configure the address.
1848 PxeBcSetIp6Address (
1849 IN PXEBC_PRIVATE_DATA
*Private
1853 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1855 Dhcp6
= Private
->Dhcp6
;
1857 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1858 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1860 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1861 if (EFI_ERROR (Status
)) {
1862 Dhcp6
->Stop (Dhcp6
);
1866 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1867 if (EFI_ERROR (Status
)) {
1868 PxeBcUnregisterIp6Address (Private
);
1869 Dhcp6
->Stop (Dhcp6
);
1873 AsciiPrint ("\n Station IP address is ");
1874 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1880 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1881 to intercept events that occurred in the configuration process.
1883 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1884 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1885 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1886 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1888 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1889 @param[out] NewPacket The packet that is used to replace the Packet above.
1891 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1892 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1893 driver will continue to wait for more packets.
1894 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1899 PxeBcDhcp6CallBack (
1900 IN EFI_DHCP6_PROTOCOL
*This
,
1902 IN EFI_DHCP6_STATE CurrentState
,
1903 IN EFI_DHCP6_EVENT Dhcp6Event
,
1904 IN EFI_DHCP6_PACKET
*Packet
,
1905 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1908 PXEBC_PRIVATE_DATA
*Private
;
1909 EFI_PXE_BASE_CODE_MODE
*Mode
;
1910 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1911 EFI_DHCP6_PACKET
*SelectAd
;
1915 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1916 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1917 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1918 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1919 (Dhcp6Event
!= Dhcp6RcvdReply
))
1924 ASSERT (Packet
!= NULL
);
1926 Private
= (PXEBC_PRIVATE_DATA
*)Context
;
1927 Mode
= Private
->PxeBc
.Mode
;
1928 Callback
= Private
->PxeBcCallback
;
1931 // Callback to user when any traffic occurred if has.
1933 if ((Dhcp6Event
!= Dhcp6SelectAdvertise
) && (Callback
!= NULL
)) {
1934 Received
= (BOOLEAN
)(Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1935 Status
= Callback
->Callback (
1940 (EFI_PXE_BASE_CODE_PACKET
*)&Packet
->Dhcp6
1942 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1947 Status
= EFI_SUCCESS
;
1949 switch (Dhcp6Event
) {
1950 case Dhcp6SendSolicit
:
1951 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1953 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1955 Status
= EFI_ABORTED
;
1960 // Record the first Solicate msg time
1962 if (Private
->SolicitTimes
== 0) {
1963 CalcElapsedTime (Private
);
1964 Private
->SolicitTimes
++;
1968 // Cache the dhcp discover packet to mode data directly.
1970 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1973 case Dhcp6RcvdAdvertise
:
1974 Status
= EFI_NOT_READY
;
1975 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1977 // Ignore the incoming packets which exceed the maximum length.
1982 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1984 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1985 // the OfferIndex and OfferCount.
1987 PxeBcCacheDhcp6Offer (Private
, Packet
);
1992 case Dhcp6SendRequest
:
1993 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1995 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1997 Status
= EFI_ABORTED
;
2002 // Store the request packet as seed packet for discover.
2004 if (Private
->Dhcp6Request
!= NULL
) {
2005 FreePool (Private
->Dhcp6Request
);
2008 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
2009 if (Private
->Dhcp6Request
!= NULL
) {
2010 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
2015 case Dhcp6SelectAdvertise
:
2017 // Select offer by the default policy or by order, and record the SelectIndex
2018 // and SelectProxyType.
2020 PxeBcSelectDhcp6Offer (Private
);
2022 if (Private
->SelectIndex
== 0) {
2023 Status
= EFI_ABORTED
;
2025 ASSERT (NewPacket
!= NULL
);
2026 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
2027 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
2028 ASSERT (*NewPacket
!= NULL
);
2029 if (*NewPacket
== NULL
) {
2033 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
2038 case Dhcp6RcvdReply
:
2040 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
2041 // without verification.
2043 ASSERT (Private
->SelectIndex
!= 0);
2044 Status
= PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
2045 if (EFI_ERROR (Status
)) {
2046 Status
= EFI_ABORTED
;
2059 Build and send out the request packet for the bootfile, and parse the reply.
2061 @param[in] Private The pointer to PxeBc private data.
2062 @param[in] Type PxeBc option boot item type.
2063 @param[in] Layer The pointer to option boot item layer.
2064 @param[in] UseBis Use BIS or not.
2065 @param[in] DestIp The pointer to the server address.
2067 @retval EFI_SUCCESS Successfully discovered the boot file.
2068 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2069 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2070 @retval Others Failed to discover the boot file.
2074 PxeBcDhcp6Discover (
2075 IN PXEBC_PRIVATE_DATA
*Private
,
2079 IN EFI_IP_ADDRESS
*DestIp
2082 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2083 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2084 EFI_PXE_BASE_CODE_MODE
*Mode
;
2085 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2086 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2088 EFI_DHCP6_PACKET
*Request
;
2090 EFI_DHCP6_PACKET
*Reply
;
2099 PxeBc
= &Private
->PxeBc
;
2101 Request
= Private
->Dhcp6Request
;
2102 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2103 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2105 if (!UseBis
&& (Layer
!= NULL
)) {
2106 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2109 if (Request
== NULL
) {
2110 return EFI_DEVICE_ERROR
;
2113 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2114 if (Discover
== NULL
) {
2115 return EFI_OUT_OF_RESOURCES
;
2119 // Build the discover packet by the cached request packet before.
2121 Xid
= NET_RANDOM (NetRandomInitSeed ());
2122 Discover
->TransactionId
= HTONL (Xid
);
2123 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2124 RequestOpt
= Request
->Dhcp6
.Option
;
2125 DiscoverOpt
= Discover
->DhcpOptions
;
2126 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2127 RequestLen
= DiscoverLen
;
2129 while (RequestLen
< Request
->Length
) {
2130 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*)RequestOpt
)->OpCode
);
2131 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*)RequestOpt
)->OpLen
);
2132 if ((OpCode
!= EFI_DHCP6_IA_TYPE_NA
) &&
2133 (OpCode
!= EFI_DHCP6_IA_TYPE_TA
))
2136 // Copy all the options except IA option.
2138 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2139 DiscoverOpt
+= (OpLen
+ 4);
2140 DiscoverLen
+= (OpLen
+ 4);
2143 RequestOpt
+= (OpLen
+ 4);
2144 RequestLen
+= (OpLen
+ 4);
2147 Status
= PxeBc
->UdpWrite (
2153 &Private
->StationIp
,
2160 if (EFI_ERROR (Status
)) {
2165 // Cache the right PXE reply packet here, set valid flag later.
2166 // Especially for PXE discover packet, store it into mode data here.
2168 if (Private
->IsDoDiscover
) {
2169 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2170 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2172 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2175 ReadSize
= (UINTN
)Reply
->Size
;
2178 // Start Udp6Read instance
2180 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2181 if (EFI_ERROR (Status
)) {
2185 Status
= PxeBc
->UdpRead (
2187 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2195 (VOID
*)&Reply
->Dhcp6
2198 // Stop Udp6Read instance
2200 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2201 if (EFI_ERROR (Status
)) {
2208 if (Discover
!= NULL
) {
2209 FreePool (Discover
);
2216 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2218 @param[in] Private The pointer to PxeBc private data.
2219 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2221 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2222 @retval Others Failed to finish the S.A.R.R. process.
2227 IN PXEBC_PRIVATE_DATA
*Private
,
2228 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2231 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2232 EFI_DHCP6_CONFIG_DATA Config
;
2233 EFI_DHCP6_MODE_DATA Mode
;
2234 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2235 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2236 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2239 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2240 EFI_STATUS TimerStatus
;
2242 UINT64 GetMappingTimeOut
;
2244 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2246 Status
= EFI_SUCCESS
;
2247 PxeMode
= Private
->PxeBc
.Mode
;
2248 Ip6Cfg
= Private
->Ip6Cfg
;
2252 // Build option list for the request packet.
2254 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2255 ASSERT (OptCount
> 0);
2257 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2258 if (Retransmit
== NULL
) {
2259 return EFI_OUT_OF_RESOURCES
;
2262 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2263 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2265 Config
.OptionCount
= OptCount
;
2266 Config
.OptionList
= OptList
;
2267 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2268 Config
.CallbackContext
= Private
;
2269 Config
.IaInfoEvent
= NULL
;
2270 Config
.RapidCommit
= FALSE
;
2271 Config
.ReconfigureAccept
= FALSE
;
2272 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2273 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2274 Config
.SolicitRetransmission
= Retransmit
;
2275 Retransmit
->Irt
= 4;
2276 Retransmit
->Mrc
= 4;
2277 Retransmit
->Mrt
= 32;
2278 Retransmit
->Mrd
= 60;
2281 // Configure the DHCPv6 instance for PXE boot.
2283 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2284 FreePool (Retransmit
);
2285 if (EFI_ERROR (Status
)) {
2290 // Initialize the record fields for DHCPv6 offer in private data.
2292 Private
->IsProxyRecved
= FALSE
;
2293 Private
->OfferNum
= 0;
2294 Private
->SelectIndex
= 0;
2295 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2296 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2299 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2301 Status
= Dhcp6
->Start (Dhcp6
);
2302 if (Status
== EFI_NO_MAPPING
) {
2304 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2305 // and wait for duplicate address detection to finish.
2307 Dhcp6
->Stop (Dhcp6
);
2310 // Get Duplicate Address Detection Transmits count.
2312 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2313 Status
= Ip6Cfg
->GetData (
2315 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2319 if (EFI_ERROR (Status
)) {
2320 Dhcp6
->Configure (Dhcp6
, NULL
);
2324 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2325 if (EFI_ERROR (Status
)) {
2326 Dhcp6
->Configure (Dhcp6
, NULL
);
2330 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2331 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2332 if (EFI_ERROR (Status
)) {
2333 gBS
->CloseEvent (Timer
);
2334 Dhcp6
->Configure (Dhcp6
, NULL
);
2339 TimerStatus
= gBS
->CheckEvent (Timer
);
2340 if (!EFI_ERROR (TimerStatus
)) {
2341 Status
= Dhcp6
->Start (Dhcp6
);
2343 } while (TimerStatus
== EFI_NOT_READY
);
2345 gBS
->CloseEvent (Timer
);
2348 if (EFI_ERROR (Status
)) {
2349 if (Status
== EFI_ICMP_ERROR
) {
2350 PxeMode
->IcmpErrorReceived
= TRUE
;
2353 Dhcp6
->Configure (Dhcp6
, NULL
);
2358 // Get the acquired IPv6 address and store them.
2360 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2361 if (EFI_ERROR (Status
)) {
2362 Dhcp6
->Stop (Dhcp6
);
2366 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2368 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2369 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2370 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2371 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2372 // to find a valid router address.
2374 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2375 if (Mode
.ClientId
!= NULL
) {
2376 FreePool (Mode
.ClientId
);
2379 if (Mode
.Ia
!= NULL
) {
2384 // Check the selected offer whether BINL retry is needed.
2386 Status
= PxeBcHandleDhcp6Offer (Private
);
2387 if (EFI_ERROR (Status
)) {
2388 Dhcp6
->Stop (Dhcp6
);