2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2016, 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 (6);
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
);
102 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
105 // Append client network device interface option
107 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
108 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
109 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
111 if (Private
->Nii
!= NULL
) {
112 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
113 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
114 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
116 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
117 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
118 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
122 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
125 // Append client system architecture option
127 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
128 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
129 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
130 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
131 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
133 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
136 // Append vendor class option to store the PXE class identifier.
138 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
139 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
140 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
141 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
142 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
144 &OptEnt
.VendorClass
->ClassId
,
145 DEFAULT_CLASS_ID_DATA
,
146 sizeof (PXEBC_CLASS_ID
)
148 PxeBcUintnToAscDecWithFormat (
149 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
150 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
151 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
154 if (Private
->Nii
!= NULL
) {
156 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
157 Private
->Nii
->StringId
,
158 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
160 PxeBcUintnToAscDecWithFormat (
161 Private
->Nii
->MajorVer
,
162 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
163 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
165 PxeBcUintnToAscDecWithFormat (
166 Private
->Nii
->MinorVer
,
167 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
168 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
179 Cache the DHCPv6 packet.
181 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
182 @param[in] Src The pointer to the DHCPv6 packet to be cached.
186 PxeBcCacheDhcp6Packet (
187 IN EFI_DHCP6_PACKET
*Dst
,
188 IN EFI_DHCP6_PACKET
*Src
191 ASSERT (Dst
->Size
>= Src
->Length
);
193 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
194 Dst
->Length
= Src
->Length
;
199 Free all the nodes in the list for boot file.
201 @param[in] Head The pointer to the head of list.
205 PxeBcFreeBootFileOption (
210 LIST_ENTRY
*NextEntry
;
211 PXEBC_DHCP6_OPTION_NODE
*Node
;
213 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
214 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
215 RemoveEntryList (Entry
);
221 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.
223 @param[in] Private Pointer to PxeBc private data.
224 @param[in] HostName Pointer to buffer containing hostname.
225 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
227 @retval EFI_SUCCESS Operation succeeded.
228 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
229 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
230 @retval Others Other errors as indicated.
235 IN PXEBC_PRIVATE_DATA
*Private
,
237 OUT EFI_IPv6_ADDRESS
*IpAddress
241 EFI_DNS6_PROTOCOL
*Dns6
;
242 EFI_DNS6_CONFIG_DATA Dns6ConfigData
;
243 EFI_DNS6_COMPLETION_TOKEN Token
;
244 EFI_HANDLE Dns6Handle
;
245 EFI_IPv6_ADDRESS
*DnsServerList
;
250 DnsServerList
= Private
->DnsServer
;
251 ZeroMem (&Token
, sizeof (EFI_DNS6_COMPLETION_TOKEN
));
254 // Create a DNSv6 child instance and get the protocol.
256 Status
= NetLibCreateServiceChild (
259 &gEfiDns6ServiceBindingProtocolGuid
,
262 if (EFI_ERROR (Status
)) {
266 Status
= gBS
->OpenProtocol (
268 &gEfiDns6ProtocolGuid
,
272 EFI_OPEN_PROTOCOL_BY_DRIVER
274 if (EFI_ERROR (Status
)) {
279 // Configure DNS6 instance for the DNS server address and protocol.
281 ZeroMem (&Dns6ConfigData
, sizeof (EFI_DNS6_CONFIG_DATA
));
282 Dns6ConfigData
.DnsServerCount
= 1;
283 Dns6ConfigData
.DnsServerList
= DnsServerList
;
284 Dns6ConfigData
.EnableDnsCache
= TRUE
;
285 Dns6ConfigData
.Protocol
= EFI_IP_PROTO_UDP
;
286 IP6_COPY_ADDRESS (&Dns6ConfigData
.StationIp
, &Private
->TmpStationIp
.v6
);
287 Status
= Dns6
->Configure (
291 if (EFI_ERROR (Status
)) {
295 Token
.Status
= EFI_NOT_READY
;
298 // Create event to set the IsDone flag when name resolution is finished.
300 Status
= gBS
->CreateEvent (
307 if (EFI_ERROR (Status
)) {
312 // Start asynchronous name resolution.
314 Status
= Dns6
->HostNameToIp (Dns6
, HostName
, &Token
);
315 if (EFI_ERROR (Status
)) {
324 // Name resolution is done, check result.
326 Status
= Token
.Status
;
327 if (!EFI_ERROR (Status
)) {
328 if (Token
.RspData
.H2AData
== NULL
) {
329 Status
= EFI_DEVICE_ERROR
;
332 if (Token
.RspData
.H2AData
->IpCount
== 0 || Token
.RspData
.H2AData
->IpList
== NULL
) {
333 Status
= EFI_DEVICE_ERROR
;
337 // We just return the first IPv6 address from DNS protocol.
339 IP6_COPY_ADDRESS (IpAddress
, Token
.RspData
.H2AData
->IpList
);
340 Status
= EFI_SUCCESS
;
346 if (Token
.Event
!= NULL
) {
347 gBS
->CloseEvent (Token
.Event
);
349 if (Token
.RspData
.H2AData
!= NULL
) {
350 if (Token
.RspData
.H2AData
->IpList
!= NULL
) {
351 FreePool (Token
.RspData
.H2AData
->IpList
);
353 FreePool (Token
.RspData
.H2AData
);
357 Dns6
->Configure (Dns6
, NULL
);
361 &gEfiDns6ProtocolGuid
,
367 if (Dns6Handle
!= NULL
) {
368 NetLibDestroyServiceChild (
371 &gEfiDns6ServiceBindingProtocolGuid
,
376 if (DnsServerList
!= NULL
) {
377 FreePool (DnsServerList
);
384 Parse the Boot File URL option.
386 @param[in] Private Pointer to PxeBc private data.
387 @param[out] FileName The pointer to the boot file name.
388 @param[in, out] SrvAddr The pointer to the boot server address.
389 @param[in] BootFile The pointer to the boot file URL option data.
390 @param[in] Length The length of the boot file URL option data.
392 @retval EFI_ABORTED User cancel operation.
393 @retval EFI_SUCCESS Selected the boot menu successfully.
394 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
398 PxeBcExtractBootFileUrl (
399 IN PXEBC_PRIVATE_DATA
*Private
,
400 OUT UINT8
**FileName
,
401 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
407 CHAR8
*BootFileNamePtr
;
409 UINT16 BootFileNameLen
;
412 CHAR8
*ServerAddressOption
;
413 CHAR8
*ServerAddress
;
416 BOOLEAN IpExpressedUrl
;
420 IpExpressedUrl
= TRUE
;
422 // The format of the Boot File URL option is:
425 // 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
426 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427 // | OPT_BOOTFILE_URL | option-len |
428 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
430 // . bootfile-url (variable length) .
432 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
436 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be
437 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME
438 // As an example where the BOOTFILE_NAME is the EFI loader and
439 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
441 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
443 if (Length
<= PrefixLen
||
444 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
445 return EFI_NOT_FOUND
;
448 BootFile
= BootFile
+ PrefixLen
;
449 Length
= (UINT16
) (Length
- PrefixLen
);
451 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
452 if (TmpStr
== NULL
) {
453 return EFI_OUT_OF_RESOURCES
;
456 CopyMem (TmpStr
, BootFile
, Length
);
457 TmpStr
[Length
] = '\0';
460 // Get the part of SERVER_ADDRESS string.
462 ServerAddressOption
= TmpStr
;
463 if (*ServerAddressOption
== PXEBC_ADDR_START_DELIMITER
) {
464 ServerAddressOption
++;
465 ServerAddress
= ServerAddressOption
;
466 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
470 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
472 return EFI_INVALID_PARAMETER
;
475 *ServerAddress
= '\0';
478 // Convert the string of server address to Ipv6 address format and store it.
480 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
481 if (EFI_ERROR (Status
)) {
487 IpExpressedUrl
= FALSE
;
488 ServerAddress
= ServerAddressOption
;
489 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
493 if (*ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
495 return EFI_INVALID_PARAMETER
;
497 *ServerAddress
= '\0';
499 Len
= AsciiStrSize (ServerAddressOption
);
500 HostName
= AllocateZeroPool (Len
* sizeof (CHAR16
));
501 if (HostName
== NULL
) {
503 return EFI_OUT_OF_RESOURCES
;
505 AsciiStrToUnicodeStrS (
512 // Perform DNS resolution.
514 Status
= PxeBcDns6 (Private
,HostName
, SrvAddr
);
515 if (EFI_ERROR (Status
)) {
522 // Get the part of BOOTFILE_NAME string.
524 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
525 if (IpExpressedUrl
) {
526 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
528 return EFI_INVALID_PARAMETER
;
533 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
534 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
536 // Remove trailing mode=octet if present and ignore. All other modes are
537 // invalid for netboot6, so reject them.
539 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
540 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
542 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
543 return EFI_INVALID_PARAMETER
;
547 // Extract boot file name from URL.
549 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
550 if (BootFileName
== NULL
) {
552 return EFI_OUT_OF_RESOURCES
;
554 *FileName
= (UINT8
*) BootFileName
;
557 // Decode percent-encoding in boot file name.
559 while (*BootFileNamePtr
!= '\0') {
560 if (*BootFileNamePtr
== '%') {
561 TmpChar
= *(BootFileNamePtr
+ 3);
562 *(BootFileNamePtr
+ 3) = '\0';
563 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
565 *(BootFileNamePtr
+ 3) = TmpChar
;
566 BootFileNamePtr
+= 3;
568 *BootFileName
= *BootFileNamePtr
;
573 *BootFileName
= '\0';
583 Parse the Boot File Parameter option.
585 @param[in] BootFilePara The pointer to boot file parameter option data.
586 @param[out] BootFileSize The pointer to the parsed boot file size.
588 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
589 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
593 PxeBcExtractBootFileParam (
594 IN CHAR8
*BootFilePara
,
595 OUT UINT16
*BootFileSize
603 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
604 Length
= NTOHS (Length
);
607 // The BootFile Size should be 1~5 byte ASCII strings
609 if (Length
< 1 || Length
> 5) {
610 return EFI_NOT_FOUND
;
614 // Extract the value of BootFile Size.
616 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
618 for (Index
= 0; Index
< Length
; Index
++) {
619 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
620 return EFI_NOT_FOUND
;
623 Size
= (Size
+ Digit
) * 10;
627 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
628 return EFI_NOT_FOUND
;
631 *BootFileSize
= (UINT16
) Size
;
637 Parse the cached DHCPv6 packet, including all the options.
639 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
641 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
642 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
646 PxeBcParseDhcp6Packet (
647 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
650 EFI_DHCP6_PACKET
*Offer
;
651 EFI_DHCP6_PACKET_OPTION
**Options
;
652 EFI_DHCP6_PACKET_OPTION
*Option
;
653 PXEBC_OFFER_TYPE OfferType
;
654 BOOLEAN IsProxyOffer
;
658 UINT32 EnterpriseNum
;
662 Offer
= &Cache6
->Packet
.Offer
;
663 Options
= Cache6
->OptList
;
665 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
667 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
669 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
672 // OpLen and OpCode here are both stored in network order, since they are from original packet.
674 while (Offset
< Length
) {
676 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
677 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
678 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
680 // The server sends this option to inform the client about an URL to a boot file.
682 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
683 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
684 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
685 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
686 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
687 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
688 Options
[PXEBC_DHCP6_IDX_DNS_SERVER
] = Option
;
691 Offset
+= (NTOHS (Option
->OpLen
) + 4);
692 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
696 // The offer with assigned client address is NOT a proxy offer.
697 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
699 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
700 if (Option
!= NULL
) {
701 Option
= PxeBcParseDhcp6Options (
703 NTOHS (Option
->OpLen
),
704 DHCP6_OPT_STATUS_CODE
706 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
707 IsProxyOffer
= FALSE
;
712 // The offer with "PXEClient" is a pxe offer.
714 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
715 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
717 if (Option
!= NULL
&&
718 NTOHS(Option
->OpLen
) >= 13 &&
719 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
720 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
725 // Determine offer type of the dhcp6 packet.
729 // It's a binl offer only with PXEClient.
731 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
734 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
736 OfferType
= PxeOfferTypeDhcpOnly
;
739 Cache6
->OfferType
= OfferType
;
746 Cache the DHCPv6 ack packet, and parse it on demand.
748 @param[in] Private The pointer to PxeBc private data.
749 @param[in] Ack The pointer to the DHCPv6 ack packet.
750 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
755 IN PXEBC_PRIVATE_DATA
*Private
,
756 IN EFI_DHCP6_PACKET
*Ack
,
760 EFI_PXE_BASE_CODE_MODE
*Mode
;
762 Mode
= Private
->PxeBc
.Mode
;
764 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
768 // Parse the ack packet and store it into mode data if needed.
770 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
771 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
772 Mode
->DhcpAckReceived
= TRUE
;
778 Cache the DHCPv6 proxy offer packet according to the received order.
780 @param[in] Private The pointer to PxeBc private data.
781 @param[in] OfferIndex The received order of offer packets.
785 PxeBcCopyDhcp6Proxy (
786 IN PXEBC_PRIVATE_DATA
*Private
,
790 EFI_PXE_BASE_CODE_MODE
*Mode
;
791 EFI_DHCP6_PACKET
*Offer
;
793 ASSERT (OfferIndex
< Private
->OfferNum
);
794 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
796 Mode
= Private
->PxeBc
.Mode
;
797 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
800 // Cache the proxy offer packet and parse it.
802 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
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
;
813 Seek the address of the first byte of the option header.
815 @param[in] Buf The pointer to the buffer.
816 @param[in] SeekLen The length to seek.
817 @param[in] OptType The option type.
819 @retval NULL If it failed to seek the option.
820 @retval others The position to the option.
824 PxeBcDhcp6SeekOption (
838 while (Cursor
< Buf
+ SeekLen
) {
839 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
840 if (OpCode
== HTONS (OptType
)) {
844 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
845 Cursor
+= (DataLen
+ 4);
853 Build and send out the request packet for the bootfile, and parse the reply.
855 @param[in] Private The pointer to PxeBc private data.
856 @param[in] Index PxeBc option boot item type.
858 @retval EFI_SUCCESS Successfully discovered the boot file.
859 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
860 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
861 @retval Others Failed to discover the boot file.
865 PxeBcRequestBootService (
866 IN PXEBC_PRIVATE_DATA
*Private
,
870 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
871 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
872 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
873 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
875 EFI_DHCP6_PACKET
*Request
;
877 EFI_DHCP6_PACKET
*Reply
;
885 EFI_DHCP6_PACKET
*ProxyOffer
;
888 PxeBc
= &Private
->PxeBc
;
889 Request
= Private
->Dhcp6Request
;
890 ProxyOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
891 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
892 DestPort
= PXEBC_BS_DISCOVER_PORT
;
895 if (Request
== NULL
) {
896 return EFI_DEVICE_ERROR
;
899 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
900 if (Discover
== NULL
) {
901 return EFI_OUT_OF_RESOURCES
;
905 // Build the request packet by the cached request packet before.
907 Discover
->TransactionId
= ProxyOffer
->Dhcp6
.Header
.TransactionId
;
908 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
909 RequestOpt
= Request
->Dhcp6
.Option
;
910 DiscoverOpt
= Discover
->DhcpOptions
;
911 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
912 RequestLen
= DiscoverLen
;
915 // Find Server ID Option from ProxyOffer.
917 Option
= PxeBcDhcp6SeekOption (
918 ProxyOffer
->Dhcp6
.Option
,
919 ProxyOffer
->Length
- 4,
922 if (Option
== NULL
) {
923 return EFI_NOT_FOUND
;
927 // Add Server ID Option.
929 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
930 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
931 DiscoverOpt
+= (OpLen
+ 4);
932 DiscoverLen
+= (OpLen
+ 4);
934 while (RequestLen
< Request
->Length
) {
935 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
936 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
937 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
938 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
939 OpCode
!= DHCP6_OPT_SERVER_ID
942 // Copy all the options except IA option and Server ID
944 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
945 DiscoverOpt
+= (OpLen
+ 4);
946 DiscoverLen
+= (OpLen
+ 4);
948 RequestOpt
+= (OpLen
+ 4);
949 RequestLen
+= (OpLen
+ 4);
953 // Update Elapsed option in the package
955 Option
= PxeBcDhcp6SeekOption (
956 Discover
->DhcpOptions
,
957 (UINT32
)(RequestLen
- 4),
958 DHCP6_OPT_ELAPSED_TIME
960 if (Option
!= NULL
) {
961 CalcElapsedTime (Private
);
962 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
965 Status
= PxeBc
->UdpWrite (
979 if (EFI_ERROR (Status
)) {
984 // Cache the right PXE reply packet here, set valid flag later.
985 // Especially for PXE discover packet, store it into mode data here.
987 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
988 ReadSize
= (UINTN
) Reply
->Size
;
991 // Start Udp6Read instance
993 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
994 if (EFI_ERROR (Status
)) {
998 Status
= PxeBc
->UdpRead (
1000 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
1008 (VOID
*) &Reply
->Dhcp6
1011 // Stop Udp6Read instance
1013 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1015 if (EFI_ERROR (Status
)) {
1022 Reply
->Length
= (UINT32
) ReadSize
;
1029 Retry to request bootfile name by the BINL offer.
1031 @param[in] Private The pointer to PxeBc private data.
1032 @param[in] Index The received order of offer packets.
1034 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
1035 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
1039 PxeBcRetryDhcp6Binl (
1040 IN PXEBC_PRIVATE_DATA
*Private
,
1044 EFI_PXE_BASE_CODE_MODE
*Mode
;
1045 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
1046 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1049 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1050 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
1051 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
1053 Mode
= Private
->PxeBc
.Mode
;
1054 Private
->IsDoDiscover
= FALSE
;
1055 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
1056 if (Offer
->OfferType
== PxeOfferTypeDhcpBinl
) {
1058 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
1061 &Private
->ServerIp
.v6
,
1062 &mAllDhcpRelayAndServersAddress
,
1063 sizeof (EFI_IPv6_ADDRESS
)
1066 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1068 // Parse out the next server address from the last offer, and store it
1070 Status
= PxeBcExtractBootFileUrl (
1072 &Private
->BootFileName
,
1073 &Private
->ServerIp
.v6
,
1074 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
1075 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
1077 if (EFI_ERROR (Status
)) {
1083 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
1085 Status
= PxeBcRequestBootService (Private
, Index
);
1087 if (EFI_ERROR (Status
)) {
1091 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
1092 Status
= PxeBcParseDhcp6Packet (Cache6
);
1093 if (EFI_ERROR (Status
)) {
1097 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
1098 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
1099 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1101 // This BINL ack doesn't have discovery option set or multicast option set
1102 // or bootfile name specified.
1104 return EFI_DEVICE_ERROR
;
1107 Mode
->ProxyOfferReceived
= TRUE
;
1109 &Mode
->ProxyOffer
.Dhcpv6
,
1110 &Cache6
->Packet
.Offer
.Dhcp6
,
1111 Cache6
->Packet
.Offer
.Length
1119 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
1121 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1122 @param[in] RcvdOffer The pointer to the received offer packet.
1126 PxeBcCacheDhcp6Offer (
1127 IN PXEBC_PRIVATE_DATA
*Private
,
1128 IN EFI_DHCP6_PACKET
*RcvdOffer
1131 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1132 EFI_DHCP6_PACKET
*Offer
;
1133 PXEBC_OFFER_TYPE OfferType
;
1135 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
1136 Offer
= &Cache6
->Packet
.Offer
;
1139 // Cache the content of DHCPv6 packet firstly.
1141 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
1144 // Validate the DHCPv6 packet, and parse the options and offer type.
1146 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
1151 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
1153 OfferType
= Cache6
->OfferType
;
1154 ASSERT (OfferType
< PxeOfferTypeMax
);
1155 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
1157 if (IS_PROXY_OFFER (OfferType
)) {
1159 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
1161 Private
->IsProxyRecved
= TRUE
;
1163 if (OfferType
== PxeOfferTypeProxyBinl
) {
1165 // Cache all proxy BINL offers.
1167 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1168 Private
->OfferCount
[OfferType
]++;
1169 } else if (Private
->OfferCount
[OfferType
] > 0) {
1171 // Only cache the first PXE10/WFM11a offer, and discard the others.
1173 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
1174 Private
->OfferCount
[OfferType
] = 1;
1180 // It's a DHCPv6 offer with yiaddr, and cache them all.
1182 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1183 Private
->OfferCount
[OfferType
]++;
1186 Private
->OfferNum
++;
1191 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
1193 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1197 PxeBcSelectDhcp6Offer (
1198 IN PXEBC_PRIVATE_DATA
*Private
1203 PXEBC_OFFER_TYPE OfferType
;
1205 Private
->SelectIndex
= 0;
1207 if (Private
->IsOfferSorted
) {
1209 // Select offer by default policy.
1211 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1213 // 1. DhcpPxe10 offer
1215 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
1217 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
1219 // 2. DhcpWfm11a offer
1221 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1223 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1224 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1226 // 3. DhcpOnly offer and ProxyPxe10 offer.
1228 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1229 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1231 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1232 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1234 // 4. DhcpOnly offer and ProxyWfm11a offer.
1236 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1237 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1239 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1241 // 5. DhcpBinl offer.
1243 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1245 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1246 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1248 // 6. DhcpOnly offer and ProxyBinl offer.
1250 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1251 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1255 // 7. DhcpOnly offer with bootfilename.
1257 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1258 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1259 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1260 Private
->SelectIndex
= OfferIndex
+ 1;
1267 // Select offer by received order.
1269 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1271 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1273 if (IS_PROXY_OFFER (OfferType
)) {
1275 // Skip proxy offers
1280 if (!Private
->IsProxyRecved
&&
1281 OfferType
== PxeOfferTypeDhcpOnly
&&
1282 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1284 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1289 Private
->SelectIndex
= Index
+ 1;
1297 Handle the DHCPv6 offer packet.
1299 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1301 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1302 @retval EFI_NO_RESPONSE No response to the following request packet.
1303 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1307 PxeBcHandleDhcp6Offer (
1308 IN PXEBC_PRIVATE_DATA
*Private
1311 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1313 PXEBC_OFFER_TYPE OfferType
;
1318 ASSERT (Private
->SelectIndex
> 0);
1319 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1320 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1321 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1322 Status
= EFI_SUCCESS
;
1325 // First try to cache DNS server address if DHCP6 offer provides.
1327 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1328 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1329 if (Private
->DnsServer
== NULL
) {
1330 return EFI_OUT_OF_RESOURCES
;
1332 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1335 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1337 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1339 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1340 Status
= EFI_NO_RESPONSE
;
1342 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1344 if (Private
->IsProxyRecved
) {
1346 // DhcpOnly offer is selected, so need try to request bootfilename.
1349 if (Private
->IsOfferSorted
) {
1351 // The proxy offer should be determined if select by default policy.
1352 // IsOfferSorted means all offers are labeled by OfferIndex.
1354 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1356 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1358 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1360 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1362 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1363 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1367 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1368 Status
= EFI_NO_RESPONSE
;
1372 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1374 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1378 // The proxy offer should not be determined if select by received order.
1380 Status
= EFI_NO_RESPONSE
;
1382 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1384 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1386 if (!IS_PROXY_OFFER (OfferType
)) {
1388 // Skip non proxy dhcp offers.
1393 if (OfferType
== PxeOfferTypeProxyBinl
) {
1395 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1397 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1402 Private
->SelectProxyType
= OfferType
;
1404 Status
= EFI_SUCCESS
;
1409 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1411 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1413 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1417 // Othewise, the bootfilename must be included in DhcpOnly offer.
1419 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1423 if (!EFI_ERROR (Status
)) {
1425 // All PXE boot information is ready by now.
1427 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1428 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1436 Unregister the address by Ip6Config protocol.
1438 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1442 PxeBcUnregisterIp6Address (
1443 IN PXEBC_PRIVATE_DATA
*Private
1446 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1448 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1449 // Keep the point and there is no enough requirements to do recovery.
1455 Check whether IP driver could route the message which will be sent to ServerIp address.
1457 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1458 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1460 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1461 @param[in] TimeOutInSecond Timeout value in seconds.
1462 @param[out] GatewayAddr Pointer to store the gateway IP address.
1464 @retval EFI_SUCCESS Found a valid gateway address successfully.
1465 @retval EFI_TIMEOUT The operation is time out.
1466 @retval Other Unexpect error happened.
1470 PxeBcCheckRouteTable (
1471 IN PXEBC_PRIVATE_DATA
*Private
,
1472 IN UINTN TimeOutInSecond
,
1473 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1477 EFI_IP6_PROTOCOL
*Ip6
;
1478 EFI_IP6_MODE_DATA Ip6ModeData
;
1480 EFI_EVENT TimeOutEvt
;
1482 BOOLEAN GatewayIsFound
;
1484 ASSERT (GatewayAddr
!= NULL
);
1485 ASSERT (Private
!= NULL
);
1488 GatewayIsFound
= FALSE
;
1491 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1494 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1495 if (EFI_ERROR (Status
)) {
1500 // Find out the gateway address which can route the message which send to ServerIp.
1502 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1503 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1504 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1505 GatewayIsFound
= TRUE
;
1510 if (Ip6ModeData
.AddressList
!= NULL
) {
1511 FreePool (Ip6ModeData
.AddressList
);
1513 if (Ip6ModeData
.GroupTable
!= NULL
) {
1514 FreePool (Ip6ModeData
.GroupTable
);
1516 if (Ip6ModeData
.RouteTable
!= NULL
) {
1517 FreePool (Ip6ModeData
.RouteTable
);
1519 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1520 FreePool (Ip6ModeData
.NeighborCache
);
1522 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1523 FreePool (Ip6ModeData
.PrefixTable
);
1525 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1526 FreePool (Ip6ModeData
.IcmpTypeList
);
1529 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
1536 // Delay 1 second then recheck it again.
1538 if (TimeOutEvt
== NULL
) {
1539 Status
= gBS
->CreateEvent (
1546 if (EFI_ERROR (Status
)) {
1551 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
1552 if (EFI_ERROR (Status
)) {
1555 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1561 if (TimeOutEvt
!= NULL
) {
1562 gBS
->CloseEvent (TimeOutEvt
);
1565 if (GatewayIsFound
) {
1566 Status
= EFI_SUCCESS
;
1567 } else if (RetryCount
== TimeOutInSecond
) {
1568 Status
= EFI_TIMEOUT
;
1575 Register the ready station address and gateway by Ip6Config protocol.
1577 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1578 @param[in] Address The pointer to the ready address.
1580 @retval EFI_SUCCESS Registered the address succesfully.
1581 @retval Others Failed to register the address.
1585 PxeBcRegisterIp6Address (
1586 IN PXEBC_PRIVATE_DATA
*Private
,
1587 IN EFI_IPv6_ADDRESS
*Address
1590 EFI_IP6_PROTOCOL
*Ip6
;
1591 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1592 EFI_IP6_CONFIG_POLICY Policy
;
1593 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1594 EFI_IPv6_ADDRESS GatewayAddr
;
1596 EFI_EVENT MappedEvt
;
1599 EFI_IPv6_ADDRESS
*Ip6Addr
;
1602 Status
= EFI_SUCCESS
;
1605 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1606 Ip6Cfg
= Private
->Ip6Cfg
;
1610 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1611 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1613 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1614 if (EFI_ERROR (Status
)) {
1619 // Retrieve the gateway address from IP6 route table.
1621 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1622 if (EFI_ERROR (Status
)) {
1627 // There is no channel between IP6 and PXE driver about address setting,
1628 // so it has to set the new address by Ip6ConfigProtocol manually.
1630 Policy
= Ip6ConfigPolicyManual
;
1631 Status
= Ip6Cfg
->SetData (
1633 Ip6ConfigDataTypePolicy
,
1634 sizeof(EFI_IP6_CONFIG_POLICY
),
1637 if (EFI_ERROR (Status
)) {
1639 // There is no need to recover later.
1641 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1646 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1648 Status
= gBS
->CreateEvent (
1652 &Private
->IsAddressOk
,
1655 if (EFI_ERROR (Status
)) {
1659 Private
->IsAddressOk
= FALSE
;
1660 Status
= Ip6Cfg
->RegisterDataNotify (
1662 Ip6ConfigDataTypeManualAddress
,
1665 if (EFI_ERROR(Status
)) {
1669 Status
= Ip6Cfg
->SetData (
1671 Ip6ConfigDataTypeManualAddress
,
1672 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1675 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1677 } else if (Status
== EFI_NOT_READY
) {
1679 // Poll the network until the asynchronous process is finished.
1681 while (!Private
->IsAddressOk
) {
1685 // Check whether the IP6 address setting is successed.
1688 Status
= Ip6Cfg
->GetData (
1690 Ip6ConfigDataTypeManualAddress
,
1694 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
1695 Status
= EFI_DEVICE_ERROR
;
1699 Ip6Addr
= AllocatePool (DataSize
);
1700 if (Ip6Addr
== NULL
) {
1701 return EFI_OUT_OF_RESOURCES
;
1703 Status
= Ip6Cfg
->GetData (
1705 Ip6ConfigDataTypeManualAddress
,
1709 if (EFI_ERROR (Status
)) {
1710 Status
= EFI_DEVICE_ERROR
;
1714 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1715 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1719 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1720 Status
= EFI_ABORTED
;
1726 // Set the default gateway address back if needed.
1728 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1729 Status
= Ip6Cfg
->SetData (
1731 Ip6ConfigDataTypeGateway
,
1732 sizeof (EFI_IPv6_ADDRESS
),
1735 if (EFI_ERROR (Status
)) {
1741 if (MappedEvt
!= NULL
) {
1742 Ip6Cfg
->UnregisterDataNotify (
1744 Ip6ConfigDataTypeManualAddress
,
1747 gBS
->CloseEvent (MappedEvt
);
1749 if (Ip6Addr
!= NULL
) {
1756 Set the IP6 policy to Automatic.
1758 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1760 @retval EFI_SUCCESS Switch the IP policy succesfully.
1761 @retval Others Unexpect error happened.
1766 IN PXEBC_PRIVATE_DATA
*Private
1769 EFI_IP6_CONFIG_POLICY Policy
;
1771 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1774 Ip6Cfg
= Private
->Ip6Cfg
;
1775 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1778 // Get and store the current policy of IP6 driver.
1780 Status
= Ip6Cfg
->GetData (
1782 Ip6ConfigDataTypePolicy
,
1786 if (EFI_ERROR (Status
)) {
1790 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1791 Policy
= Ip6ConfigPolicyAutomatic
;
1792 Status
= Ip6Cfg
->SetData (
1794 Ip6ConfigDataTypePolicy
,
1795 sizeof(EFI_IP6_CONFIG_POLICY
),
1798 if (EFI_ERROR (Status
)) {
1800 // There is no need to recover later.
1802 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1810 This function will register the station IP address and flush IP instance to start using the new IP address.
1812 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1814 @retval EFI_SUCCESS The new IP address has been configured successfully.
1815 @retval Others Failed to configure the address.
1819 PxeBcSetIp6Address (
1820 IN PXEBC_PRIVATE_DATA
*Private
1824 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1826 Dhcp6
= Private
->Dhcp6
;
1828 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1829 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1831 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1832 if (EFI_ERROR (Status
)) {
1833 Dhcp6
->Stop (Dhcp6
);
1837 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1838 if (EFI_ERROR (Status
)) {
1839 PxeBcUnregisterIp6Address (Private
);
1840 Dhcp6
->Stop (Dhcp6
);
1844 AsciiPrint ("\n Station IP address is ");
1845 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1851 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1852 to intercept events that occurred in the configuration process.
1854 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1855 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1856 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1857 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1859 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1860 @param[out] NewPacket The packet that is used to replace the Packet above.
1862 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1863 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1864 driver will continue to wait for more packets.
1865 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1870 PxeBcDhcp6CallBack (
1871 IN EFI_DHCP6_PROTOCOL
*This
,
1873 IN EFI_DHCP6_STATE CurrentState
,
1874 IN EFI_DHCP6_EVENT Dhcp6Event
,
1875 IN EFI_DHCP6_PACKET
*Packet
,
1876 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1879 PXEBC_PRIVATE_DATA
*Private
;
1880 EFI_PXE_BASE_CODE_MODE
*Mode
;
1881 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1882 EFI_DHCP6_PACKET
*SelectAd
;
1886 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1887 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1888 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1889 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1890 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1894 ASSERT (Packet
!= NULL
);
1896 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1897 Mode
= Private
->PxeBc
.Mode
;
1898 Callback
= Private
->PxeBcCallback
;
1901 // Callback to user when any traffic ocurred if has.
1903 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1904 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1905 Status
= Callback
->Callback (
1910 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1912 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1917 Status
= EFI_SUCCESS
;
1919 switch (Dhcp6Event
) {
1921 case Dhcp6SendSolicit
:
1922 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1924 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1926 Status
= EFI_ABORTED
;
1931 // Record the first Solicate msg time
1933 if (Private
->SolicitTimes
== 0) {
1934 CalcElapsedTime (Private
);
1935 Private
->SolicitTimes
++;
1938 // Cache the dhcp discover packet to mode data directly.
1940 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1943 case Dhcp6RcvdAdvertise
:
1944 Status
= EFI_NOT_READY
;
1945 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1947 // Ignore the incoming packets which exceed the maximum length.
1951 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1953 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1954 // the OfferIndex and OfferCount.
1956 PxeBcCacheDhcp6Offer (Private
, Packet
);
1960 case Dhcp6SendRequest
:
1961 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1963 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1965 Status
= EFI_ABORTED
;
1970 // Store the request packet as seed packet for discover.
1972 if (Private
->Dhcp6Request
!= NULL
) {
1973 FreePool (Private
->Dhcp6Request
);
1975 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1976 if (Private
->Dhcp6Request
!= NULL
) {
1977 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1981 case Dhcp6SelectAdvertise
:
1983 // Select offer by the default policy or by order, and record the SelectIndex
1984 // and SelectProxyType.
1986 PxeBcSelectDhcp6Offer (Private
);
1988 if (Private
->SelectIndex
== 0) {
1989 Status
= EFI_ABORTED
;
1991 ASSERT (NewPacket
!= NULL
);
1992 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1993 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1994 ASSERT (*NewPacket
!= NULL
);
1995 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1999 case Dhcp6RcvdReply
:
2000 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
2002 // Abort the DHCP if the Peply packet exceeds the maximum length.
2004 Status
= EFI_ABORTED
;
2008 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
2009 // without verification.
2011 ASSERT (Private
->SelectIndex
!= 0);
2012 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
2024 Build and send out the request packet for the bootfile, and parse the reply.
2026 @param[in] Private The pointer to PxeBc private data.
2027 @param[in] Type PxeBc option boot item type.
2028 @param[in] Layer The pointer to option boot item layer.
2029 @param[in] UseBis Use BIS or not.
2030 @param[in] DestIp The pointer to the server address.
2032 @retval EFI_SUCCESS Successfully discovered the boot file.
2033 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2034 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2035 @retval Others Failed to discover the boot file.
2039 PxeBcDhcp6Discover (
2040 IN PXEBC_PRIVATE_DATA
*Private
,
2044 IN EFI_IP_ADDRESS
*DestIp
2047 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2048 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2049 EFI_PXE_BASE_CODE_MODE
*Mode
;
2050 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2051 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2053 EFI_DHCP6_PACKET
*Request
;
2055 EFI_DHCP6_PACKET
*Reply
;
2064 PxeBc
= &Private
->PxeBc
;
2066 Request
= Private
->Dhcp6Request
;
2067 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2068 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2070 if (!UseBis
&& Layer
!= NULL
) {
2071 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2074 if (Request
== NULL
) {
2075 return EFI_DEVICE_ERROR
;
2078 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2079 if (Discover
== NULL
) {
2080 return EFI_OUT_OF_RESOURCES
;
2084 // Build the discover packet by the cached request packet before.
2086 Xid
= NET_RANDOM (NetRandomInitSeed ());
2087 Discover
->TransactionId
= HTONL (Xid
);
2088 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2089 RequestOpt
= Request
->Dhcp6
.Option
;
2090 DiscoverOpt
= Discover
->DhcpOptions
;
2091 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2092 RequestLen
= DiscoverLen
;
2094 while (RequestLen
< Request
->Length
) {
2095 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
2096 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
2097 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
2098 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
2100 // Copy all the options except IA option.
2102 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2103 DiscoverOpt
+= (OpLen
+ 4);
2104 DiscoverLen
+= (OpLen
+ 4);
2106 RequestOpt
+= (OpLen
+ 4);
2107 RequestLen
+= (OpLen
+ 4);
2110 Status
= PxeBc
->UdpWrite (
2116 &Private
->StationIp
,
2123 if (EFI_ERROR (Status
)) {
2128 // Cache the right PXE reply packet here, set valid flag later.
2129 // Especially for PXE discover packet, store it into mode data here.
2131 if (Private
->IsDoDiscover
) {
2132 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2133 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2135 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2137 ReadSize
= (UINTN
) Reply
->Size
;
2140 // Start Udp6Read instance
2142 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2143 if (EFI_ERROR (Status
)) {
2147 Status
= PxeBc
->UdpRead (
2149 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2157 (VOID
*) &Reply
->Dhcp6
2160 // Stop Udp6Read instance
2162 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2163 if (EFI_ERROR (Status
)) {
2172 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2174 @param[in] Private The pointer to PxeBc private data.
2175 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2177 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2178 @retval Others Failed to finish the S.A.R.R. process.
2183 IN PXEBC_PRIVATE_DATA
*Private
,
2184 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2187 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2188 EFI_DHCP6_CONFIG_DATA Config
;
2189 EFI_DHCP6_MODE_DATA Mode
;
2190 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2191 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2192 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2195 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2196 EFI_STATUS TimerStatus
;
2198 UINT64 GetMappingTimeOut
;
2200 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2202 Status
= EFI_SUCCESS
;
2203 PxeMode
= Private
->PxeBc
.Mode
;
2204 Ip6Cfg
= Private
->Ip6Cfg
;
2208 // Build option list for the request packet.
2210 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2211 ASSERT (OptCount
> 0);
2213 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2214 if (Retransmit
== NULL
) {
2215 return EFI_OUT_OF_RESOURCES
;
2218 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2219 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2221 Config
.OptionCount
= OptCount
;
2222 Config
.OptionList
= OptList
;
2223 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2224 Config
.CallbackContext
= Private
;
2225 Config
.IaInfoEvent
= NULL
;
2226 Config
.RapidCommit
= FALSE
;
2227 Config
.ReconfigureAccept
= FALSE
;
2228 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2229 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2230 Config
.SolicitRetransmission
= Retransmit
;
2231 Retransmit
->Irt
= 4;
2232 Retransmit
->Mrc
= 4;
2233 Retransmit
->Mrt
= 32;
2234 Retransmit
->Mrd
= 60;
2237 // Configure the DHCPv6 instance for PXE boot.
2239 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2240 FreePool (Retransmit
);
2241 if (EFI_ERROR (Status
)) {
2246 // Initialize the record fields for DHCPv6 offer in private data.
2248 Private
->IsProxyRecved
= FALSE
;
2249 Private
->OfferNum
= 0;
2250 Private
->SelectIndex
= 0;
2251 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2252 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2256 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2258 Status
= Dhcp6
->Start (Dhcp6
);
2259 if (Status
== EFI_NO_MAPPING
) {
2261 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2262 // and wait for duplicate address detection to finish.
2264 Dhcp6
->Stop (Dhcp6
);
2267 // Get Duplicate Address Detection Transmits count.
2269 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2270 Status
= Ip6Cfg
->GetData (
2272 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2276 if (EFI_ERROR (Status
)) {
2277 Dhcp6
->Configure (Dhcp6
, NULL
);
2281 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2282 if (EFI_ERROR (Status
)) {
2283 Dhcp6
->Configure (Dhcp6
, NULL
);
2287 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2288 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2289 if (EFI_ERROR (Status
)) {
2290 gBS
->CloseEvent (Timer
);
2291 Dhcp6
->Configure (Dhcp6
, NULL
);
2297 TimerStatus
= gBS
->CheckEvent (Timer
);
2298 if (!EFI_ERROR (TimerStatus
)) {
2299 Status
= Dhcp6
->Start (Dhcp6
);
2301 } while (TimerStatus
== EFI_NOT_READY
);
2303 gBS
->CloseEvent (Timer
);
2305 if (EFI_ERROR (Status
)) {
2306 if (Status
== EFI_ICMP_ERROR
) {
2307 PxeMode
->IcmpErrorReceived
= TRUE
;
2309 Dhcp6
->Configure (Dhcp6
, NULL
);
2314 // Get the acquired IPv6 address and store them.
2316 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2317 if (EFI_ERROR (Status
)) {
2318 Dhcp6
->Stop (Dhcp6
);
2322 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2324 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2325 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2326 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2327 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2328 // to find a valid router address.
2330 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2331 if (Mode
.ClientId
!= NULL
) {
2332 FreePool (Mode
.ClientId
);
2334 if (Mode
.Ia
!= NULL
) {
2338 // Check the selected offer whether BINL retry is needed.
2340 Status
= PxeBcHandleDhcp6Offer (Private
);
2341 if (EFI_ERROR (Status
)) {
2342 Dhcp6
->Stop (Dhcp6
);