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.
1306 PxeBcHandleDhcp6Offer (
1307 IN PXEBC_PRIVATE_DATA
*Private
1310 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1312 PXEBC_OFFER_TYPE OfferType
;
1317 ASSERT (Private
->SelectIndex
> 0);
1318 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1319 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1320 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1321 Status
= EFI_SUCCESS
;
1324 // First try to cache DNS server address if DHCP6 offer provides.
1326 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1327 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1328 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1331 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1333 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1335 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1336 Status
= EFI_NO_RESPONSE
;
1338 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1340 if (Private
->IsProxyRecved
) {
1342 // DhcpOnly offer is selected, so need try to request bootfilename.
1345 if (Private
->IsOfferSorted
) {
1347 // The proxy offer should be determined if select by default policy.
1348 // IsOfferSorted means all offers are labeled by OfferIndex.
1350 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1352 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1354 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1356 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1358 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1359 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1363 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1364 Status
= EFI_NO_RESPONSE
;
1368 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1370 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1374 // The proxy offer should not be determined if select by received order.
1376 Status
= EFI_NO_RESPONSE
;
1378 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1380 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1382 if (!IS_PROXY_OFFER (OfferType
)) {
1384 // Skip non proxy dhcp offers.
1389 if (OfferType
== PxeOfferTypeProxyBinl
) {
1391 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1393 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1398 Private
->SelectProxyType
= OfferType
;
1400 Status
= EFI_SUCCESS
;
1405 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1407 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1409 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1413 // Othewise, the bootfilename must be included in DhcpOnly offer.
1415 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1419 if (!EFI_ERROR (Status
)) {
1421 // All PXE boot information is ready by now.
1423 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1424 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1432 Unregister the address by Ip6Config protocol.
1434 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1438 PxeBcUnregisterIp6Address (
1439 IN PXEBC_PRIVATE_DATA
*Private
1442 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1444 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1445 // Keep the point and there is no enough requirements to do recovery.
1451 Check whether IP driver could route the message which will be sent to ServerIp address.
1453 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1454 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1456 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1457 @param[in] TimeOutInSecond Timeout value in seconds.
1458 @param[out] GatewayAddr Pointer to store the gateway IP address.
1460 @retval EFI_SUCCESS Found a valid gateway address successfully.
1461 @retval EFI_TIMEOUT The operation is time out.
1462 @retval Other Unexpect error happened.
1466 PxeBcCheckRouteTable (
1467 IN PXEBC_PRIVATE_DATA
*Private
,
1468 IN UINTN TimeOutInSecond
,
1469 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1473 EFI_IP6_PROTOCOL
*Ip6
;
1474 EFI_IP6_MODE_DATA Ip6ModeData
;
1476 EFI_EVENT TimeOutEvt
;
1478 BOOLEAN GatewayIsFound
;
1480 ASSERT (GatewayAddr
!= NULL
);
1481 ASSERT (Private
!= NULL
);
1484 GatewayIsFound
= FALSE
;
1487 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1490 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1491 if (EFI_ERROR (Status
)) {
1496 // Find out the gateway address which can route the message which send to ServerIp.
1498 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1499 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1500 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1501 GatewayIsFound
= TRUE
;
1506 if (Ip6ModeData
.AddressList
!= NULL
) {
1507 FreePool (Ip6ModeData
.AddressList
);
1509 if (Ip6ModeData
.GroupTable
!= NULL
) {
1510 FreePool (Ip6ModeData
.GroupTable
);
1512 if (Ip6ModeData
.RouteTable
!= NULL
) {
1513 FreePool (Ip6ModeData
.RouteTable
);
1515 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1516 FreePool (Ip6ModeData
.NeighborCache
);
1518 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1519 FreePool (Ip6ModeData
.PrefixTable
);
1521 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1522 FreePool (Ip6ModeData
.IcmpTypeList
);
1525 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
1532 // Delay 1 second then recheck it again.
1534 if (TimeOutEvt
== NULL
) {
1535 Status
= gBS
->CreateEvent (
1542 if (EFI_ERROR (Status
)) {
1547 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
1548 if (EFI_ERROR (Status
)) {
1551 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1557 if (TimeOutEvt
!= NULL
) {
1558 gBS
->CloseEvent (TimeOutEvt
);
1561 if (GatewayIsFound
) {
1562 Status
= EFI_SUCCESS
;
1563 } else if (RetryCount
== TimeOutInSecond
) {
1564 Status
= EFI_TIMEOUT
;
1571 Register the ready station address and gateway by Ip6Config protocol.
1573 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1574 @param[in] Address The pointer to the ready address.
1576 @retval EFI_SUCCESS Registered the address succesfully.
1577 @retval Others Failed to register the address.
1581 PxeBcRegisterIp6Address (
1582 IN PXEBC_PRIVATE_DATA
*Private
,
1583 IN EFI_IPv6_ADDRESS
*Address
1586 EFI_IP6_PROTOCOL
*Ip6
;
1587 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1588 EFI_IP6_CONFIG_POLICY Policy
;
1589 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1590 EFI_IPv6_ADDRESS GatewayAddr
;
1592 EFI_EVENT MappedEvt
;
1595 EFI_IPv6_ADDRESS
*Ip6Addr
;
1598 Status
= EFI_SUCCESS
;
1601 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1602 Ip6Cfg
= Private
->Ip6Cfg
;
1606 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1607 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1609 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1610 if (EFI_ERROR (Status
)) {
1615 // Retrieve the gateway address from IP6 route table.
1617 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1618 if (EFI_ERROR (Status
)) {
1623 // There is no channel between IP6 and PXE driver about address setting,
1624 // so it has to set the new address by Ip6ConfigProtocol manually.
1626 Policy
= Ip6ConfigPolicyManual
;
1627 Status
= Ip6Cfg
->SetData (
1629 Ip6ConfigDataTypePolicy
,
1630 sizeof(EFI_IP6_CONFIG_POLICY
),
1633 if (EFI_ERROR (Status
)) {
1635 // There is no need to recover later.
1637 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1642 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1644 Status
= gBS
->CreateEvent (
1648 &Private
->IsAddressOk
,
1651 if (EFI_ERROR (Status
)) {
1655 Private
->IsAddressOk
= FALSE
;
1656 Status
= Ip6Cfg
->RegisterDataNotify (
1658 Ip6ConfigDataTypeManualAddress
,
1661 if (EFI_ERROR(Status
)) {
1665 Status
= Ip6Cfg
->SetData (
1667 Ip6ConfigDataTypeManualAddress
,
1668 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1671 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1673 } else if (Status
== EFI_NOT_READY
) {
1675 // Poll the network until the asynchronous process is finished.
1677 while (!Private
->IsAddressOk
) {
1681 // Check whether the IP6 address setting is successed.
1684 Status
= Ip6Cfg
->GetData (
1686 Ip6ConfigDataTypeManualAddress
,
1690 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
1691 Status
= EFI_DEVICE_ERROR
;
1695 Ip6Addr
= AllocatePool (DataSize
);
1696 if (Ip6Addr
== NULL
) {
1697 return EFI_OUT_OF_RESOURCES
;
1699 Status
= Ip6Cfg
->GetData (
1701 Ip6ConfigDataTypeManualAddress
,
1705 if (EFI_ERROR (Status
)) {
1706 Status
= EFI_DEVICE_ERROR
;
1710 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1711 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1715 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1716 Status
= EFI_ABORTED
;
1722 // Set the default gateway address back if needed.
1724 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1725 Status
= Ip6Cfg
->SetData (
1727 Ip6ConfigDataTypeGateway
,
1728 sizeof (EFI_IPv6_ADDRESS
),
1731 if (EFI_ERROR (Status
)) {
1737 if (MappedEvt
!= NULL
) {
1738 Ip6Cfg
->UnregisterDataNotify (
1740 Ip6ConfigDataTypeManualAddress
,
1743 gBS
->CloseEvent (MappedEvt
);
1745 if (Ip6Addr
!= NULL
) {
1752 Set the IP6 policy to Automatic.
1754 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1756 @retval EFI_SUCCESS Switch the IP policy succesfully.
1757 @retval Others Unexpect error happened.
1762 IN PXEBC_PRIVATE_DATA
*Private
1765 EFI_IP6_CONFIG_POLICY Policy
;
1767 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1770 Ip6Cfg
= Private
->Ip6Cfg
;
1771 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1774 // Get and store the current policy of IP6 driver.
1776 Status
= Ip6Cfg
->GetData (
1778 Ip6ConfigDataTypePolicy
,
1782 if (EFI_ERROR (Status
)) {
1786 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1787 Policy
= Ip6ConfigPolicyAutomatic
;
1788 Status
= Ip6Cfg
->SetData (
1790 Ip6ConfigDataTypePolicy
,
1791 sizeof(EFI_IP6_CONFIG_POLICY
),
1794 if (EFI_ERROR (Status
)) {
1796 // There is no need to recover later.
1798 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1806 This function will register the station IP address and flush IP instance to start using the new IP address.
1808 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1810 @retval EFI_SUCCESS The new IP address has been configured successfully.
1811 @retval Others Failed to configure the address.
1815 PxeBcSetIp6Address (
1816 IN PXEBC_PRIVATE_DATA
*Private
1820 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1822 Dhcp6
= Private
->Dhcp6
;
1824 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1825 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1827 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1828 if (EFI_ERROR (Status
)) {
1829 Dhcp6
->Stop (Dhcp6
);
1833 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1834 if (EFI_ERROR (Status
)) {
1835 PxeBcUnregisterIp6Address (Private
);
1836 Dhcp6
->Stop (Dhcp6
);
1840 AsciiPrint ("\n Station IP address is ");
1841 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1847 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1848 to intercept events that occurred in the configuration process.
1850 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1851 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1852 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1853 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1855 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1856 @param[out] NewPacket The packet that is used to replace the Packet above.
1858 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1859 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1860 driver will continue to wait for more packets.
1861 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1866 PxeBcDhcp6CallBack (
1867 IN EFI_DHCP6_PROTOCOL
*This
,
1869 IN EFI_DHCP6_STATE CurrentState
,
1870 IN EFI_DHCP6_EVENT Dhcp6Event
,
1871 IN EFI_DHCP6_PACKET
*Packet
,
1872 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1875 PXEBC_PRIVATE_DATA
*Private
;
1876 EFI_PXE_BASE_CODE_MODE
*Mode
;
1877 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1878 EFI_DHCP6_PACKET
*SelectAd
;
1882 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1883 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1884 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1885 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1886 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1890 ASSERT (Packet
!= NULL
);
1892 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1893 Mode
= Private
->PxeBc
.Mode
;
1894 Callback
= Private
->PxeBcCallback
;
1897 // Callback to user when any traffic ocurred if has.
1899 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1900 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1901 Status
= Callback
->Callback (
1906 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1908 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1913 Status
= EFI_SUCCESS
;
1915 switch (Dhcp6Event
) {
1917 case Dhcp6SendSolicit
:
1919 // Record the first Solicate msg time
1921 if (Private
->SolicitTimes
== 0) {
1922 CalcElapsedTime (Private
);
1923 Private
->SolicitTimes
++;
1926 // Cache the dhcp discover packet to mode data directly.
1928 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1931 case Dhcp6RcvdAdvertise
:
1932 Status
= EFI_NOT_READY
;
1933 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1935 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1936 // the OfferIndex and OfferCount.
1938 PxeBcCacheDhcp6Offer (Private
, Packet
);
1942 case Dhcp6SendRequest
:
1944 // Store the request packet as seed packet for discover.
1946 if (Private
->Dhcp6Request
!= NULL
) {
1947 FreePool (Private
->Dhcp6Request
);
1949 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1950 if (Private
->Dhcp6Request
!= NULL
) {
1951 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1955 case Dhcp6SelectAdvertise
:
1957 // Select offer by the default policy or by order, and record the SelectIndex
1958 // and SelectProxyType.
1960 PxeBcSelectDhcp6Offer (Private
);
1962 if (Private
->SelectIndex
== 0) {
1963 Status
= EFI_ABORTED
;
1965 ASSERT (NewPacket
!= NULL
);
1966 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1967 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1968 ASSERT (*NewPacket
!= NULL
);
1969 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1973 case Dhcp6RcvdReply
:
1975 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1976 // without verification.
1978 ASSERT (Private
->SelectIndex
!= 0);
1979 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1991 Build and send out the request packet for the bootfile, and parse the reply.
1993 @param[in] Private The pointer to PxeBc private data.
1994 @param[in] Type PxeBc option boot item type.
1995 @param[in] Layer The pointer to option boot item layer.
1996 @param[in] UseBis Use BIS or not.
1997 @param[in] DestIp The pointer to the server address.
1999 @retval EFI_SUCCESS Successfully discovered the boot file.
2000 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2001 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2002 @retval Others Failed to discover the boot file.
2006 PxeBcDhcp6Discover (
2007 IN PXEBC_PRIVATE_DATA
*Private
,
2011 IN EFI_IP_ADDRESS
*DestIp
2014 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2015 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2016 EFI_PXE_BASE_CODE_MODE
*Mode
;
2017 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2018 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2020 EFI_DHCP6_PACKET
*Request
;
2022 EFI_DHCP6_PACKET
*Reply
;
2031 PxeBc
= &Private
->PxeBc
;
2033 Request
= Private
->Dhcp6Request
;
2034 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2035 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2037 if (!UseBis
&& Layer
!= NULL
) {
2038 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2041 if (Request
== NULL
) {
2042 return EFI_DEVICE_ERROR
;
2045 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2046 if (Discover
== NULL
) {
2047 return EFI_OUT_OF_RESOURCES
;
2051 // Build the discover packet by the cached request packet before.
2053 Xid
= NET_RANDOM (NetRandomInitSeed ());
2054 Discover
->TransactionId
= HTONL (Xid
);
2055 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2056 RequestOpt
= Request
->Dhcp6
.Option
;
2057 DiscoverOpt
= Discover
->DhcpOptions
;
2058 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2059 RequestLen
= DiscoverLen
;
2061 while (RequestLen
< Request
->Length
) {
2062 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
2063 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
2064 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
2065 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
2067 // Copy all the options except IA option.
2069 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2070 DiscoverOpt
+= (OpLen
+ 4);
2071 DiscoverLen
+= (OpLen
+ 4);
2073 RequestOpt
+= (OpLen
+ 4);
2074 RequestLen
+= (OpLen
+ 4);
2077 Status
= PxeBc
->UdpWrite (
2083 &Private
->StationIp
,
2090 if (EFI_ERROR (Status
)) {
2095 // Cache the right PXE reply packet here, set valid flag later.
2096 // Especially for PXE discover packet, store it into mode data here.
2098 if (Private
->IsDoDiscover
) {
2099 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2100 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2102 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2104 ReadSize
= (UINTN
) Reply
->Size
;
2107 // Start Udp6Read instance
2109 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2110 if (EFI_ERROR (Status
)) {
2114 Status
= PxeBc
->UdpRead (
2116 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2124 (VOID
*) &Reply
->Dhcp6
2127 // Stop Udp6Read instance
2129 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2130 if (EFI_ERROR (Status
)) {
2139 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2141 @param[in] Private The pointer to PxeBc private data.
2142 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2144 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2145 @retval Others Failed to finish the S.A.R.R. process.
2150 IN PXEBC_PRIVATE_DATA
*Private
,
2151 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2154 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2155 EFI_DHCP6_CONFIG_DATA Config
;
2156 EFI_DHCP6_MODE_DATA Mode
;
2157 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2158 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2159 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2162 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2163 EFI_STATUS TimerStatus
;
2165 UINT64 GetMappingTimeOut
;
2167 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2169 Status
= EFI_SUCCESS
;
2170 PxeMode
= Private
->PxeBc
.Mode
;
2171 Ip6Cfg
= Private
->Ip6Cfg
;
2175 // Build option list for the request packet.
2177 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2178 ASSERT (OptCount
> 0);
2180 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2181 if (Retransmit
== NULL
) {
2182 return EFI_OUT_OF_RESOURCES
;
2185 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2186 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2188 Config
.OptionCount
= OptCount
;
2189 Config
.OptionList
= OptList
;
2190 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2191 Config
.CallbackContext
= Private
;
2192 Config
.IaInfoEvent
= NULL
;
2193 Config
.RapidCommit
= FALSE
;
2194 Config
.ReconfigureAccept
= FALSE
;
2195 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2196 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2197 Config
.SolicitRetransmission
= Retransmit
;
2198 Retransmit
->Irt
= 4;
2199 Retransmit
->Mrc
= 4;
2200 Retransmit
->Mrt
= 32;
2201 Retransmit
->Mrd
= 60;
2204 // Configure the DHCPv6 instance for PXE boot.
2206 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2207 FreePool (Retransmit
);
2208 if (EFI_ERROR (Status
)) {
2213 // Initialize the record fields for DHCPv6 offer in private data.
2215 Private
->IsProxyRecved
= FALSE
;
2216 Private
->OfferNum
= 0;
2217 Private
->SelectIndex
= 0;
2218 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2219 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2223 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2225 Status
= Dhcp6
->Start (Dhcp6
);
2226 if (Status
== EFI_NO_MAPPING
) {
2228 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2229 // and wait for duplicate address detection to finish.
2231 Dhcp6
->Stop (Dhcp6
);
2234 // Get Duplicate Address Detection Transmits count.
2236 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2237 Status
= Ip6Cfg
->GetData (
2239 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2243 if (EFI_ERROR (Status
)) {
2244 Dhcp6
->Configure (Dhcp6
, NULL
);
2248 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2249 if (EFI_ERROR (Status
)) {
2250 Dhcp6
->Configure (Dhcp6
, NULL
);
2254 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2255 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2256 if (EFI_ERROR (Status
)) {
2257 gBS
->CloseEvent (Timer
);
2258 Dhcp6
->Configure (Dhcp6
, NULL
);
2264 TimerStatus
= gBS
->CheckEvent (Timer
);
2265 if (!EFI_ERROR (TimerStatus
)) {
2266 Status
= Dhcp6
->Start (Dhcp6
);
2268 } while (TimerStatus
== EFI_NOT_READY
);
2270 gBS
->CloseEvent (Timer
);
2272 if (EFI_ERROR (Status
)) {
2273 if (Status
== EFI_ICMP_ERROR
) {
2274 PxeMode
->IcmpErrorReceived
= TRUE
;
2276 Dhcp6
->Configure (Dhcp6
, NULL
);
2281 // Get the acquired IPv6 address and store them.
2283 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2284 if (EFI_ERROR (Status
)) {
2285 Dhcp6
->Stop (Dhcp6
);
2289 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2291 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2292 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2293 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2294 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2295 // to find a valid router address.
2297 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2298 if (Mode
.ClientId
!= NULL
) {
2299 FreePool (Mode
.ClientId
);
2301 if (Mode
.Ia
!= NULL
) {
2305 // Check the selected offer whether BINL retry is needed.
2307 Status
= PxeBcHandleDhcp6Offer (Private
);
2308 if (EFI_ERROR (Status
)) {
2309 Dhcp6
->Stop (Dhcp6
);