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.
184 @retval EFI_SUCCESS Packet is copied.
185 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
189 PxeBcCacheDhcp6Packet (
190 IN EFI_DHCP6_PACKET
*Dst
,
191 IN EFI_DHCP6_PACKET
*Src
194 if (Dst
->Size
< Src
->Length
) {
195 return EFI_BUFFER_TOO_SMALL
;
198 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
199 Dst
->Length
= Src
->Length
;
206 Free all the nodes in the list for boot file.
208 @param[in] Head The pointer to the head of list.
212 PxeBcFreeBootFileOption (
217 LIST_ENTRY
*NextEntry
;
218 PXEBC_DHCP6_OPTION_NODE
*Node
;
220 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
221 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
222 RemoveEntryList (Entry
);
228 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.
230 @param[in] Private Pointer to PxeBc private data.
231 @param[in] HostName Pointer to buffer containing hostname.
232 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
234 @retval EFI_SUCCESS Operation succeeded.
235 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
236 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
237 @retval Others Other errors as indicated.
242 IN PXEBC_PRIVATE_DATA
*Private
,
244 OUT EFI_IPv6_ADDRESS
*IpAddress
248 EFI_DNS6_PROTOCOL
*Dns6
;
249 EFI_DNS6_CONFIG_DATA Dns6ConfigData
;
250 EFI_DNS6_COMPLETION_TOKEN Token
;
251 EFI_HANDLE Dns6Handle
;
252 EFI_IPv6_ADDRESS
*DnsServerList
;
257 DnsServerList
= Private
->DnsServer
;
258 ZeroMem (&Token
, sizeof (EFI_DNS6_COMPLETION_TOKEN
));
261 // Create a DNSv6 child instance and get the protocol.
263 Status
= NetLibCreateServiceChild (
266 &gEfiDns6ServiceBindingProtocolGuid
,
269 if (EFI_ERROR (Status
)) {
273 Status
= gBS
->OpenProtocol (
275 &gEfiDns6ProtocolGuid
,
279 EFI_OPEN_PROTOCOL_BY_DRIVER
281 if (EFI_ERROR (Status
)) {
286 // Configure DNS6 instance for the DNS server address and protocol.
288 ZeroMem (&Dns6ConfigData
, sizeof (EFI_DNS6_CONFIG_DATA
));
289 Dns6ConfigData
.DnsServerCount
= 1;
290 Dns6ConfigData
.DnsServerList
= DnsServerList
;
291 Dns6ConfigData
.EnableDnsCache
= TRUE
;
292 Dns6ConfigData
.Protocol
= EFI_IP_PROTO_UDP
;
293 IP6_COPY_ADDRESS (&Dns6ConfigData
.StationIp
, &Private
->TmpStationIp
.v6
);
294 Status
= Dns6
->Configure (
298 if (EFI_ERROR (Status
)) {
302 Token
.Status
= EFI_NOT_READY
;
305 // Create event to set the IsDone flag when name resolution is finished.
307 Status
= gBS
->CreateEvent (
314 if (EFI_ERROR (Status
)) {
319 // Start asynchronous name resolution.
321 Status
= Dns6
->HostNameToIp (Dns6
, HostName
, &Token
);
322 if (EFI_ERROR (Status
)) {
331 // Name resolution is done, check result.
333 Status
= Token
.Status
;
334 if (!EFI_ERROR (Status
)) {
335 if (Token
.RspData
.H2AData
== NULL
) {
336 Status
= EFI_DEVICE_ERROR
;
339 if (Token
.RspData
.H2AData
->IpCount
== 0 || Token
.RspData
.H2AData
->IpList
== NULL
) {
340 Status
= EFI_DEVICE_ERROR
;
344 // We just return the first IPv6 address from DNS protocol.
346 IP6_COPY_ADDRESS (IpAddress
, Token
.RspData
.H2AData
->IpList
);
347 Status
= EFI_SUCCESS
;
353 if (Token
.Event
!= NULL
) {
354 gBS
->CloseEvent (Token
.Event
);
356 if (Token
.RspData
.H2AData
!= NULL
) {
357 if (Token
.RspData
.H2AData
->IpList
!= NULL
) {
358 FreePool (Token
.RspData
.H2AData
->IpList
);
360 FreePool (Token
.RspData
.H2AData
);
364 Dns6
->Configure (Dns6
, NULL
);
368 &gEfiDns6ProtocolGuid
,
374 if (Dns6Handle
!= NULL
) {
375 NetLibDestroyServiceChild (
378 &gEfiDns6ServiceBindingProtocolGuid
,
383 if (DnsServerList
!= NULL
) {
384 FreePool (DnsServerList
);
391 Parse the Boot File URL option.
393 @param[in] Private Pointer to PxeBc private data.
394 @param[out] FileName The pointer to the boot file name.
395 @param[in, out] SrvAddr The pointer to the boot server address.
396 @param[in] BootFile The pointer to the boot file URL option data.
397 @param[in] Length The length of the boot file URL option data.
399 @retval EFI_ABORTED User cancel operation.
400 @retval EFI_SUCCESS Selected the boot menu successfully.
401 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
405 PxeBcExtractBootFileUrl (
406 IN PXEBC_PRIVATE_DATA
*Private
,
407 OUT UINT8
**FileName
,
408 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
414 CHAR8
*BootFileNamePtr
;
416 UINT16 BootFileNameLen
;
419 CHAR8
*ServerAddressOption
;
420 CHAR8
*ServerAddress
;
423 BOOLEAN IpExpressedUrl
;
427 IpExpressedUrl
= TRUE
;
429 // The format of the Boot File URL option is:
432 // 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
433 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
434 // | OPT_BOOTFILE_URL | option-len |
435 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437 // . bootfile-url (variable length) .
439 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
443 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be
444 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME
445 // As an example where the BOOTFILE_NAME is the EFI loader and
446 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
448 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
450 if (Length
<= PrefixLen
||
451 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
452 return EFI_NOT_FOUND
;
455 BootFile
= BootFile
+ PrefixLen
;
456 Length
= (UINT16
) (Length
- PrefixLen
);
458 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
459 if (TmpStr
== NULL
) {
460 return EFI_OUT_OF_RESOURCES
;
463 CopyMem (TmpStr
, BootFile
, Length
);
464 TmpStr
[Length
] = '\0';
467 // Get the part of SERVER_ADDRESS string.
469 ServerAddressOption
= TmpStr
;
470 if (*ServerAddressOption
== PXEBC_ADDR_START_DELIMITER
) {
471 ServerAddressOption
++;
472 ServerAddress
= ServerAddressOption
;
473 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
477 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
479 return EFI_INVALID_PARAMETER
;
482 *ServerAddress
= '\0';
485 // Convert the string of server address to Ipv6 address format and store it.
487 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
488 if (EFI_ERROR (Status
)) {
494 IpExpressedUrl
= FALSE
;
495 ServerAddress
= ServerAddressOption
;
496 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
500 if (*ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
502 return EFI_INVALID_PARAMETER
;
504 *ServerAddress
= '\0';
506 Len
= AsciiStrSize (ServerAddressOption
);
507 HostName
= AllocateZeroPool (Len
* sizeof (CHAR16
));
508 if (HostName
== NULL
) {
510 return EFI_OUT_OF_RESOURCES
;
512 AsciiStrToUnicodeStrS (
519 // Perform DNS resolution.
521 Status
= PxeBcDns6 (Private
,HostName
, SrvAddr
);
522 if (EFI_ERROR (Status
)) {
529 // Get the part of BOOTFILE_NAME string.
531 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
532 if (IpExpressedUrl
) {
533 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
535 return EFI_INVALID_PARAMETER
;
540 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
541 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
543 // Remove trailing mode=octet if present and ignore. All other modes are
544 // invalid for netboot6, so reject them.
546 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
547 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
549 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
550 return EFI_INVALID_PARAMETER
;
554 // Extract boot file name from URL.
556 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
557 if (BootFileName
== NULL
) {
559 return EFI_OUT_OF_RESOURCES
;
561 *FileName
= (UINT8
*) BootFileName
;
564 // Decode percent-encoding in boot file name.
566 while (*BootFileNamePtr
!= '\0') {
567 if (*BootFileNamePtr
== '%') {
568 TmpChar
= *(BootFileNamePtr
+ 3);
569 *(BootFileNamePtr
+ 3) = '\0';
570 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
572 *(BootFileNamePtr
+ 3) = TmpChar
;
573 BootFileNamePtr
+= 3;
575 *BootFileName
= *BootFileNamePtr
;
580 *BootFileName
= '\0';
590 Parse the Boot File Parameter option.
592 @param[in] BootFilePara The pointer to boot file parameter option data.
593 @param[out] BootFileSize The pointer to the parsed boot file size.
595 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
596 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
600 PxeBcExtractBootFileParam (
601 IN CHAR8
*BootFilePara
,
602 OUT UINT16
*BootFileSize
610 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
611 Length
= NTOHS (Length
);
614 // The BootFile Size should be 1~5 byte ASCII strings
616 if (Length
< 1 || Length
> 5) {
617 return EFI_NOT_FOUND
;
621 // Extract the value of BootFile Size.
623 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
625 for (Index
= 0; Index
< Length
; Index
++) {
626 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
627 return EFI_NOT_FOUND
;
630 Size
= (Size
+ Digit
) * 10;
634 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
635 return EFI_NOT_FOUND
;
638 *BootFileSize
= (UINT16
) Size
;
644 Parse the cached DHCPv6 packet, including all the options.
646 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
648 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
649 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
653 PxeBcParseDhcp6Packet (
654 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
657 EFI_DHCP6_PACKET
*Offer
;
658 EFI_DHCP6_PACKET_OPTION
**Options
;
659 EFI_DHCP6_PACKET_OPTION
*Option
;
660 PXEBC_OFFER_TYPE OfferType
;
661 BOOLEAN IsProxyOffer
;
665 UINT32 EnterpriseNum
;
669 Offer
= &Cache6
->Packet
.Offer
;
670 Options
= Cache6
->OptList
;
672 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
674 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
676 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
679 // OpLen and OpCode here are both stored in network order, since they are from original packet.
681 while (Offset
< Length
) {
683 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
684 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
685 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
687 // The server sends this option to inform the client about an URL to a boot file.
689 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
690 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
691 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
692 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
693 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
694 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
695 Options
[PXEBC_DHCP6_IDX_DNS_SERVER
] = Option
;
698 Offset
+= (NTOHS (Option
->OpLen
) + 4);
699 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
703 // The offer with assigned client address is NOT a proxy offer.
704 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
706 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
707 if (Option
!= NULL
) {
708 Option
= PxeBcParseDhcp6Options (
710 NTOHS (Option
->OpLen
),
711 DHCP6_OPT_STATUS_CODE
713 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
714 IsProxyOffer
= FALSE
;
719 // The offer with "PXEClient" is a pxe offer.
721 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
722 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
724 if (Option
!= NULL
&&
725 NTOHS(Option
->OpLen
) >= 13 &&
726 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
727 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
732 // Determine offer type of the dhcp6 packet.
736 // It's a binl offer only with PXEClient.
738 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
741 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
743 OfferType
= PxeOfferTypeDhcpOnly
;
746 Cache6
->OfferType
= OfferType
;
753 Cache the DHCPv6 ack packet, and parse it on demand.
755 @param[in] Private The pointer to PxeBc private data.
756 @param[in] Ack The pointer to the DHCPv6 ack packet.
757 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
759 @retval EFI_SUCCESS Cache and parse the packet successfully.
760 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
765 IN PXEBC_PRIVATE_DATA
*Private
,
766 IN EFI_DHCP6_PACKET
*Ack
,
770 EFI_PXE_BASE_CODE_MODE
*Mode
;
773 Mode
= Private
->PxeBc
.Mode
;
775 Status
= PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
776 if (EFI_ERROR (Status
)) {
782 // Parse the ack packet and store it into mode data if needed.
784 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
785 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
786 Mode
->DhcpAckReceived
= TRUE
;
794 Cache the DHCPv6 proxy offer packet according to the received order.
796 @param[in] Private The pointer to PxeBc private data.
797 @param[in] OfferIndex The received order of offer packets.
799 @retval EFI_SUCCESS Cache and parse the packet successfully.
800 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
804 PxeBcCopyDhcp6Proxy (
805 IN PXEBC_PRIVATE_DATA
*Private
,
809 EFI_PXE_BASE_CODE_MODE
*Mode
;
810 EFI_DHCP6_PACKET
*Offer
;
813 ASSERT (OfferIndex
< Private
->OfferNum
);
814 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
816 Mode
= Private
->PxeBc
.Mode
;
817 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
820 // Cache the proxy offer packet and parse it.
822 Status
= PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
823 if (EFI_ERROR(Status
)) {
826 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
829 // Store this packet into mode data.
831 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
832 Mode
->ProxyOfferReceived
= TRUE
;
838 Seek the address of the first byte of the option header.
840 @param[in] Buf The pointer to the buffer.
841 @param[in] SeekLen The length to seek.
842 @param[in] OptType The option type.
844 @retval NULL If it failed to seek the option.
845 @retval others The position to the option.
849 PxeBcDhcp6SeekOption (
863 while (Cursor
< Buf
+ SeekLen
) {
864 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
865 if (OpCode
== HTONS (OptType
)) {
869 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
870 Cursor
+= (DataLen
+ 4);
878 Build and send out the request packet for the bootfile, and parse the reply.
880 @param[in] Private The pointer to PxeBc private data.
881 @param[in] Index PxeBc option boot item type.
883 @retval EFI_SUCCESS Successfully discovered the boot file.
884 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
885 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
886 @retval Others Failed to discover the boot file.
890 PxeBcRequestBootService (
891 IN PXEBC_PRIVATE_DATA
*Private
,
895 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
896 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
897 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
898 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
900 EFI_DHCP6_PACKET
*Request
;
902 EFI_DHCP6_PACKET
*Reply
;
910 EFI_DHCP6_PACKET
*ProxyOffer
;
913 PxeBc
= &Private
->PxeBc
;
914 Request
= Private
->Dhcp6Request
;
915 ProxyOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
916 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
917 DestPort
= PXEBC_BS_DISCOVER_PORT
;
920 if (Request
== NULL
) {
921 return EFI_DEVICE_ERROR
;
924 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
925 if (Discover
== NULL
) {
926 return EFI_OUT_OF_RESOURCES
;
930 // Build the request packet by the cached request packet before.
932 Discover
->TransactionId
= ProxyOffer
->Dhcp6
.Header
.TransactionId
;
933 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
934 RequestOpt
= Request
->Dhcp6
.Option
;
935 DiscoverOpt
= Discover
->DhcpOptions
;
936 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
937 RequestLen
= DiscoverLen
;
940 // Find Server ID Option from ProxyOffer.
942 Option
= PxeBcDhcp6SeekOption (
943 ProxyOffer
->Dhcp6
.Option
,
944 ProxyOffer
->Length
- 4,
947 if (Option
== NULL
) {
948 return EFI_NOT_FOUND
;
952 // Add Server ID Option.
954 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
955 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
956 DiscoverOpt
+= (OpLen
+ 4);
957 DiscoverLen
+= (OpLen
+ 4);
959 while (RequestLen
< Request
->Length
) {
960 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
961 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
962 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
963 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
964 OpCode
!= DHCP6_OPT_SERVER_ID
967 // Copy all the options except IA option and Server ID
969 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
970 DiscoverOpt
+= (OpLen
+ 4);
971 DiscoverLen
+= (OpLen
+ 4);
973 RequestOpt
+= (OpLen
+ 4);
974 RequestLen
+= (OpLen
+ 4);
978 // Update Elapsed option in the package
980 Option
= PxeBcDhcp6SeekOption (
981 Discover
->DhcpOptions
,
982 (UINT32
)(RequestLen
- 4),
983 DHCP6_OPT_ELAPSED_TIME
985 if (Option
!= NULL
) {
986 CalcElapsedTime (Private
);
987 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
990 Status
= PxeBc
->UdpWrite (
1004 if (EFI_ERROR (Status
)) {
1009 // Cache the right PXE reply packet here, set valid flag later.
1010 // Especially for PXE discover packet, store it into mode data here.
1012 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1013 ReadSize
= (UINTN
) Reply
->Size
;
1016 // Start Udp6Read instance
1018 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
1019 if (EFI_ERROR (Status
)) {
1023 Status
= PxeBc
->UdpRead (
1025 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
1033 (VOID
*) &Reply
->Dhcp6
1036 // Stop Udp6Read instance
1038 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1040 if (EFI_ERROR (Status
)) {
1047 Reply
->Length
= (UINT32
) ReadSize
;
1054 Retry to request bootfile name by the BINL offer.
1056 @param[in] Private The pointer to PxeBc private data.
1057 @param[in] Index The received order of offer packets.
1059 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
1060 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
1064 PxeBcRetryDhcp6Binl (
1065 IN PXEBC_PRIVATE_DATA
*Private
,
1069 EFI_PXE_BASE_CODE_MODE
*Mode
;
1070 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
1071 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1074 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1075 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
1076 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
1078 Mode
= Private
->PxeBc
.Mode
;
1079 Private
->IsDoDiscover
= FALSE
;
1080 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
1081 if (Offer
->OfferType
== PxeOfferTypeDhcpBinl
) {
1083 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
1086 &Private
->ServerIp
.v6
,
1087 &mAllDhcpRelayAndServersAddress
,
1088 sizeof (EFI_IPv6_ADDRESS
)
1091 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1093 // Parse out the next server address from the last offer, and store it
1095 Status
= PxeBcExtractBootFileUrl (
1097 &Private
->BootFileName
,
1098 &Private
->ServerIp
.v6
,
1099 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
1100 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
1102 if (EFI_ERROR (Status
)) {
1108 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
1110 Status
= PxeBcRequestBootService (Private
, Index
);
1112 if (EFI_ERROR (Status
)) {
1116 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
1117 Status
= PxeBcParseDhcp6Packet (Cache6
);
1118 if (EFI_ERROR (Status
)) {
1122 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
1123 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
1124 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1126 // This BINL ack doesn't have discovery option set or multicast option set
1127 // or bootfile name specified.
1129 return EFI_DEVICE_ERROR
;
1132 Mode
->ProxyOfferReceived
= TRUE
;
1134 &Mode
->ProxyOffer
.Dhcpv6
,
1135 &Cache6
->Packet
.Offer
.Dhcp6
,
1136 Cache6
->Packet
.Offer
.Length
1144 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
1146 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1147 @param[in] RcvdOffer The pointer to the received offer packet.
1149 @retval EFI_SUCCESS Cache and parse the packet successfully.
1150 @retval Others Operation failed.
1153 PxeBcCacheDhcp6Offer (
1154 IN PXEBC_PRIVATE_DATA
*Private
,
1155 IN EFI_DHCP6_PACKET
*RcvdOffer
1158 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1159 EFI_DHCP6_PACKET
*Offer
;
1160 PXEBC_OFFER_TYPE OfferType
;
1163 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
1164 Offer
= &Cache6
->Packet
.Offer
;
1167 // Cache the content of DHCPv6 packet firstly.
1169 Status
= PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
1170 if (EFI_ERROR (Status
)) {
1175 // Validate the DHCPv6 packet, and parse the options and offer type.
1177 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
1182 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
1184 OfferType
= Cache6
->OfferType
;
1185 ASSERT (OfferType
< PxeOfferTypeMax
);
1186 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
1188 if (IS_PROXY_OFFER (OfferType
)) {
1190 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
1192 Private
->IsProxyRecved
= TRUE
;
1194 if (OfferType
== PxeOfferTypeProxyBinl
) {
1196 // Cache all proxy BINL offers.
1198 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1199 Private
->OfferCount
[OfferType
]++;
1200 } else if (Private
->OfferCount
[OfferType
] > 0) {
1202 // Only cache the first PXE10/WFM11a offer, and discard the others.
1204 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
1205 Private
->OfferCount
[OfferType
] = 1;
1211 // It's a DHCPv6 offer with yiaddr, and cache them all.
1213 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1214 Private
->OfferCount
[OfferType
]++;
1217 Private
->OfferNum
++;
1224 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
1226 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1230 PxeBcSelectDhcp6Offer (
1231 IN PXEBC_PRIVATE_DATA
*Private
1236 PXEBC_OFFER_TYPE OfferType
;
1238 Private
->SelectIndex
= 0;
1240 if (Private
->IsOfferSorted
) {
1242 // Select offer by default policy.
1244 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1246 // 1. DhcpPxe10 offer
1248 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
1250 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
1252 // 2. DhcpWfm11a offer
1254 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1256 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1257 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1259 // 3. DhcpOnly offer and ProxyPxe10 offer.
1261 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1262 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1264 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1265 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1267 // 4. DhcpOnly offer and ProxyWfm11a offer.
1269 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1270 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1272 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1274 // 5. DhcpBinl offer.
1276 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1278 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1279 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1281 // 6. DhcpOnly offer and ProxyBinl offer.
1283 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1284 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1288 // 7. DhcpOnly offer with bootfilename.
1290 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1291 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1292 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1293 Private
->SelectIndex
= OfferIndex
+ 1;
1300 // Select offer by received order.
1302 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1304 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1306 if (IS_PROXY_OFFER (OfferType
)) {
1308 // Skip proxy offers
1313 if (!Private
->IsProxyRecved
&&
1314 OfferType
== PxeOfferTypeDhcpOnly
&&
1315 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1317 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1322 Private
->SelectIndex
= Index
+ 1;
1330 Handle the DHCPv6 offer packet.
1332 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1334 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1335 @retval EFI_NO_RESPONSE No response to the following request packet.
1336 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1337 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1341 PxeBcHandleDhcp6Offer (
1342 IN PXEBC_PRIVATE_DATA
*Private
1345 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1347 PXEBC_OFFER_TYPE OfferType
;
1352 ASSERT (Private
->SelectIndex
> 0);
1353 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1354 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1355 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1356 Status
= EFI_SUCCESS
;
1359 // First try to cache DNS server address if DHCP6 offer provides.
1361 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1362 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1363 if (Private
->DnsServer
== NULL
) {
1364 return EFI_OUT_OF_RESOURCES
;
1366 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1369 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1371 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1373 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1374 Status
= EFI_NO_RESPONSE
;
1376 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1378 if (Private
->IsProxyRecved
) {
1380 // DhcpOnly offer is selected, so need try to request bootfilename.
1383 if (Private
->IsOfferSorted
) {
1385 // The proxy offer should be determined if select by default policy.
1386 // IsOfferSorted means all offers are labeled by OfferIndex.
1388 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1390 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1392 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1394 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1396 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1397 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1401 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1402 Status
= EFI_NO_RESPONSE
;
1406 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1408 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1412 // The proxy offer should not be determined if select by received order.
1414 Status
= EFI_NO_RESPONSE
;
1416 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1418 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1420 if (!IS_PROXY_OFFER (OfferType
)) {
1422 // Skip non proxy dhcp offers.
1427 if (OfferType
== PxeOfferTypeProxyBinl
) {
1429 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1431 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1436 Private
->SelectProxyType
= OfferType
;
1438 Status
= EFI_SUCCESS
;
1443 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1445 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1447 Status
= PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1451 // Othewise, the bootfilename must be included in DhcpOnly offer.
1453 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1457 if (!EFI_ERROR (Status
)) {
1459 // All PXE boot information is ready by now.
1461 Status
= PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1462 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1470 Unregister the address by Ip6Config protocol.
1472 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1476 PxeBcUnregisterIp6Address (
1477 IN PXEBC_PRIVATE_DATA
*Private
1480 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1482 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1483 // Keep the point and there is no enough requirements to do recovery.
1489 Check whether IP driver could route the message which will be sent to ServerIp address.
1491 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1492 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1494 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1495 @param[in] TimeOutInSecond Timeout value in seconds.
1496 @param[out] GatewayAddr Pointer to store the gateway IP address.
1498 @retval EFI_SUCCESS Found a valid gateway address successfully.
1499 @retval EFI_TIMEOUT The operation is time out.
1500 @retval Other Unexpect error happened.
1504 PxeBcCheckRouteTable (
1505 IN PXEBC_PRIVATE_DATA
*Private
,
1506 IN UINTN TimeOutInSecond
,
1507 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1511 EFI_IP6_PROTOCOL
*Ip6
;
1512 EFI_IP6_MODE_DATA Ip6ModeData
;
1514 EFI_EVENT TimeOutEvt
;
1516 BOOLEAN GatewayIsFound
;
1518 ASSERT (GatewayAddr
!= NULL
);
1519 ASSERT (Private
!= NULL
);
1522 GatewayIsFound
= FALSE
;
1525 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1528 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1529 if (EFI_ERROR (Status
)) {
1534 // Find out the gateway address which can route the message which send to ServerIp.
1536 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1537 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1538 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1539 GatewayIsFound
= TRUE
;
1544 if (Ip6ModeData
.AddressList
!= NULL
) {
1545 FreePool (Ip6ModeData
.AddressList
);
1547 if (Ip6ModeData
.GroupTable
!= NULL
) {
1548 FreePool (Ip6ModeData
.GroupTable
);
1550 if (Ip6ModeData
.RouteTable
!= NULL
) {
1551 FreePool (Ip6ModeData
.RouteTable
);
1553 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1554 FreePool (Ip6ModeData
.NeighborCache
);
1556 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1557 FreePool (Ip6ModeData
.PrefixTable
);
1559 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1560 FreePool (Ip6ModeData
.IcmpTypeList
);
1563 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
1570 // Delay 1 second then recheck it again.
1572 if (TimeOutEvt
== NULL
) {
1573 Status
= gBS
->CreateEvent (
1580 if (EFI_ERROR (Status
)) {
1585 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
1586 if (EFI_ERROR (Status
)) {
1589 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1595 if (TimeOutEvt
!= NULL
) {
1596 gBS
->CloseEvent (TimeOutEvt
);
1599 if (GatewayIsFound
) {
1600 Status
= EFI_SUCCESS
;
1601 } else if (RetryCount
== TimeOutInSecond
) {
1602 Status
= EFI_TIMEOUT
;
1609 Register the ready station address and gateway by Ip6Config protocol.
1611 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1612 @param[in] Address The pointer to the ready address.
1614 @retval EFI_SUCCESS Registered the address succesfully.
1615 @retval Others Failed to register the address.
1619 PxeBcRegisterIp6Address (
1620 IN PXEBC_PRIVATE_DATA
*Private
,
1621 IN EFI_IPv6_ADDRESS
*Address
1624 EFI_IP6_PROTOCOL
*Ip6
;
1625 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1626 EFI_IP6_CONFIG_POLICY Policy
;
1627 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1628 EFI_IPv6_ADDRESS GatewayAddr
;
1630 EFI_EVENT MappedEvt
;
1633 EFI_IPv6_ADDRESS
*Ip6Addr
;
1636 Status
= EFI_SUCCESS
;
1639 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1640 Ip6Cfg
= Private
->Ip6Cfg
;
1644 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1645 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1647 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1648 if (EFI_ERROR (Status
)) {
1653 // Retrieve the gateway address from IP6 route table.
1655 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1656 if (EFI_ERROR (Status
)) {
1661 // There is no channel between IP6 and PXE driver about address setting,
1662 // so it has to set the new address by Ip6ConfigProtocol manually.
1664 Policy
= Ip6ConfigPolicyManual
;
1665 Status
= Ip6Cfg
->SetData (
1667 Ip6ConfigDataTypePolicy
,
1668 sizeof(EFI_IP6_CONFIG_POLICY
),
1671 if (EFI_ERROR (Status
)) {
1673 // There is no need to recover later.
1675 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1680 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1682 Status
= gBS
->CreateEvent (
1686 &Private
->IsAddressOk
,
1689 if (EFI_ERROR (Status
)) {
1693 Private
->IsAddressOk
= FALSE
;
1694 Status
= Ip6Cfg
->RegisterDataNotify (
1696 Ip6ConfigDataTypeManualAddress
,
1699 if (EFI_ERROR(Status
)) {
1703 Status
= Ip6Cfg
->SetData (
1705 Ip6ConfigDataTypeManualAddress
,
1706 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1709 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1711 } else if (Status
== EFI_NOT_READY
) {
1713 // Poll the network until the asynchronous process is finished.
1715 while (!Private
->IsAddressOk
) {
1719 // Check whether the IP6 address setting is successed.
1722 Status
= Ip6Cfg
->GetData (
1724 Ip6ConfigDataTypeManualAddress
,
1728 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
1729 Status
= EFI_DEVICE_ERROR
;
1733 Ip6Addr
= AllocatePool (DataSize
);
1734 if (Ip6Addr
== NULL
) {
1735 return EFI_OUT_OF_RESOURCES
;
1737 Status
= Ip6Cfg
->GetData (
1739 Ip6ConfigDataTypeManualAddress
,
1743 if (EFI_ERROR (Status
)) {
1744 Status
= EFI_DEVICE_ERROR
;
1748 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1749 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1753 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1754 Status
= EFI_ABORTED
;
1760 // Set the default gateway address back if needed.
1762 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1763 Status
= Ip6Cfg
->SetData (
1765 Ip6ConfigDataTypeGateway
,
1766 sizeof (EFI_IPv6_ADDRESS
),
1769 if (EFI_ERROR (Status
)) {
1775 if (MappedEvt
!= NULL
) {
1776 Ip6Cfg
->UnregisterDataNotify (
1778 Ip6ConfigDataTypeManualAddress
,
1781 gBS
->CloseEvent (MappedEvt
);
1783 if (Ip6Addr
!= NULL
) {
1790 Set the IP6 policy to Automatic.
1792 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1794 @retval EFI_SUCCESS Switch the IP policy succesfully.
1795 @retval Others Unexpect error happened.
1800 IN PXEBC_PRIVATE_DATA
*Private
1803 EFI_IP6_CONFIG_POLICY Policy
;
1805 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1808 Ip6Cfg
= Private
->Ip6Cfg
;
1809 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1812 // Get and store the current policy of IP6 driver.
1814 Status
= Ip6Cfg
->GetData (
1816 Ip6ConfigDataTypePolicy
,
1820 if (EFI_ERROR (Status
)) {
1824 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1825 Policy
= Ip6ConfigPolicyAutomatic
;
1826 Status
= Ip6Cfg
->SetData (
1828 Ip6ConfigDataTypePolicy
,
1829 sizeof(EFI_IP6_CONFIG_POLICY
),
1832 if (EFI_ERROR (Status
)) {
1834 // There is no need to recover later.
1836 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1844 This function will register the station IP address and flush IP instance to start using the new IP address.
1846 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1848 @retval EFI_SUCCESS The new IP address has been configured successfully.
1849 @retval Others Failed to configure the address.
1853 PxeBcSetIp6Address (
1854 IN PXEBC_PRIVATE_DATA
*Private
1858 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1860 Dhcp6
= Private
->Dhcp6
;
1862 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1863 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1865 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1866 if (EFI_ERROR (Status
)) {
1867 Dhcp6
->Stop (Dhcp6
);
1871 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1872 if (EFI_ERROR (Status
)) {
1873 PxeBcUnregisterIp6Address (Private
);
1874 Dhcp6
->Stop (Dhcp6
);
1878 AsciiPrint ("\n Station IP address is ");
1879 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1885 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1886 to intercept events that occurred in the configuration process.
1888 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1889 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1890 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1891 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1893 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1894 @param[out] NewPacket The packet that is used to replace the Packet above.
1896 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1897 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1898 driver will continue to wait for more packets.
1899 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1904 PxeBcDhcp6CallBack (
1905 IN EFI_DHCP6_PROTOCOL
*This
,
1907 IN EFI_DHCP6_STATE CurrentState
,
1908 IN EFI_DHCP6_EVENT Dhcp6Event
,
1909 IN EFI_DHCP6_PACKET
*Packet
,
1910 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1913 PXEBC_PRIVATE_DATA
*Private
;
1914 EFI_PXE_BASE_CODE_MODE
*Mode
;
1915 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1916 EFI_DHCP6_PACKET
*SelectAd
;
1920 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1921 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1922 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1923 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1924 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1928 ASSERT (Packet
!= NULL
);
1930 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1931 Mode
= Private
->PxeBc
.Mode
;
1932 Callback
= Private
->PxeBcCallback
;
1935 // Callback to user when any traffic ocurred if has.
1937 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1938 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1939 Status
= Callback
->Callback (
1944 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1946 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1951 Status
= EFI_SUCCESS
;
1953 switch (Dhcp6Event
) {
1955 case Dhcp6SendSolicit
:
1956 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1958 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1960 Status
= EFI_ABORTED
;
1965 // Record the first Solicate msg time
1967 if (Private
->SolicitTimes
== 0) {
1968 CalcElapsedTime (Private
);
1969 Private
->SolicitTimes
++;
1972 // Cache the dhcp discover packet to mode data directly.
1974 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1977 case Dhcp6RcvdAdvertise
:
1978 Status
= EFI_NOT_READY
;
1979 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1981 // Ignore the incoming packets which exceed the maximum length.
1985 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1987 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1988 // the OfferIndex and OfferCount.
1990 PxeBcCacheDhcp6Offer (Private
, Packet
);
1994 case Dhcp6SendRequest
:
1995 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1997 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1999 Status
= EFI_ABORTED
;
2004 // Store the request packet as seed packet for discover.
2006 if (Private
->Dhcp6Request
!= NULL
) {
2007 FreePool (Private
->Dhcp6Request
);
2009 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
2010 if (Private
->Dhcp6Request
!= NULL
) {
2011 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
2015 case Dhcp6SelectAdvertise
:
2017 // Select offer by the default policy or by order, and record the SelectIndex
2018 // and SelectProxyType.
2020 PxeBcSelectDhcp6Offer (Private
);
2022 if (Private
->SelectIndex
== 0) {
2023 Status
= EFI_ABORTED
;
2025 ASSERT (NewPacket
!= NULL
);
2026 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
2027 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
2028 ASSERT (*NewPacket
!= NULL
);
2029 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
2033 case Dhcp6RcvdReply
:
2035 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
2036 // without verification.
2038 ASSERT (Private
->SelectIndex
!= 0);
2039 Status
= PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
2040 if (EFI_ERROR (Status
)) {
2041 Status
= EFI_ABORTED
;
2054 Build and send out the request packet for the bootfile, and parse the reply.
2056 @param[in] Private The pointer to PxeBc private data.
2057 @param[in] Type PxeBc option boot item type.
2058 @param[in] Layer The pointer to option boot item layer.
2059 @param[in] UseBis Use BIS or not.
2060 @param[in] DestIp The pointer to the server address.
2062 @retval EFI_SUCCESS Successfully discovered the boot file.
2063 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2064 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2065 @retval Others Failed to discover the boot file.
2069 PxeBcDhcp6Discover (
2070 IN PXEBC_PRIVATE_DATA
*Private
,
2074 IN EFI_IP_ADDRESS
*DestIp
2077 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2078 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2079 EFI_PXE_BASE_CODE_MODE
*Mode
;
2080 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2081 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2083 EFI_DHCP6_PACKET
*Request
;
2085 EFI_DHCP6_PACKET
*Reply
;
2094 PxeBc
= &Private
->PxeBc
;
2096 Request
= Private
->Dhcp6Request
;
2097 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2098 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2100 if (!UseBis
&& Layer
!= NULL
) {
2101 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2104 if (Request
== NULL
) {
2105 return EFI_DEVICE_ERROR
;
2108 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2109 if (Discover
== NULL
) {
2110 return EFI_OUT_OF_RESOURCES
;
2114 // Build the discover packet by the cached request packet before.
2116 Xid
= NET_RANDOM (NetRandomInitSeed ());
2117 Discover
->TransactionId
= HTONL (Xid
);
2118 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2119 RequestOpt
= Request
->Dhcp6
.Option
;
2120 DiscoverOpt
= Discover
->DhcpOptions
;
2121 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2122 RequestLen
= DiscoverLen
;
2124 while (RequestLen
< Request
->Length
) {
2125 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
2126 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
2127 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
2128 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
2130 // Copy all the options except IA option.
2132 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2133 DiscoverOpt
+= (OpLen
+ 4);
2134 DiscoverLen
+= (OpLen
+ 4);
2136 RequestOpt
+= (OpLen
+ 4);
2137 RequestLen
+= (OpLen
+ 4);
2140 Status
= PxeBc
->UdpWrite (
2146 &Private
->StationIp
,
2153 if (EFI_ERROR (Status
)) {
2158 // Cache the right PXE reply packet here, set valid flag later.
2159 // Especially for PXE discover packet, store it into mode data here.
2161 if (Private
->IsDoDiscover
) {
2162 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2163 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2165 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2167 ReadSize
= (UINTN
) Reply
->Size
;
2170 // Start Udp6Read instance
2172 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2173 if (EFI_ERROR (Status
)) {
2177 Status
= PxeBc
->UdpRead (
2179 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2187 (VOID
*) &Reply
->Dhcp6
2190 // Stop Udp6Read instance
2192 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2193 if (EFI_ERROR (Status
)) {
2202 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2204 @param[in] Private The pointer to PxeBc private data.
2205 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2207 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2208 @retval Others Failed to finish the S.A.R.R. process.
2213 IN PXEBC_PRIVATE_DATA
*Private
,
2214 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2217 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2218 EFI_DHCP6_CONFIG_DATA Config
;
2219 EFI_DHCP6_MODE_DATA Mode
;
2220 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2221 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2222 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2225 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2226 EFI_STATUS TimerStatus
;
2228 UINT64 GetMappingTimeOut
;
2230 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2232 Status
= EFI_SUCCESS
;
2233 PxeMode
= Private
->PxeBc
.Mode
;
2234 Ip6Cfg
= Private
->Ip6Cfg
;
2238 // Build option list for the request packet.
2240 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2241 ASSERT (OptCount
> 0);
2243 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2244 if (Retransmit
== NULL
) {
2245 return EFI_OUT_OF_RESOURCES
;
2248 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2249 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2251 Config
.OptionCount
= OptCount
;
2252 Config
.OptionList
= OptList
;
2253 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2254 Config
.CallbackContext
= Private
;
2255 Config
.IaInfoEvent
= NULL
;
2256 Config
.RapidCommit
= FALSE
;
2257 Config
.ReconfigureAccept
= FALSE
;
2258 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2259 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2260 Config
.SolicitRetransmission
= Retransmit
;
2261 Retransmit
->Irt
= 4;
2262 Retransmit
->Mrc
= 4;
2263 Retransmit
->Mrt
= 32;
2264 Retransmit
->Mrd
= 60;
2267 // Configure the DHCPv6 instance for PXE boot.
2269 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2270 FreePool (Retransmit
);
2271 if (EFI_ERROR (Status
)) {
2276 // Initialize the record fields for DHCPv6 offer in private data.
2278 Private
->IsProxyRecved
= FALSE
;
2279 Private
->OfferNum
= 0;
2280 Private
->SelectIndex
= 0;
2281 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2282 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2286 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2288 Status
= Dhcp6
->Start (Dhcp6
);
2289 if (Status
== EFI_NO_MAPPING
) {
2291 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2292 // and wait for duplicate address detection to finish.
2294 Dhcp6
->Stop (Dhcp6
);
2297 // Get Duplicate Address Detection Transmits count.
2299 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2300 Status
= Ip6Cfg
->GetData (
2302 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2306 if (EFI_ERROR (Status
)) {
2307 Dhcp6
->Configure (Dhcp6
, NULL
);
2311 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2312 if (EFI_ERROR (Status
)) {
2313 Dhcp6
->Configure (Dhcp6
, NULL
);
2317 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2318 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2319 if (EFI_ERROR (Status
)) {
2320 gBS
->CloseEvent (Timer
);
2321 Dhcp6
->Configure (Dhcp6
, NULL
);
2327 TimerStatus
= gBS
->CheckEvent (Timer
);
2328 if (!EFI_ERROR (TimerStatus
)) {
2329 Status
= Dhcp6
->Start (Dhcp6
);
2331 } while (TimerStatus
== EFI_NOT_READY
);
2333 gBS
->CloseEvent (Timer
);
2335 if (EFI_ERROR (Status
)) {
2336 if (Status
== EFI_ICMP_ERROR
) {
2337 PxeMode
->IcmpErrorReceived
= TRUE
;
2339 Dhcp6
->Configure (Dhcp6
, NULL
);
2344 // Get the acquired IPv6 address and store them.
2346 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2347 if (EFI_ERROR (Status
)) {
2348 Dhcp6
->Stop (Dhcp6
);
2352 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2354 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2355 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2356 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2357 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2358 // to find a valid router address.
2360 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2361 if (Mode
.ClientId
!= NULL
) {
2362 FreePool (Mode
.ClientId
);
2364 if (Mode
.Ia
!= NULL
) {
2368 // Check the selected offer whether BINL retry is needed.
2370 Status
= PxeBcHandleDhcp6Offer (Private
);
2371 if (EFI_ERROR (Status
)) {
2372 Dhcp6
->Stop (Dhcp6
);