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 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "PxeBcImpl.h"
20 // Well-known multi-cast address defined in section-24.1 of rfc-3315
22 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
24 EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress
= {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
27 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
29 @param[in] Buffer The pointer to the option buffer.
30 @param[in] Length Length of the option buffer.
31 @param[in] OptTag The required option tag.
33 @retval NULL Failed to parse the required option.
34 @retval Others The postion of the required option in buffer.
37 EFI_DHCP6_PACKET_OPTION
*
38 PxeBcParseDhcp6Options (
44 EFI_DHCP6_PACKET_OPTION
*Option
;
47 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
51 // OpLen and OpCode here are both stored in network order.
53 while (Offset
< Length
) {
55 if (NTOHS (Option
->OpCode
) == OptTag
) {
60 Offset
+= (NTOHS(Option
->OpLen
) + 4);
61 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
69 Build the options buffer for the DHCPv6 request packet.
71 @param[in] Private The pointer to PxeBc private data.
72 @param[out] OptList The pointer to the option pointer array.
73 @param[in] Buffer The pointer to the buffer to contain the option list.
75 @return Index The count of the built-in options.
79 PxeBcBuildDhcp6Options (
80 IN PXEBC_PRIVATE_DATA
*Private
,
81 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
85 PXEBC_DHCP6_OPTION_ENTRY OptEnt
;
90 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
93 // Append client option request option
95 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ORO
);
96 OptList
[Index
]->OpLen
= HTONS (8);
97 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
98 OptEnt
.Oro
->OpCode
[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL
);
99 OptEnt
.Oro
->OpCode
[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM
);
100 OptEnt
.Oro
->OpCode
[2] = HTONS(DHCP6_OPT_DNS_SERVERS
);
101 OptEnt
.Oro
->OpCode
[3] = HTONS(DHCP6_OPT_VENDOR_CLASS
);
103 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
106 // Append client network device interface option
108 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
109 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
110 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
112 if (Private
->Nii
!= NULL
) {
113 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
114 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
115 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
117 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
118 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
119 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
123 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
126 // Append client system architecture option
128 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
129 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
130 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
131 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
132 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
134 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
137 // Append vendor class option to store the PXE class identifier.
139 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
140 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
141 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
142 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
143 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
145 &OptEnt
.VendorClass
->ClassId
,
146 DEFAULT_CLASS_ID_DATA
,
147 sizeof (PXEBC_CLASS_ID
)
149 PxeBcUintnToAscDecWithFormat (
150 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
151 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
152 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
155 if (Private
->Nii
!= NULL
) {
157 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
158 Private
->Nii
->StringId
,
159 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
161 PxeBcUintnToAscDecWithFormat (
162 Private
->Nii
->MajorVer
,
163 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
164 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
166 PxeBcUintnToAscDecWithFormat (
167 Private
->Nii
->MinorVer
,
168 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
169 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
180 Cache the DHCPv6 packet.
182 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
183 @param[in] Src The pointer to the DHCPv6 packet to be cached.
185 @retval EFI_SUCCESS Packet is copied.
186 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
190 PxeBcCacheDhcp6Packet (
191 IN EFI_DHCP6_PACKET
*Dst
,
192 IN EFI_DHCP6_PACKET
*Src
195 if (Dst
->Size
< Src
->Length
) {
196 return EFI_BUFFER_TOO_SMALL
;
199 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
200 Dst
->Length
= Src
->Length
;
206 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.
208 @param[in] Private Pointer to PxeBc private data.
209 @param[in] HostName Pointer to buffer containing hostname.
210 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
212 @retval EFI_SUCCESS Operation succeeded.
213 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
214 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
215 @retval Others Other errors as indicated.
220 IN PXEBC_PRIVATE_DATA
*Private
,
222 OUT EFI_IPv6_ADDRESS
*IpAddress
226 EFI_DNS6_PROTOCOL
*Dns6
;
227 EFI_DNS6_CONFIG_DATA Dns6ConfigData
;
228 EFI_DNS6_COMPLETION_TOKEN Token
;
229 EFI_HANDLE Dns6Handle
;
230 EFI_IPv6_ADDRESS
*DnsServerList
;
235 DnsServerList
= Private
->DnsServer
;
236 ZeroMem (&Token
, sizeof (EFI_DNS6_COMPLETION_TOKEN
));
239 // Create a DNSv6 child instance and get the protocol.
241 Status
= NetLibCreateServiceChild (
244 &gEfiDns6ServiceBindingProtocolGuid
,
247 if (EFI_ERROR (Status
)) {
251 Status
= gBS
->OpenProtocol (
253 &gEfiDns6ProtocolGuid
,
257 EFI_OPEN_PROTOCOL_BY_DRIVER
259 if (EFI_ERROR (Status
)) {
264 // Configure DNS6 instance for the DNS server address and protocol.
266 ZeroMem (&Dns6ConfigData
, sizeof (EFI_DNS6_CONFIG_DATA
));
267 Dns6ConfigData
.DnsServerCount
= 1;
268 Dns6ConfigData
.DnsServerList
= DnsServerList
;
269 Dns6ConfigData
.EnableDnsCache
= TRUE
;
270 Dns6ConfigData
.Protocol
= EFI_IP_PROTO_UDP
;
271 IP6_COPY_ADDRESS (&Dns6ConfigData
.StationIp
, &Private
->TmpStationIp
.v6
);
272 Status
= Dns6
->Configure (
276 if (EFI_ERROR (Status
)) {
280 Token
.Status
= EFI_NOT_READY
;
283 // Create event to set the IsDone flag when name resolution is finished.
285 Status
= gBS
->CreateEvent (
292 if (EFI_ERROR (Status
)) {
297 // Start asynchronous name resolution.
299 Status
= Dns6
->HostNameToIp (Dns6
, HostName
, &Token
);
300 if (EFI_ERROR (Status
)) {
309 // Name resolution is done, check result.
311 Status
= Token
.Status
;
312 if (!EFI_ERROR (Status
)) {
313 if (Token
.RspData
.H2AData
== NULL
) {
314 Status
= EFI_DEVICE_ERROR
;
317 if (Token
.RspData
.H2AData
->IpCount
== 0 || Token
.RspData
.H2AData
->IpList
== NULL
) {
318 Status
= EFI_DEVICE_ERROR
;
322 // We just return the first IPv6 address from DNS protocol.
324 IP6_COPY_ADDRESS (IpAddress
, Token
.RspData
.H2AData
->IpList
);
325 Status
= EFI_SUCCESS
;
331 if (Token
.Event
!= NULL
) {
332 gBS
->CloseEvent (Token
.Event
);
334 if (Token
.RspData
.H2AData
!= NULL
) {
335 if (Token
.RspData
.H2AData
->IpList
!= NULL
) {
336 FreePool (Token
.RspData
.H2AData
->IpList
);
338 FreePool (Token
.RspData
.H2AData
);
342 Dns6
->Configure (Dns6
, NULL
);
346 &gEfiDns6ProtocolGuid
,
352 if (Dns6Handle
!= NULL
) {
353 NetLibDestroyServiceChild (
356 &gEfiDns6ServiceBindingProtocolGuid
,
361 if (DnsServerList
!= NULL
) {
362 FreePool (DnsServerList
);
369 Parse the Boot File URL option.
371 @param[in] Private Pointer to PxeBc private data.
372 @param[out] FileName The pointer to the boot file name.
373 @param[in, out] SrvAddr The pointer to the boot server address.
374 @param[in] BootFile The pointer to the boot file URL option data.
375 @param[in] Length The length of the boot file URL option data.
377 @retval EFI_ABORTED User cancel operation.
378 @retval EFI_SUCCESS Selected the boot menu successfully.
379 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
383 PxeBcExtractBootFileUrl (
384 IN PXEBC_PRIVATE_DATA
*Private
,
385 OUT UINT8
**FileName
,
386 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
392 CHAR8
*BootFileNamePtr
;
394 UINT16 BootFileNameLen
;
397 CHAR8
*ServerAddressOption
;
398 CHAR8
*ServerAddress
;
401 BOOLEAN IpExpressedUrl
;
405 IpExpressedUrl
= TRUE
;
407 // The format of the Boot File URL option is:
410 // 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
411 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412 // | OPT_BOOTFILE_URL | option-len |
413 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
415 // . bootfile-url (variable length) .
417 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be
422 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME
423 // As an example where the BOOTFILE_NAME is the EFI loader and
424 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
426 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
428 if (Length
<= PrefixLen
||
429 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
430 return EFI_NOT_FOUND
;
433 BootFile
= BootFile
+ PrefixLen
;
434 Length
= (UINT16
) (Length
- PrefixLen
);
436 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
437 if (TmpStr
== NULL
) {
438 return EFI_OUT_OF_RESOURCES
;
441 CopyMem (TmpStr
, BootFile
, Length
);
442 TmpStr
[Length
] = '\0';
445 // Get the part of SERVER_ADDRESS string.
447 ServerAddressOption
= TmpStr
;
448 if (*ServerAddressOption
== PXEBC_ADDR_START_DELIMITER
) {
449 ServerAddressOption
++;
450 ServerAddress
= ServerAddressOption
;
451 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
455 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
457 return EFI_INVALID_PARAMETER
;
460 *ServerAddress
= '\0';
463 // Convert the string of server address to Ipv6 address format and store it.
465 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
466 if (EFI_ERROR (Status
)) {
472 IpExpressedUrl
= FALSE
;
473 ServerAddress
= ServerAddressOption
;
474 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
478 if (*ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
480 return EFI_INVALID_PARAMETER
;
482 *ServerAddress
= '\0';
484 Len
= AsciiStrSize (ServerAddressOption
);
485 HostName
= AllocateZeroPool (Len
* sizeof (CHAR16
));
486 if (HostName
== NULL
) {
488 return EFI_OUT_OF_RESOURCES
;
490 AsciiStrToUnicodeStrS (
497 // Perform DNS resolution.
499 Status
= PxeBcDns6 (Private
,HostName
, SrvAddr
);
500 if (EFI_ERROR (Status
)) {
507 // Get the part of BOOTFILE_NAME string.
509 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
510 if (IpExpressedUrl
) {
511 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
513 return EFI_INVALID_PARAMETER
;
518 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
519 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
521 // Remove trailing mode=octet if present and ignore. All other modes are
522 // invalid for netboot6, so reject them.
524 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
525 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
527 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
529 return EFI_INVALID_PARAMETER
;
533 // Extract boot file name from URL.
535 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
536 if (BootFileName
== NULL
) {
538 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
;
559 *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
;
623 Parse the cached DHCPv6 packet, including all the options.
625 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
627 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
628 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
632 PxeBcParseDhcp6Packet (
633 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
636 EFI_DHCP6_PACKET
*Offer
;
637 EFI_DHCP6_PACKET_OPTION
**Options
;
638 EFI_DHCP6_PACKET_OPTION
*Option
;
639 PXEBC_OFFER_TYPE OfferType
;
640 BOOLEAN IsProxyOffer
;
644 UINT32 EnterpriseNum
;
648 Offer
= &Cache6
->Packet
.Offer
;
649 Options
= Cache6
->OptList
;
651 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
653 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
655 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
658 // OpLen and OpCode here are both stored in network order, since they are from original packet.
660 while (Offset
< Length
) {
662 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
663 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
664 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
666 // The server sends this option to inform the client about an URL to a boot file.
668 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
669 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
670 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
671 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
672 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
673 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
674 Options
[PXEBC_DHCP6_IDX_DNS_SERVER
] = Option
;
677 Offset
+= (NTOHS (Option
->OpLen
) + 4);
678 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
682 // The offer with assigned client address is NOT a proxy offer.
683 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
685 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
686 if (Option
!= NULL
) {
687 Option
= PxeBcParseDhcp6Options (
689 NTOHS (Option
->OpLen
),
690 DHCP6_OPT_STATUS_CODE
692 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
693 IsProxyOffer
= FALSE
;
698 // The offer with "PXEClient" is a pxe offer.
700 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
701 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
703 if (Option
!= NULL
&&
704 NTOHS(Option
->OpLen
) >= 13 &&
705 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
706 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
711 // Determine offer type of the dhcp6 packet.
715 // It's a binl offer only with PXEClient.
717 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
720 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
722 OfferType
= PxeOfferTypeDhcpOnly
;
725 Cache6
->OfferType
= OfferType
;
732 Cache the DHCPv6 ack packet, and parse it on demand.
734 @param[in] Private The pointer to PxeBc private data.
735 @param[in] Ack The pointer to the DHCPv6 ack packet.
736 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
738 @retval EFI_SUCCESS Cache and parse the packet successfully.
739 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
744 IN PXEBC_PRIVATE_DATA
*Private
,
745 IN EFI_DHCP6_PACKET
*Ack
,
749 EFI_PXE_BASE_CODE_MODE
*Mode
;
752 Mode
= Private
->PxeBc
.Mode
;
754 Status
= PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
755 if (EFI_ERROR (Status
)) {
761 // Parse the ack packet and store it into mode data if needed.
763 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
764 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
765 Mode
->DhcpAckReceived
= TRUE
;
773 Cache the DHCPv6 proxy offer packet according to the received order.
775 @param[in] Private The pointer to PxeBc private data.
776 @param[in] OfferIndex The received order of offer packets.
778 @retval EFI_SUCCESS Cache and parse the packet successfully.
779 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
783 PxeBcCopyDhcp6Proxy (
784 IN PXEBC_PRIVATE_DATA
*Private
,
788 EFI_PXE_BASE_CODE_MODE
*Mode
;
789 EFI_DHCP6_PACKET
*Offer
;
792 ASSERT (OfferIndex
< Private
->OfferNum
);
793 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
795 Mode
= Private
->PxeBc
.Mode
;
796 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
799 // Cache the proxy offer packet and parse it.
801 Status
= PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
802 if (EFI_ERROR(Status
)) {
805 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
808 // Store this packet into mode data.
810 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
811 Mode
->ProxyOfferReceived
= TRUE
;
817 Seek the address of the first byte of the option header.
819 @param[in] Buf The pointer to the buffer.
820 @param[in] SeekLen The length to seek.
821 @param[in] OptType The option type.
823 @retval NULL If it failed to seek the option.
824 @retval others The position to the option.
828 PxeBcDhcp6SeekOption (
842 while (Cursor
< Buf
+ SeekLen
) {
843 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
844 if (OpCode
== HTONS (OptType
)) {
848 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
849 Cursor
+= (DataLen
+ 4);
857 Build and send out the request packet for the bootfile, and parse the reply.
859 @param[in] Private The pointer to PxeBc private data.
860 @param[in] Index PxeBc option boot item type.
862 @retval EFI_SUCCESS Successfully discovered the boot file.
863 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
864 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
865 @retval Others Failed to discover the boot file.
869 PxeBcRequestBootService (
870 IN PXEBC_PRIVATE_DATA
*Private
,
874 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
875 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
876 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
877 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
879 EFI_DHCP6_PACKET
*Request
;
881 EFI_DHCP6_PACKET
*Reply
;
889 EFI_DHCP6_PACKET
*IndexOffer
;
892 PxeBc
= &Private
->PxeBc
;
893 Request
= Private
->Dhcp6Request
;
894 IndexOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
895 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
896 DestPort
= PXEBC_BS_DISCOVER_PORT
;
899 if (Request
== NULL
) {
900 return EFI_DEVICE_ERROR
;
903 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
904 if (Discover
== NULL
) {
905 return EFI_OUT_OF_RESOURCES
;
909 // Build the request packet by the cached request packet before.
911 Discover
->TransactionId
= IndexOffer
->Dhcp6
.Header
.TransactionId
;
912 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
913 RequestOpt
= Request
->Dhcp6
.Option
;
914 DiscoverOpt
= Discover
->DhcpOptions
;
915 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
916 RequestLen
= DiscoverLen
;
919 // Find Server ID Option from ProxyOffer.
921 if (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
) {
922 Option
= PxeBcDhcp6SeekOption (
923 IndexOffer
->Dhcp6
.Option
,
924 IndexOffer
->Length
- 4,
927 if (Option
== NULL
) {
928 return EFI_NOT_FOUND
;
932 // Add Server ID Option.
934 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
935 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
936 DiscoverOpt
+= (OpLen
+ 4);
937 DiscoverLen
+= (OpLen
+ 4);
940 while (RequestLen
< Request
->Length
) {
941 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
942 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
943 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
944 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
945 OpCode
!= DHCP6_OPT_SERVER_ID
948 // Copy all the options except IA option and Server ID
950 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
951 DiscoverOpt
+= (OpLen
+ 4);
952 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
);
1042 Retry to request bootfile name by the BINL offer.
1044 @param[in] Private The pointer to PxeBc private data.
1045 @param[in] Index The received order of offer packets.
1047 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
1048 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
1052 PxeBcRetryDhcp6Binl (
1053 IN PXEBC_PRIVATE_DATA
*Private
,
1057 EFI_PXE_BASE_CODE_MODE
*Mode
;
1058 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
1059 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1062 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1063 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
1064 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
1066 Mode
= Private
->PxeBc
.Mode
;
1067 Private
->IsDoDiscover
= FALSE
;
1068 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
1069 if (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1071 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
1074 &Private
->ServerIp
.v6
,
1075 &mAllDhcpRelayAndServersAddress
,
1076 sizeof (EFI_IPv6_ADDRESS
)
1079 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1081 // Parse out the next server address from the last offer, and store it
1083 Status
= PxeBcExtractBootFileUrl (
1085 &Private
->BootFileName
,
1086 &Private
->ServerIp
.v6
,
1087 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
1088 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
1090 if (EFI_ERROR (Status
)) {
1096 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
1098 Status
= PxeBcRequestBootService (Private
, Index
);
1100 if (EFI_ERROR (Status
)) {
1104 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
1105 Status
= PxeBcParseDhcp6Packet (Cache6
);
1106 if (EFI_ERROR (Status
)) {
1110 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
1111 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
1112 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1114 // This BINL ack doesn't have discovery option set or multicast option set
1115 // or bootfile name specified.
1117 return EFI_DEVICE_ERROR
;
1120 Mode
->ProxyOfferReceived
= TRUE
;
1122 &Mode
->ProxyOffer
.Dhcpv6
,
1123 &Cache6
->Packet
.Offer
.Dhcp6
,
1124 Cache6
->Packet
.Offer
.Length
1132 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
1134 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1135 @param[in] RcvdOffer The pointer to the received offer packet.
1137 @retval EFI_SUCCESS Cache and parse the packet successfully.
1138 @retval Others Operation failed.
1141 PxeBcCacheDhcp6Offer (
1142 IN PXEBC_PRIVATE_DATA
*Private
,
1143 IN EFI_DHCP6_PACKET
*RcvdOffer
1146 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1147 EFI_DHCP6_PACKET
*Offer
;
1148 PXEBC_OFFER_TYPE OfferType
;
1151 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
1152 Offer
= &Cache6
->Packet
.Offer
;
1155 // Cache the content of DHCPv6 packet firstly.
1157 Status
= PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
1158 if (EFI_ERROR (Status
)) {
1163 // Validate the DHCPv6 packet, and parse the options and offer type.
1165 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
1170 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
1172 OfferType
= Cache6
->OfferType
;
1173 ASSERT (OfferType
< PxeOfferTypeMax
);
1174 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
1176 if (IS_PROXY_OFFER (OfferType
)) {
1178 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
1180 Private
->IsProxyRecved
= TRUE
;
1182 if (OfferType
== PxeOfferTypeProxyBinl
) {
1184 // Cache all proxy BINL offers.
1186 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1187 Private
->OfferCount
[OfferType
]++;
1188 } else if ((OfferType
== PxeOfferTypeProxyPxe10
|| OfferType
== PxeOfferTypeProxyWfm11a
) &&
1189 Private
->OfferCount
[OfferType
] < 1) {
1191 // Only cache the first PXE10/WFM11a offer, and discard the others.
1193 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
1194 Private
->OfferCount
[OfferType
] = 1;
1200 // It's a DHCPv6 offer with yiaddr, and cache them all.
1202 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1203 Private
->OfferCount
[OfferType
]++;
1206 Private
->OfferNum
++;
1213 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
1215 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1219 PxeBcSelectDhcp6Offer (
1220 IN PXEBC_PRIVATE_DATA
*Private
1225 PXEBC_OFFER_TYPE OfferType
;
1227 Private
->SelectIndex
= 0;
1229 if (Private
->IsOfferSorted
) {
1231 // Select offer by default policy.
1233 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1235 // 1. DhcpPxe10 offer
1237 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;
1245 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1246 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1248 // 3. DhcpOnly offer and ProxyPxe10 offer.
1250 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1251 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1253 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1254 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1256 // 4. DhcpOnly offer and ProxyWfm11a offer.
1258 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1259 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1261 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1263 // 5. DhcpBinl offer.
1265 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1267 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1268 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1270 // 6. DhcpOnly offer and ProxyBinl offer.
1272 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1273 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1277 // 7. DhcpOnly offer with bootfilename.
1279 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1280 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1281 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1282 Private
->SelectIndex
= OfferIndex
+ 1;
1289 // Select offer by received order.
1291 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1293 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1295 if (IS_PROXY_OFFER (OfferType
)) {
1297 // Skip proxy offers
1302 if (!Private
->IsProxyRecved
&&
1303 OfferType
== PxeOfferTypeDhcpOnly
&&
1304 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1306 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1311 Private
->SelectIndex
= Index
+ 1;
1319 Handle the DHCPv6 offer packet.
1321 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1323 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1324 @retval EFI_NO_RESPONSE No response to the following request packet.
1325 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1326 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1330 PxeBcHandleDhcp6Offer (
1331 IN PXEBC_PRIVATE_DATA
*Private
1334 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1336 PXEBC_OFFER_TYPE OfferType
;
1341 ASSERT (Private
->SelectIndex
> 0);
1342 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1343 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1344 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1345 Status
= EFI_SUCCESS
;
1348 // First try to cache DNS server address if DHCP6 offer provides.
1350 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1351 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1352 if (Private
->DnsServer
== NULL
) {
1353 return EFI_OUT_OF_RESOURCES
;
1355 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1358 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1360 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1362 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1363 Status
= EFI_NO_RESPONSE
;
1365 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1367 if (Private
->IsProxyRecved
) {
1369 // DhcpOnly offer is selected, so need try to request bootfilename.
1372 if (Private
->IsOfferSorted
) {
1374 // The proxy offer should be determined if select by default policy.
1375 // IsOfferSorted means all offers are labeled by OfferIndex.
1377 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1379 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1381 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1383 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1385 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1386 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1390 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1391 Status
= EFI_NO_RESPONSE
;
1395 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1397 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1401 // The proxy offer should not be determined if select by received order.
1403 Status
= EFI_NO_RESPONSE
;
1405 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1407 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1409 if (!IS_PROXY_OFFER (OfferType
)) {
1411 // Skip non proxy dhcp offers.
1416 if (OfferType
== PxeOfferTypeProxyBinl
) {
1418 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1420 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1425 Private
->SelectProxyType
= OfferType
;
1427 Status
= EFI_SUCCESS
;
1432 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1434 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1436 Status
= PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1440 // Othewise, the bootfilename must be included in DhcpOnly offer.
1442 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1446 if (!EFI_ERROR (Status
)) {
1448 // All PXE boot information is ready by now.
1450 Status
= PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1451 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1459 Unregister the address by Ip6Config protocol.
1461 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1465 PxeBcUnregisterIp6Address (
1466 IN PXEBC_PRIVATE_DATA
*Private
1469 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1471 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1472 // Keep the point and there is no enough requirements to do recovery.
1478 Check whether IP driver could route the message which will be sent to ServerIp address.
1480 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1481 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1483 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1484 @param[in] TimeOutInSecond Timeout value in seconds.
1485 @param[out] GatewayAddr Pointer to store the gateway IP address.
1487 @retval EFI_SUCCESS Found a valid gateway address successfully.
1488 @retval EFI_TIMEOUT The operation is time out.
1489 @retval Other Unexpect error happened.
1493 PxeBcCheckRouteTable (
1494 IN PXEBC_PRIVATE_DATA
*Private
,
1495 IN UINTN TimeOutInSecond
,
1496 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1500 EFI_IP6_PROTOCOL
*Ip6
;
1501 EFI_IP6_MODE_DATA Ip6ModeData
;
1503 EFI_EVENT TimeOutEvt
;
1505 BOOLEAN GatewayIsFound
;
1507 ASSERT (GatewayAddr
!= NULL
);
1508 ASSERT (Private
!= NULL
);
1511 GatewayIsFound
= FALSE
;
1514 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1517 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1518 if (EFI_ERROR (Status
)) {
1523 // Find out the gateway address which can route the message which send to ServerIp.
1525 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1526 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1527 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1528 GatewayIsFound
= TRUE
;
1533 if (Ip6ModeData
.AddressList
!= NULL
) {
1534 FreePool (Ip6ModeData
.AddressList
);
1536 if (Ip6ModeData
.GroupTable
!= NULL
) {
1537 FreePool (Ip6ModeData
.GroupTable
);
1539 if (Ip6ModeData
.RouteTable
!= NULL
) {
1540 FreePool (Ip6ModeData
.RouteTable
);
1542 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1543 FreePool (Ip6ModeData
.NeighborCache
);
1545 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1546 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
)) {
1578 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1584 if (TimeOutEvt
!= NULL
) {
1585 gBS
->CloseEvent (TimeOutEvt
);
1588 if (GatewayIsFound
) {
1589 Status
= EFI_SUCCESS
;
1590 } else if (RetryCount
== TimeOutInSecond
) {
1591 Status
= EFI_TIMEOUT
;
1598 Register the ready station address and gateway by Ip6Config protocol.
1600 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1601 @param[in] Address The pointer to the ready address.
1603 @retval EFI_SUCCESS Registered the address succesfully.
1604 @retval Others Failed to register the address.
1608 PxeBcRegisterIp6Address (
1609 IN PXEBC_PRIVATE_DATA
*Private
,
1610 IN EFI_IPv6_ADDRESS
*Address
1613 EFI_IP6_PROTOCOL
*Ip6
;
1614 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1615 EFI_IP6_CONFIG_POLICY Policy
;
1616 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1617 EFI_IPv6_ADDRESS GatewayAddr
;
1619 EFI_EVENT MappedEvt
;
1622 EFI_IPv6_ADDRESS
*Ip6Addr
;
1625 Status
= EFI_SUCCESS
;
1628 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1629 Ip6Cfg
= Private
->Ip6Cfg
;
1633 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1634 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1636 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1637 if (EFI_ERROR (Status
)) {
1642 // Retrieve the gateway address from IP6 route table.
1644 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1645 if (EFI_ERROR (Status
)) {
1650 // There is no channel between IP6 and PXE driver about address setting,
1651 // so it has to set the new address by Ip6ConfigProtocol manually.
1653 Policy
= Ip6ConfigPolicyManual
;
1654 Status
= Ip6Cfg
->SetData (
1656 Ip6ConfigDataTypePolicy
,
1657 sizeof(EFI_IP6_CONFIG_POLICY
),
1660 if (EFI_ERROR (Status
)) {
1662 // There is no need to recover later.
1664 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1669 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1671 Status
= gBS
->CreateEvent (
1675 &Private
->IsAddressOk
,
1678 if (EFI_ERROR (Status
)) {
1682 Private
->IsAddressOk
= FALSE
;
1683 Status
= Ip6Cfg
->RegisterDataNotify (
1685 Ip6ConfigDataTypeManualAddress
,
1688 if (EFI_ERROR(Status
)) {
1692 Status
= Ip6Cfg
->SetData (
1694 Ip6ConfigDataTypeManualAddress
,
1695 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1698 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1700 } else if (Status
== EFI_NOT_READY
) {
1702 // Poll the network until the asynchronous process is finished.
1704 while (!Private
->IsAddressOk
) {
1708 // Check whether the IP6 address setting is successed.
1711 Status
= Ip6Cfg
->GetData (
1713 Ip6ConfigDataTypeManualAddress
,
1717 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
1718 Status
= EFI_DEVICE_ERROR
;
1722 Ip6Addr
= AllocatePool (DataSize
);
1723 if (Ip6Addr
== NULL
) {
1724 return EFI_OUT_OF_RESOURCES
;
1726 Status
= Ip6Cfg
->GetData (
1728 Ip6ConfigDataTypeManualAddress
,
1732 if (EFI_ERROR (Status
)) {
1733 Status
= EFI_DEVICE_ERROR
;
1737 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1738 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1742 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1743 Status
= EFI_ABORTED
;
1749 // Set the default gateway address back if needed.
1751 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1752 Status
= Ip6Cfg
->SetData (
1754 Ip6ConfigDataTypeGateway
,
1755 sizeof (EFI_IPv6_ADDRESS
),
1758 if (EFI_ERROR (Status
)) {
1764 if (MappedEvt
!= NULL
) {
1765 Ip6Cfg
->UnregisterDataNotify (
1767 Ip6ConfigDataTypeManualAddress
,
1770 gBS
->CloseEvent (MappedEvt
);
1772 if (Ip6Addr
!= NULL
) {
1779 Set the IP6 policy to Automatic.
1781 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1783 @retval EFI_SUCCESS Switch the IP policy succesfully.
1784 @retval Others Unexpect error happened.
1789 IN PXEBC_PRIVATE_DATA
*Private
1792 EFI_IP6_CONFIG_POLICY Policy
;
1794 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1797 Ip6Cfg
= Private
->Ip6Cfg
;
1798 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1801 // Get and store the current policy of IP6 driver.
1803 Status
= Ip6Cfg
->GetData (
1805 Ip6ConfigDataTypePolicy
,
1809 if (EFI_ERROR (Status
)) {
1813 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1814 Policy
= Ip6ConfigPolicyAutomatic
;
1815 Status
= Ip6Cfg
->SetData (
1817 Ip6ConfigDataTypePolicy
,
1818 sizeof(EFI_IP6_CONFIG_POLICY
),
1821 if (EFI_ERROR (Status
)) {
1823 // There is no need to recover later.
1825 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1833 This function will register the station IP address and flush IP instance to start using the new IP address.
1835 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1837 @retval EFI_SUCCESS The new IP address has been configured successfully.
1838 @retval Others Failed to configure the address.
1842 PxeBcSetIp6Address (
1843 IN PXEBC_PRIVATE_DATA
*Private
1847 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1849 Dhcp6
= Private
->Dhcp6
;
1851 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1852 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1854 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1855 if (EFI_ERROR (Status
)) {
1856 Dhcp6
->Stop (Dhcp6
);
1860 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1861 if (EFI_ERROR (Status
)) {
1862 PxeBcUnregisterIp6Address (Private
);
1863 Dhcp6
->Stop (Dhcp6
);
1867 AsciiPrint ("\n Station IP address is ");
1868 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1874 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1875 to intercept events that occurred in the configuration process.
1877 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1878 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1879 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1880 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1882 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1883 @param[out] NewPacket The packet that is used to replace the Packet above.
1885 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1886 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1887 driver will continue to wait for more packets.
1888 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1893 PxeBcDhcp6CallBack (
1894 IN EFI_DHCP6_PROTOCOL
*This
,
1896 IN EFI_DHCP6_STATE CurrentState
,
1897 IN EFI_DHCP6_EVENT Dhcp6Event
,
1898 IN EFI_DHCP6_PACKET
*Packet
,
1899 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1902 PXEBC_PRIVATE_DATA
*Private
;
1903 EFI_PXE_BASE_CODE_MODE
*Mode
;
1904 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1905 EFI_DHCP6_PACKET
*SelectAd
;
1909 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1910 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1911 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1912 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1913 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1917 ASSERT (Packet
!= NULL
);
1919 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1920 Mode
= Private
->PxeBc
.Mode
;
1921 Callback
= Private
->PxeBcCallback
;
1924 // Callback to user when any traffic ocurred if has.
1926 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1927 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1928 Status
= Callback
->Callback (
1933 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1935 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1940 Status
= EFI_SUCCESS
;
1942 switch (Dhcp6Event
) {
1944 case Dhcp6SendSolicit
:
1945 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1947 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1949 Status
= EFI_ABORTED
;
1954 // Record the first Solicate msg time
1956 if (Private
->SolicitTimes
== 0) {
1957 CalcElapsedTime (Private
);
1958 Private
->SolicitTimes
++;
1961 // Cache the dhcp discover packet to mode data directly.
1963 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1966 case Dhcp6RcvdAdvertise
:
1967 Status
= EFI_NOT_READY
;
1968 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1970 // Ignore the incoming packets which exceed the maximum length.
1974 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1976 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1977 // the OfferIndex and OfferCount.
1979 PxeBcCacheDhcp6Offer (Private
, Packet
);
1983 case Dhcp6SendRequest
:
1984 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1986 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1988 Status
= EFI_ABORTED
;
1993 // Store the request packet as seed packet for discover.
1995 if (Private
->Dhcp6Request
!= NULL
) {
1996 FreePool (Private
->Dhcp6Request
);
1998 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1999 if (Private
->Dhcp6Request
!= NULL
) {
2000 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
2004 case Dhcp6SelectAdvertise
:
2006 // Select offer by the default policy or by order, and record the SelectIndex
2007 // and SelectProxyType.
2009 PxeBcSelectDhcp6Offer (Private
);
2011 if (Private
->SelectIndex
== 0) {
2012 Status
= EFI_ABORTED
;
2014 ASSERT (NewPacket
!= NULL
);
2015 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
2016 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
2017 ASSERT (*NewPacket
!= NULL
);
2018 if (*NewPacket
== NULL
) {
2021 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
2025 case Dhcp6RcvdReply
:
2027 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
2028 // without verification.
2030 ASSERT (Private
->SelectIndex
!= 0);
2031 Status
= PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
2032 if (EFI_ERROR (Status
)) {
2033 Status
= EFI_ABORTED
;
2046 Build and send out the request packet for the bootfile, and parse the reply.
2048 @param[in] Private The pointer to PxeBc private data.
2049 @param[in] Type PxeBc option boot item type.
2050 @param[in] Layer The pointer to option boot item layer.
2051 @param[in] UseBis Use BIS or not.
2052 @param[in] DestIp The pointer to the server address.
2054 @retval EFI_SUCCESS Successfully discovered the boot file.
2055 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2056 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2057 @retval Others Failed to discover the boot file.
2061 PxeBcDhcp6Discover (
2062 IN PXEBC_PRIVATE_DATA
*Private
,
2066 IN EFI_IP_ADDRESS
*DestIp
2069 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2070 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2071 EFI_PXE_BASE_CODE_MODE
*Mode
;
2072 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2073 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2075 EFI_DHCP6_PACKET
*Request
;
2077 EFI_DHCP6_PACKET
*Reply
;
2086 PxeBc
= &Private
->PxeBc
;
2088 Request
= Private
->Dhcp6Request
;
2089 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2090 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2092 if (!UseBis
&& Layer
!= NULL
) {
2093 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2096 if (Request
== NULL
) {
2097 return EFI_DEVICE_ERROR
;
2100 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2101 if (Discover
== NULL
) {
2102 return EFI_OUT_OF_RESOURCES
;
2106 // Build the discover packet by the cached request packet before.
2108 Xid
= NET_RANDOM (NetRandomInitSeed ());
2109 Discover
->TransactionId
= HTONL (Xid
);
2110 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2111 RequestOpt
= Request
->Dhcp6
.Option
;
2112 DiscoverOpt
= Discover
->DhcpOptions
;
2113 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2114 RequestLen
= DiscoverLen
;
2116 while (RequestLen
< Request
->Length
) {
2117 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
2118 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
2119 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
2120 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
2122 // Copy all the options except IA option.
2124 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2125 DiscoverOpt
+= (OpLen
+ 4);
2126 DiscoverLen
+= (OpLen
+ 4);
2128 RequestOpt
+= (OpLen
+ 4);
2129 RequestLen
+= (OpLen
+ 4);
2132 Status
= PxeBc
->UdpWrite (
2138 &Private
->StationIp
,
2145 if (EFI_ERROR (Status
)) {
2150 // Cache the right PXE reply packet here, set valid flag later.
2151 // Especially for PXE discover packet, store it into mode data here.
2153 if (Private
->IsDoDiscover
) {
2154 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2155 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2157 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2159 ReadSize
= (UINTN
) Reply
->Size
;
2162 // Start Udp6Read instance
2164 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2165 if (EFI_ERROR (Status
)) {
2169 Status
= PxeBc
->UdpRead (
2171 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2179 (VOID
*) &Reply
->Dhcp6
2182 // Stop Udp6Read instance
2184 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2185 if (EFI_ERROR (Status
)) {
2192 if (Discover
!= NULL
) {
2193 FreePool (Discover
);
2201 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2203 @param[in] Private The pointer to PxeBc private data.
2204 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2206 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2207 @retval Others Failed to finish the S.A.R.R. process.
2212 IN PXEBC_PRIVATE_DATA
*Private
,
2213 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2216 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2217 EFI_DHCP6_CONFIG_DATA Config
;
2218 EFI_DHCP6_MODE_DATA Mode
;
2219 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2220 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2221 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2224 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2225 EFI_STATUS TimerStatus
;
2227 UINT64 GetMappingTimeOut
;
2229 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2231 Status
= EFI_SUCCESS
;
2232 PxeMode
= Private
->PxeBc
.Mode
;
2233 Ip6Cfg
= Private
->Ip6Cfg
;
2237 // Build option list for the request packet.
2239 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2240 ASSERT (OptCount
> 0);
2242 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2243 if (Retransmit
== NULL
) {
2244 return EFI_OUT_OF_RESOURCES
;
2247 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2248 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2250 Config
.OptionCount
= OptCount
;
2251 Config
.OptionList
= OptList
;
2252 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2253 Config
.CallbackContext
= Private
;
2254 Config
.IaInfoEvent
= NULL
;
2255 Config
.RapidCommit
= FALSE
;
2256 Config
.ReconfigureAccept
= FALSE
;
2257 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2258 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2259 Config
.SolicitRetransmission
= Retransmit
;
2260 Retransmit
->Irt
= 4;
2261 Retransmit
->Mrc
= 4;
2262 Retransmit
->Mrt
= 32;
2263 Retransmit
->Mrd
= 60;
2266 // Configure the DHCPv6 instance for PXE boot.
2268 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2269 FreePool (Retransmit
);
2270 if (EFI_ERROR (Status
)) {
2275 // Initialize the record fields for DHCPv6 offer in private data.
2277 Private
->IsProxyRecved
= FALSE
;
2278 Private
->OfferNum
= 0;
2279 Private
->SelectIndex
= 0;
2280 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2281 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2285 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2287 Status
= Dhcp6
->Start (Dhcp6
);
2288 if (Status
== EFI_NO_MAPPING
) {
2290 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2291 // and wait for duplicate address detection to finish.
2293 Dhcp6
->Stop (Dhcp6
);
2296 // Get Duplicate Address Detection Transmits count.
2298 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2299 Status
= Ip6Cfg
->GetData (
2301 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2305 if (EFI_ERROR (Status
)) {
2306 Dhcp6
->Configure (Dhcp6
, NULL
);
2310 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2311 if (EFI_ERROR (Status
)) {
2312 Dhcp6
->Configure (Dhcp6
, NULL
);
2316 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2317 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2318 if (EFI_ERROR (Status
)) {
2319 gBS
->CloseEvent (Timer
);
2320 Dhcp6
->Configure (Dhcp6
, NULL
);
2326 TimerStatus
= gBS
->CheckEvent (Timer
);
2327 if (!EFI_ERROR (TimerStatus
)) {
2328 Status
= Dhcp6
->Start (Dhcp6
);
2330 } while (TimerStatus
== EFI_NOT_READY
);
2332 gBS
->CloseEvent (Timer
);
2334 if (EFI_ERROR (Status
)) {
2335 if (Status
== EFI_ICMP_ERROR
) {
2336 PxeMode
->IcmpErrorReceived
= TRUE
;
2338 Dhcp6
->Configure (Dhcp6
, NULL
);
2343 // Get the acquired IPv6 address and store them.
2345 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2346 if (EFI_ERROR (Status
)) {
2347 Dhcp6
->Stop (Dhcp6
);
2351 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2353 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2354 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2355 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2356 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2357 // to find a valid router address.
2359 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2360 if (Mode
.ClientId
!= NULL
) {
2361 FreePool (Mode
.ClientId
);
2363 if (Mode
.Ia
!= NULL
) {
2367 // Check the selected offer whether BINL retry is needed.
2369 Status
= PxeBcHandleDhcp6Offer (Private
);
2370 if (EFI_ERROR (Status
)) {
2371 Dhcp6
->Stop (Dhcp6
);