2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "PxeBcImpl.h"
20 // Well-known multi-cast address defined in section-24.1 of rfc-3315
22 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
24 EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress
= {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
27 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
29 @param[in] Buffer The pointer to the option buffer.
30 @param[in] Length Length of the option buffer.
31 @param[in] OptTag The required option tag.
33 @retval NULL Failed to parse the required option.
34 @retval Others The postion of the required option in buffer.
37 EFI_DHCP6_PACKET_OPTION
*
38 PxeBcParseDhcp6Options (
44 EFI_DHCP6_PACKET_OPTION
*Option
;
47 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
51 // OpLen and OpCode here are both stored in network order.
53 while (Offset
< Length
) {
55 if (NTOHS (Option
->OpCode
) == OptTag
) {
60 Offset
+= (NTOHS(Option
->OpLen
) + 4);
61 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
69 Build the options buffer for the DHCPv6 request packet.
71 @param[in] Private The pointer to PxeBc private data.
72 @param[out] OptList The pointer to the option pointer array.
73 @param[in] Buffer The pointer to the buffer to contain the option list.
75 @return Index The count of the built-in options.
79 PxeBcBuildDhcp6Options (
80 IN PXEBC_PRIVATE_DATA
*Private
,
81 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
85 PXEBC_DHCP6_OPTION_ENTRY OptEnt
;
90 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
93 // Append client option request option
95 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ORO
);
96 OptList
[Index
]->OpLen
= HTONS (8);
97 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
98 OptEnt
.Oro
->OpCode
[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL
);
99 OptEnt
.Oro
->OpCode
[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM
);
100 OptEnt
.Oro
->OpCode
[2] = HTONS(DHCP6_OPT_DNS_SERVERS
);
101 OptEnt
.Oro
->OpCode
[3] = HTONS(DHCP6_OPT_VENDOR_CLASS
);
103 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
106 // Append client network device interface option
108 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
109 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
110 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
112 if (Private
->Nii
!= NULL
) {
113 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
114 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
115 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
117 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
118 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
119 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
123 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
126 // Append client system architecture option
128 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
129 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
130 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
131 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
132 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
134 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
137 // Append vendor class option to store the PXE class identifier.
139 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
140 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
141 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
142 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
143 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
145 &OptEnt
.VendorClass
->ClassId
,
146 DEFAULT_CLASS_ID_DATA
,
147 sizeof (PXEBC_CLASS_ID
)
149 PxeBcUintnToAscDecWithFormat (
150 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
151 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
152 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
155 if (Private
->Nii
!= NULL
) {
157 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
158 Private
->Nii
->StringId
,
159 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
161 PxeBcUintnToAscDecWithFormat (
162 Private
->Nii
->MajorVer
,
163 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
164 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
166 PxeBcUintnToAscDecWithFormat (
167 Private
->Nii
->MinorVer
,
168 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
169 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
180 Cache the DHCPv6 packet.
182 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
183 @param[in] Src The pointer to the DHCPv6 packet to be cached.
185 @retval EFI_SUCCESS Packet is copied.
186 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
190 PxeBcCacheDhcp6Packet (
191 IN EFI_DHCP6_PACKET
*Dst
,
192 IN EFI_DHCP6_PACKET
*Src
195 if (Dst
->Size
< Src
->Length
) {
196 return EFI_BUFFER_TOO_SMALL
;
199 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
200 Dst
->Length
= Src
->Length
;
207 Free all the nodes in the list for boot file.
209 @param[in] Head The pointer to the head of list.
213 PxeBcFreeBootFileOption (
218 LIST_ENTRY
*NextEntry
;
219 PXEBC_DHCP6_OPTION_NODE
*Node
;
221 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
222 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
223 RemoveEntryList (Entry
);
229 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.
231 @param[in] Private Pointer to PxeBc private data.
232 @param[in] HostName Pointer to buffer containing hostname.
233 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
235 @retval EFI_SUCCESS Operation succeeded.
236 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
237 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
238 @retval Others Other errors as indicated.
243 IN PXEBC_PRIVATE_DATA
*Private
,
245 OUT EFI_IPv6_ADDRESS
*IpAddress
249 EFI_DNS6_PROTOCOL
*Dns6
;
250 EFI_DNS6_CONFIG_DATA Dns6ConfigData
;
251 EFI_DNS6_COMPLETION_TOKEN Token
;
252 EFI_HANDLE Dns6Handle
;
253 EFI_IPv6_ADDRESS
*DnsServerList
;
258 DnsServerList
= Private
->DnsServer
;
259 ZeroMem (&Token
, sizeof (EFI_DNS6_COMPLETION_TOKEN
));
262 // Create a DNSv6 child instance and get the protocol.
264 Status
= NetLibCreateServiceChild (
267 &gEfiDns6ServiceBindingProtocolGuid
,
270 if (EFI_ERROR (Status
)) {
274 Status
= gBS
->OpenProtocol (
276 &gEfiDns6ProtocolGuid
,
280 EFI_OPEN_PROTOCOL_BY_DRIVER
282 if (EFI_ERROR (Status
)) {
287 // Configure DNS6 instance for the DNS server address and protocol.
289 ZeroMem (&Dns6ConfigData
, sizeof (EFI_DNS6_CONFIG_DATA
));
290 Dns6ConfigData
.DnsServerCount
= 1;
291 Dns6ConfigData
.DnsServerList
= DnsServerList
;
292 Dns6ConfigData
.EnableDnsCache
= TRUE
;
293 Dns6ConfigData
.Protocol
= EFI_IP_PROTO_UDP
;
294 IP6_COPY_ADDRESS (&Dns6ConfigData
.StationIp
, &Private
->TmpStationIp
.v6
);
295 Status
= Dns6
->Configure (
299 if (EFI_ERROR (Status
)) {
303 Token
.Status
= EFI_NOT_READY
;
306 // Create event to set the IsDone flag when name resolution is finished.
308 Status
= gBS
->CreateEvent (
315 if (EFI_ERROR (Status
)) {
320 // Start asynchronous name resolution.
322 Status
= Dns6
->HostNameToIp (Dns6
, HostName
, &Token
);
323 if (EFI_ERROR (Status
)) {
332 // Name resolution is done, check result.
334 Status
= Token
.Status
;
335 if (!EFI_ERROR (Status
)) {
336 if (Token
.RspData
.H2AData
== NULL
) {
337 Status
= EFI_DEVICE_ERROR
;
340 if (Token
.RspData
.H2AData
->IpCount
== 0 || Token
.RspData
.H2AData
->IpList
== NULL
) {
341 Status
= EFI_DEVICE_ERROR
;
345 // We just return the first IPv6 address from DNS protocol.
347 IP6_COPY_ADDRESS (IpAddress
, Token
.RspData
.H2AData
->IpList
);
348 Status
= EFI_SUCCESS
;
354 if (Token
.Event
!= NULL
) {
355 gBS
->CloseEvent (Token
.Event
);
357 if (Token
.RspData
.H2AData
!= NULL
) {
358 if (Token
.RspData
.H2AData
->IpList
!= NULL
) {
359 FreePool (Token
.RspData
.H2AData
->IpList
);
361 FreePool (Token
.RspData
.H2AData
);
365 Dns6
->Configure (Dns6
, NULL
);
369 &gEfiDns6ProtocolGuid
,
375 if (Dns6Handle
!= NULL
) {
376 NetLibDestroyServiceChild (
379 &gEfiDns6ServiceBindingProtocolGuid
,
384 if (DnsServerList
!= NULL
) {
385 FreePool (DnsServerList
);
392 Parse the Boot File URL option.
394 @param[in] Private Pointer to PxeBc private data.
395 @param[out] FileName The pointer to the boot file name.
396 @param[in, out] SrvAddr The pointer to the boot server address.
397 @param[in] BootFile The pointer to the boot file URL option data.
398 @param[in] Length The length of the boot file URL option data.
400 @retval EFI_ABORTED User cancel operation.
401 @retval EFI_SUCCESS Selected the boot menu successfully.
402 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
406 PxeBcExtractBootFileUrl (
407 IN PXEBC_PRIVATE_DATA
*Private
,
408 OUT UINT8
**FileName
,
409 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
415 CHAR8
*BootFileNamePtr
;
417 UINT16 BootFileNameLen
;
420 CHAR8
*ServerAddressOption
;
421 CHAR8
*ServerAddress
;
424 BOOLEAN IpExpressedUrl
;
428 IpExpressedUrl
= TRUE
;
430 // The format of the Boot File URL option is:
433 // 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
434 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435 // | OPT_BOOTFILE_URL | option-len |
436 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
438 // . bootfile-url (variable length) .
440 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
444 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be
445 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME
446 // As an example where the BOOTFILE_NAME is the EFI loader and
447 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
449 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
451 if (Length
<= PrefixLen
||
452 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
453 return EFI_NOT_FOUND
;
456 BootFile
= BootFile
+ PrefixLen
;
457 Length
= (UINT16
) (Length
- PrefixLen
);
459 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
460 if (TmpStr
== NULL
) {
461 return EFI_OUT_OF_RESOURCES
;
464 CopyMem (TmpStr
, BootFile
, Length
);
465 TmpStr
[Length
] = '\0';
468 // Get the part of SERVER_ADDRESS string.
470 ServerAddressOption
= TmpStr
;
471 if (*ServerAddressOption
== PXEBC_ADDR_START_DELIMITER
) {
472 ServerAddressOption
++;
473 ServerAddress
= ServerAddressOption
;
474 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
478 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
480 return EFI_INVALID_PARAMETER
;
483 *ServerAddress
= '\0';
486 // Convert the string of server address to Ipv6 address format and store it.
488 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
489 if (EFI_ERROR (Status
)) {
495 IpExpressedUrl
= FALSE
;
496 ServerAddress
= ServerAddressOption
;
497 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
501 if (*ServerAddress
!= PXEBC_TFTP_URL_SEPARATOR
) {
503 return EFI_INVALID_PARAMETER
;
505 *ServerAddress
= '\0';
507 Len
= AsciiStrSize (ServerAddressOption
);
508 HostName
= AllocateZeroPool (Len
* sizeof (CHAR16
));
509 if (HostName
== NULL
) {
511 return EFI_OUT_OF_RESOURCES
;
513 AsciiStrToUnicodeStrS (
520 // Perform DNS resolution.
522 Status
= PxeBcDns6 (Private
,HostName
, SrvAddr
);
523 if (EFI_ERROR (Status
)) {
530 // Get the part of BOOTFILE_NAME string.
532 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
533 if (IpExpressedUrl
) {
534 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
536 return EFI_INVALID_PARAMETER
;
541 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
542 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
544 // Remove trailing mode=octet if present and ignore. All other modes are
545 // invalid for netboot6, so reject them.
547 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
548 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
550 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
552 return EFI_INVALID_PARAMETER
;
556 // Extract boot file name from URL.
558 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
559 if (BootFileName
== NULL
) {
561 return EFI_OUT_OF_RESOURCES
;
563 *FileName
= (UINT8
*) BootFileName
;
566 // Decode percent-encoding in boot file name.
568 while (*BootFileNamePtr
!= '\0') {
569 if (*BootFileNamePtr
== '%') {
570 TmpChar
= *(BootFileNamePtr
+ 3);
571 *(BootFileNamePtr
+ 3) = '\0';
572 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
574 *(BootFileNamePtr
+ 3) = TmpChar
;
575 BootFileNamePtr
+= 3;
577 *BootFileName
= *BootFileNamePtr
;
582 *BootFileName
= '\0';
592 Parse the Boot File Parameter option.
594 @param[in] BootFilePara The pointer to boot file parameter option data.
595 @param[out] BootFileSize The pointer to the parsed boot file size.
597 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
598 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
602 PxeBcExtractBootFileParam (
603 IN CHAR8
*BootFilePara
,
604 OUT UINT16
*BootFileSize
612 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
613 Length
= NTOHS (Length
);
616 // The BootFile Size should be 1~5 byte ASCII strings
618 if (Length
< 1 || Length
> 5) {
619 return EFI_NOT_FOUND
;
623 // Extract the value of BootFile Size.
625 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
627 for (Index
= 0; Index
< Length
; Index
++) {
628 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
629 return EFI_NOT_FOUND
;
632 Size
= (Size
+ Digit
) * 10;
636 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
637 return EFI_NOT_FOUND
;
640 *BootFileSize
= (UINT16
) Size
;
646 Parse the cached DHCPv6 packet, including all the options.
648 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
650 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
651 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
655 PxeBcParseDhcp6Packet (
656 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
659 EFI_DHCP6_PACKET
*Offer
;
660 EFI_DHCP6_PACKET_OPTION
**Options
;
661 EFI_DHCP6_PACKET_OPTION
*Option
;
662 PXEBC_OFFER_TYPE OfferType
;
663 BOOLEAN IsProxyOffer
;
667 UINT32 EnterpriseNum
;
671 Offer
= &Cache6
->Packet
.Offer
;
672 Options
= Cache6
->OptList
;
674 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
676 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
678 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
681 // OpLen and OpCode here are both stored in network order, since they are from original packet.
683 while (Offset
< Length
) {
685 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
686 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
687 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
689 // The server sends this option to inform the client about an URL to a boot file.
691 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
692 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
693 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
694 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
695 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
696 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
697 Options
[PXEBC_DHCP6_IDX_DNS_SERVER
] = Option
;
700 Offset
+= (NTOHS (Option
->OpLen
) + 4);
701 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
705 // The offer with assigned client address is NOT a proxy offer.
706 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
708 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
709 if (Option
!= NULL
) {
710 Option
= PxeBcParseDhcp6Options (
712 NTOHS (Option
->OpLen
),
713 DHCP6_OPT_STATUS_CODE
715 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
716 IsProxyOffer
= FALSE
;
721 // The offer with "PXEClient" is a pxe offer.
723 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
724 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
726 if (Option
!= NULL
&&
727 NTOHS(Option
->OpLen
) >= 13 &&
728 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
729 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
734 // Determine offer type of the dhcp6 packet.
738 // It's a binl offer only with PXEClient.
740 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
743 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
745 OfferType
= PxeOfferTypeDhcpOnly
;
748 Cache6
->OfferType
= OfferType
;
755 Cache the DHCPv6 ack packet, and parse it on demand.
757 @param[in] Private The pointer to PxeBc private data.
758 @param[in] Ack The pointer to the DHCPv6 ack packet.
759 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
761 @retval EFI_SUCCESS Cache and parse the packet successfully.
762 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
767 IN PXEBC_PRIVATE_DATA
*Private
,
768 IN EFI_DHCP6_PACKET
*Ack
,
772 EFI_PXE_BASE_CODE_MODE
*Mode
;
775 Mode
= Private
->PxeBc
.Mode
;
777 Status
= PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
778 if (EFI_ERROR (Status
)) {
784 // Parse the ack packet and store it into mode data if needed.
786 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
787 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
788 Mode
->DhcpAckReceived
= TRUE
;
796 Cache the DHCPv6 proxy offer packet according to the received order.
798 @param[in] Private The pointer to PxeBc private data.
799 @param[in] OfferIndex The received order of offer packets.
801 @retval EFI_SUCCESS Cache and parse the packet successfully.
802 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
806 PxeBcCopyDhcp6Proxy (
807 IN PXEBC_PRIVATE_DATA
*Private
,
811 EFI_PXE_BASE_CODE_MODE
*Mode
;
812 EFI_DHCP6_PACKET
*Offer
;
815 ASSERT (OfferIndex
< Private
->OfferNum
);
816 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
818 Mode
= Private
->PxeBc
.Mode
;
819 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
822 // Cache the proxy offer packet and parse it.
824 Status
= PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
825 if (EFI_ERROR(Status
)) {
828 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
831 // Store this packet into mode data.
833 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
834 Mode
->ProxyOfferReceived
= TRUE
;
840 Seek the address of the first byte of the option header.
842 @param[in] Buf The pointer to the buffer.
843 @param[in] SeekLen The length to seek.
844 @param[in] OptType The option type.
846 @retval NULL If it failed to seek the option.
847 @retval others The position to the option.
851 PxeBcDhcp6SeekOption (
865 while (Cursor
< Buf
+ SeekLen
) {
866 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
867 if (OpCode
== HTONS (OptType
)) {
871 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
872 Cursor
+= (DataLen
+ 4);
880 Build and send out the request packet for the bootfile, and parse the reply.
882 @param[in] Private The pointer to PxeBc private data.
883 @param[in] Index PxeBc option boot item type.
885 @retval EFI_SUCCESS Successfully discovered the boot file.
886 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
887 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
888 @retval Others Failed to discover the boot file.
892 PxeBcRequestBootService (
893 IN PXEBC_PRIVATE_DATA
*Private
,
897 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
898 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
899 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
900 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
902 EFI_DHCP6_PACKET
*Request
;
904 EFI_DHCP6_PACKET
*Reply
;
912 EFI_DHCP6_PACKET
*IndexOffer
;
915 PxeBc
= &Private
->PxeBc
;
916 Request
= Private
->Dhcp6Request
;
917 IndexOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
918 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
919 DestPort
= PXEBC_BS_DISCOVER_PORT
;
922 if (Request
== NULL
) {
923 return EFI_DEVICE_ERROR
;
926 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
927 if (Discover
== NULL
) {
928 return EFI_OUT_OF_RESOURCES
;
932 // Build the request packet by the cached request packet before.
934 Discover
->TransactionId
= IndexOffer
->Dhcp6
.Header
.TransactionId
;
935 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
936 RequestOpt
= Request
->Dhcp6
.Option
;
937 DiscoverOpt
= Discover
->DhcpOptions
;
938 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
939 RequestLen
= DiscoverLen
;
942 // Find Server ID Option from ProxyOffer.
944 if (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
) {
945 Option
= PxeBcDhcp6SeekOption (
946 IndexOffer
->Dhcp6
.Option
,
947 IndexOffer
->Length
- 4,
950 if (Option
== NULL
) {
951 return EFI_NOT_FOUND
;
955 // Add Server ID Option.
957 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
958 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
959 DiscoverOpt
+= (OpLen
+ 4);
960 DiscoverLen
+= (OpLen
+ 4);
963 while (RequestLen
< Request
->Length
) {
964 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
965 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
966 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
967 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
968 OpCode
!= DHCP6_OPT_SERVER_ID
971 // Copy all the options except IA option and Server ID
973 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
974 DiscoverOpt
+= (OpLen
+ 4);
975 DiscoverLen
+= (OpLen
+ 4);
977 RequestOpt
+= (OpLen
+ 4);
978 RequestLen
+= (OpLen
+ 4);
982 // Update Elapsed option in the package
984 Option
= PxeBcDhcp6SeekOption (
985 Discover
->DhcpOptions
,
986 (UINT32
)(RequestLen
- 4),
987 DHCP6_OPT_ELAPSED_TIME
989 if (Option
!= NULL
) {
990 CalcElapsedTime (Private
);
991 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
994 Status
= PxeBc
->UdpWrite (
1000 &Private
->StationIp
,
1008 if (EFI_ERROR (Status
)) {
1013 // Cache the right PXE reply packet here, set valid flag later.
1014 // Especially for PXE discover packet, store it into mode data here.
1016 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1017 ReadSize
= (UINTN
) Reply
->Size
;
1020 // Start Udp6Read instance
1022 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
1023 if (EFI_ERROR (Status
)) {
1027 Status
= PxeBc
->UdpRead (
1029 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
| EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
1037 (VOID
*) &Reply
->Dhcp6
1040 // Stop Udp6Read instance
1042 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1044 if (EFI_ERROR (Status
)) {
1051 Reply
->Length
= (UINT32
) ReadSize
;
1056 if (Discover
!= NULL
) {
1057 FreePool (Discover
);
1065 Retry to request bootfile name by the BINL offer.
1067 @param[in] Private The pointer to PxeBc private data.
1068 @param[in] Index The received order of offer packets.
1070 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
1071 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
1075 PxeBcRetryDhcp6Binl (
1076 IN PXEBC_PRIVATE_DATA
*Private
,
1080 EFI_PXE_BASE_CODE_MODE
*Mode
;
1081 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
1082 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1085 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
1086 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
1087 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
1089 Mode
= Private
->PxeBc
.Mode
;
1090 Private
->IsDoDiscover
= FALSE
;
1091 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
1092 if (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1094 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
1097 &Private
->ServerIp
.v6
,
1098 &mAllDhcpRelayAndServersAddress
,
1099 sizeof (EFI_IPv6_ADDRESS
)
1102 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1104 // Parse out the next server address from the last offer, and store it
1106 Status
= PxeBcExtractBootFileUrl (
1108 &Private
->BootFileName
,
1109 &Private
->ServerIp
.v6
,
1110 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
1111 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
1113 if (EFI_ERROR (Status
)) {
1119 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
1121 Status
= PxeBcRequestBootService (Private
, Index
);
1123 if (EFI_ERROR (Status
)) {
1127 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
1128 Status
= PxeBcParseDhcp6Packet (Cache6
);
1129 if (EFI_ERROR (Status
)) {
1133 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
1134 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
1135 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1137 // This BINL ack doesn't have discovery option set or multicast option set
1138 // or bootfile name specified.
1140 return EFI_DEVICE_ERROR
;
1143 Mode
->ProxyOfferReceived
= TRUE
;
1145 &Mode
->ProxyOffer
.Dhcpv6
,
1146 &Cache6
->Packet
.Offer
.Dhcp6
,
1147 Cache6
->Packet
.Offer
.Length
1155 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
1157 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1158 @param[in] RcvdOffer The pointer to the received offer packet.
1160 @retval EFI_SUCCESS Cache and parse the packet successfully.
1161 @retval Others Operation failed.
1164 PxeBcCacheDhcp6Offer (
1165 IN PXEBC_PRIVATE_DATA
*Private
,
1166 IN EFI_DHCP6_PACKET
*RcvdOffer
1169 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1170 EFI_DHCP6_PACKET
*Offer
;
1171 PXEBC_OFFER_TYPE OfferType
;
1174 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
1175 Offer
= &Cache6
->Packet
.Offer
;
1178 // Cache the content of DHCPv6 packet firstly.
1180 Status
= PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
1181 if (EFI_ERROR (Status
)) {
1186 // Validate the DHCPv6 packet, and parse the options and offer type.
1188 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
1193 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
1195 OfferType
= Cache6
->OfferType
;
1196 ASSERT (OfferType
< PxeOfferTypeMax
);
1197 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
1199 if (IS_PROXY_OFFER (OfferType
)) {
1201 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
1203 Private
->IsProxyRecved
= TRUE
;
1205 if (OfferType
== PxeOfferTypeProxyBinl
) {
1207 // Cache all proxy BINL offers.
1209 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1210 Private
->OfferCount
[OfferType
]++;
1211 } else if ((OfferType
== PxeOfferTypeProxyPxe10
|| OfferType
== PxeOfferTypeProxyWfm11a
) &&
1212 Private
->OfferCount
[OfferType
] < 1) {
1214 // Only cache the first PXE10/WFM11a offer, and discard the others.
1216 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
1217 Private
->OfferCount
[OfferType
] = 1;
1223 // It's a DHCPv6 offer with yiaddr, and cache them all.
1225 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
1226 Private
->OfferCount
[OfferType
]++;
1229 Private
->OfferNum
++;
1236 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
1238 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1242 PxeBcSelectDhcp6Offer (
1243 IN PXEBC_PRIVATE_DATA
*Private
1248 PXEBC_OFFER_TYPE OfferType
;
1250 Private
->SelectIndex
= 0;
1252 if (Private
->IsOfferSorted
) {
1254 // Select offer by default policy.
1256 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1258 // 1. DhcpPxe10 offer
1260 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
1262 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
1264 // 2. DhcpWfm11a offer
1266 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1268 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1269 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1271 // 3. DhcpOnly offer and ProxyPxe10 offer.
1273 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1274 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1276 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1277 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1279 // 4. DhcpOnly offer and ProxyWfm11a offer.
1281 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1282 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1284 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1286 // 5. DhcpBinl offer.
1288 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1290 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1291 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1293 // 6. DhcpOnly offer and ProxyBinl offer.
1295 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1296 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1300 // 7. DhcpOnly offer with bootfilename.
1302 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1303 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1304 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1305 Private
->SelectIndex
= OfferIndex
+ 1;
1312 // Select offer by received order.
1314 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1316 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1318 if (IS_PROXY_OFFER (OfferType
)) {
1320 // Skip proxy offers
1325 if (!Private
->IsProxyRecved
&&
1326 OfferType
== PxeOfferTypeDhcpOnly
&&
1327 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1329 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1334 Private
->SelectIndex
= Index
+ 1;
1342 Handle the DHCPv6 offer packet.
1344 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1346 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1347 @retval EFI_NO_RESPONSE No response to the following request packet.
1348 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1349 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1353 PxeBcHandleDhcp6Offer (
1354 IN PXEBC_PRIVATE_DATA
*Private
1357 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1359 PXEBC_OFFER_TYPE OfferType
;
1364 ASSERT (Private
->SelectIndex
> 0);
1365 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1366 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1367 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1368 Status
= EFI_SUCCESS
;
1371 // First try to cache DNS server address if DHCP6 offer provides.
1373 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
] != NULL
) {
1374 Private
->DnsServer
= AllocateZeroPool (NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->OpLen
));
1375 if (Private
->DnsServer
== NULL
) {
1376 return EFI_OUT_OF_RESOURCES
;
1378 CopyMem (Private
->DnsServer
, Cache6
->OptList
[PXEBC_DHCP6_IDX_DNS_SERVER
]->Data
, sizeof (EFI_IPv6_ADDRESS
));
1381 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1383 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1385 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1386 Status
= EFI_NO_RESPONSE
;
1388 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1390 if (Private
->IsProxyRecved
) {
1392 // DhcpOnly offer is selected, so need try to request bootfilename.
1395 if (Private
->IsOfferSorted
) {
1397 // The proxy offer should be determined if select by default policy.
1398 // IsOfferSorted means all offers are labeled by OfferIndex.
1400 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1402 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1404 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1406 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1408 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1409 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1413 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1414 Status
= EFI_NO_RESPONSE
;
1418 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1420 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1424 // The proxy offer should not be determined if select by received order.
1426 Status
= EFI_NO_RESPONSE
;
1428 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1430 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1432 if (!IS_PROXY_OFFER (OfferType
)) {
1434 // Skip non proxy dhcp offers.
1439 if (OfferType
== PxeOfferTypeProxyBinl
) {
1441 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1443 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1448 Private
->SelectProxyType
= OfferType
;
1450 Status
= EFI_SUCCESS
;
1455 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1457 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1459 Status
= PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1463 // Othewise, the bootfilename must be included in DhcpOnly offer.
1465 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1469 if (!EFI_ERROR (Status
)) {
1471 // All PXE boot information is ready by now.
1473 Status
= PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1474 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1482 Unregister the address by Ip6Config protocol.
1484 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1488 PxeBcUnregisterIp6Address (
1489 IN PXEBC_PRIVATE_DATA
*Private
1492 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1494 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1495 // Keep the point and there is no enough requirements to do recovery.
1501 Check whether IP driver could route the message which will be sent to ServerIp address.
1503 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1504 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1506 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1507 @param[in] TimeOutInSecond Timeout value in seconds.
1508 @param[out] GatewayAddr Pointer to store the gateway IP address.
1510 @retval EFI_SUCCESS Found a valid gateway address successfully.
1511 @retval EFI_TIMEOUT The operation is time out.
1512 @retval Other Unexpect error happened.
1516 PxeBcCheckRouteTable (
1517 IN PXEBC_PRIVATE_DATA
*Private
,
1518 IN UINTN TimeOutInSecond
,
1519 OUT EFI_IPv6_ADDRESS
*GatewayAddr
1523 EFI_IP6_PROTOCOL
*Ip6
;
1524 EFI_IP6_MODE_DATA Ip6ModeData
;
1526 EFI_EVENT TimeOutEvt
;
1528 BOOLEAN GatewayIsFound
;
1530 ASSERT (GatewayAddr
!= NULL
);
1531 ASSERT (Private
!= NULL
);
1534 GatewayIsFound
= FALSE
;
1537 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
1540 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
1541 if (EFI_ERROR (Status
)) {
1546 // Find out the gateway address which can route the message which send to ServerIp.
1548 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
1549 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
1550 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
1551 GatewayIsFound
= TRUE
;
1556 if (Ip6ModeData
.AddressList
!= NULL
) {
1557 FreePool (Ip6ModeData
.AddressList
);
1559 if (Ip6ModeData
.GroupTable
!= NULL
) {
1560 FreePool (Ip6ModeData
.GroupTable
);
1562 if (Ip6ModeData
.RouteTable
!= NULL
) {
1563 FreePool (Ip6ModeData
.RouteTable
);
1565 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1566 FreePool (Ip6ModeData
.NeighborCache
);
1568 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1569 FreePool (Ip6ModeData
.PrefixTable
);
1571 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1572 FreePool (Ip6ModeData
.IcmpTypeList
);
1575 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
1582 // Delay 1 second then recheck it again.
1584 if (TimeOutEvt
== NULL
) {
1585 Status
= gBS
->CreateEvent (
1592 if (EFI_ERROR (Status
)) {
1597 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
1598 if (EFI_ERROR (Status
)) {
1601 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1607 if (TimeOutEvt
!= NULL
) {
1608 gBS
->CloseEvent (TimeOutEvt
);
1611 if (GatewayIsFound
) {
1612 Status
= EFI_SUCCESS
;
1613 } else if (RetryCount
== TimeOutInSecond
) {
1614 Status
= EFI_TIMEOUT
;
1621 Register the ready station address and gateway by Ip6Config protocol.
1623 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1624 @param[in] Address The pointer to the ready address.
1626 @retval EFI_SUCCESS Registered the address succesfully.
1627 @retval Others Failed to register the address.
1631 PxeBcRegisterIp6Address (
1632 IN PXEBC_PRIVATE_DATA
*Private
,
1633 IN EFI_IPv6_ADDRESS
*Address
1636 EFI_IP6_PROTOCOL
*Ip6
;
1637 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1638 EFI_IP6_CONFIG_POLICY Policy
;
1639 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1640 EFI_IPv6_ADDRESS GatewayAddr
;
1642 EFI_EVENT MappedEvt
;
1645 EFI_IPv6_ADDRESS
*Ip6Addr
;
1648 Status
= EFI_SUCCESS
;
1651 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1652 Ip6Cfg
= Private
->Ip6Cfg
;
1656 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1657 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1659 Status
= Ip6
->Configure (Ip6
, &Private
->Ip6CfgData
);
1660 if (EFI_ERROR (Status
)) {
1665 // Retrieve the gateway address from IP6 route table.
1667 Status
= PxeBcCheckRouteTable (Private
, PXEBC_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
1668 if (EFI_ERROR (Status
)) {
1673 // There is no channel between IP6 and PXE driver about address setting,
1674 // so it has to set the new address by Ip6ConfigProtocol manually.
1676 Policy
= Ip6ConfigPolicyManual
;
1677 Status
= Ip6Cfg
->SetData (
1679 Ip6ConfigDataTypePolicy
,
1680 sizeof(EFI_IP6_CONFIG_POLICY
),
1683 if (EFI_ERROR (Status
)) {
1685 // There is no need to recover later.
1687 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1692 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1694 Status
= gBS
->CreateEvent (
1698 &Private
->IsAddressOk
,
1701 if (EFI_ERROR (Status
)) {
1705 Private
->IsAddressOk
= FALSE
;
1706 Status
= Ip6Cfg
->RegisterDataNotify (
1708 Ip6ConfigDataTypeManualAddress
,
1711 if (EFI_ERROR(Status
)) {
1715 Status
= Ip6Cfg
->SetData (
1717 Ip6ConfigDataTypeManualAddress
,
1718 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1721 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1723 } else if (Status
== EFI_NOT_READY
) {
1725 // Poll the network until the asynchronous process is finished.
1727 while (!Private
->IsAddressOk
) {
1731 // Check whether the IP6 address setting is successed.
1734 Status
= Ip6Cfg
->GetData (
1736 Ip6ConfigDataTypeManualAddress
,
1740 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
1741 Status
= EFI_DEVICE_ERROR
;
1745 Ip6Addr
= AllocatePool (DataSize
);
1746 if (Ip6Addr
== NULL
) {
1747 return EFI_OUT_OF_RESOURCES
;
1749 Status
= Ip6Cfg
->GetData (
1751 Ip6ConfigDataTypeManualAddress
,
1755 if (EFI_ERROR (Status
)) {
1756 Status
= EFI_DEVICE_ERROR
;
1760 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
1761 if (CompareMem (Ip6Addr
+ Index
, Address
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
1765 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
1766 Status
= EFI_ABORTED
;
1772 // Set the default gateway address back if needed.
1774 if (!NoGateway
&& !NetIp6IsUnspecifiedAddr (&GatewayAddr
)) {
1775 Status
= Ip6Cfg
->SetData (
1777 Ip6ConfigDataTypeGateway
,
1778 sizeof (EFI_IPv6_ADDRESS
),
1781 if (EFI_ERROR (Status
)) {
1787 if (MappedEvt
!= NULL
) {
1788 Ip6Cfg
->UnregisterDataNotify (
1790 Ip6ConfigDataTypeManualAddress
,
1793 gBS
->CloseEvent (MappedEvt
);
1795 if (Ip6Addr
!= NULL
) {
1802 Set the IP6 policy to Automatic.
1804 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1806 @retval EFI_SUCCESS Switch the IP policy succesfully.
1807 @retval Others Unexpect error happened.
1812 IN PXEBC_PRIVATE_DATA
*Private
1815 EFI_IP6_CONFIG_POLICY Policy
;
1817 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1820 Ip6Cfg
= Private
->Ip6Cfg
;
1821 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1824 // Get and store the current policy of IP6 driver.
1826 Status
= Ip6Cfg
->GetData (
1828 Ip6ConfigDataTypePolicy
,
1832 if (EFI_ERROR (Status
)) {
1836 if (Private
->Ip6Policy
== Ip6ConfigPolicyManual
) {
1837 Policy
= Ip6ConfigPolicyAutomatic
;
1838 Status
= Ip6Cfg
->SetData (
1840 Ip6ConfigDataTypePolicy
,
1841 sizeof(EFI_IP6_CONFIG_POLICY
),
1844 if (EFI_ERROR (Status
)) {
1846 // There is no need to recover later.
1848 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1856 This function will register the station IP address and flush IP instance to start using the new IP address.
1858 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1860 @retval EFI_SUCCESS The new IP address has been configured successfully.
1861 @retval Others Failed to configure the address.
1865 PxeBcSetIp6Address (
1866 IN PXEBC_PRIVATE_DATA
*Private
1870 EFI_DHCP6_PROTOCOL
*Dhcp6
;
1872 Dhcp6
= Private
->Dhcp6
;
1874 CopyMem (&Private
->StationIp
.v6
, &Private
->TmpStationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1875 CopyMem (&Private
->PxeBc
.Mode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1877 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1878 if (EFI_ERROR (Status
)) {
1879 Dhcp6
->Stop (Dhcp6
);
1883 Status
= PxeBcFlushStationIp (Private
, &Private
->StationIp
, NULL
);
1884 if (EFI_ERROR (Status
)) {
1885 PxeBcUnregisterIp6Address (Private
);
1886 Dhcp6
->Stop (Dhcp6
);
1890 AsciiPrint ("\n Station IP address is ");
1891 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);
1897 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1898 to intercept events that occurred in the configuration process.
1900 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1901 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1902 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1903 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1905 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1906 @param[out] NewPacket The packet that is used to replace the Packet above.
1908 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1909 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1910 driver will continue to wait for more packets.
1911 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1916 PxeBcDhcp6CallBack (
1917 IN EFI_DHCP6_PROTOCOL
*This
,
1919 IN EFI_DHCP6_STATE CurrentState
,
1920 IN EFI_DHCP6_EVENT Dhcp6Event
,
1921 IN EFI_DHCP6_PACKET
*Packet
,
1922 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1925 PXEBC_PRIVATE_DATA
*Private
;
1926 EFI_PXE_BASE_CODE_MODE
*Mode
;
1927 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1928 EFI_DHCP6_PACKET
*SelectAd
;
1932 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1933 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1934 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1935 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1936 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1940 ASSERT (Packet
!= NULL
);
1942 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1943 Mode
= Private
->PxeBc
.Mode
;
1944 Callback
= Private
->PxeBcCallback
;
1947 // Callback to user when any traffic ocurred if has.
1949 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1950 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1951 Status
= Callback
->Callback (
1956 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1958 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1963 Status
= EFI_SUCCESS
;
1965 switch (Dhcp6Event
) {
1967 case Dhcp6SendSolicit
:
1968 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1970 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1972 Status
= EFI_ABORTED
;
1977 // Record the first Solicate msg time
1979 if (Private
->SolicitTimes
== 0) {
1980 CalcElapsedTime (Private
);
1981 Private
->SolicitTimes
++;
1984 // Cache the dhcp discover packet to mode data directly.
1986 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1989 case Dhcp6RcvdAdvertise
:
1990 Status
= EFI_NOT_READY
;
1991 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
1993 // Ignore the incoming packets which exceed the maximum length.
1997 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1999 // Cache the dhcp offers to OfferBuffer[] for select later, and record
2000 // the OfferIndex and OfferCount.
2002 PxeBcCacheDhcp6Offer (Private
, Packet
);
2006 case Dhcp6SendRequest
:
2007 if (Packet
->Length
> PXEBC_DHCP6_PACKET_MAX_SIZE
) {
2009 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
2011 Status
= EFI_ABORTED
;
2016 // Store the request packet as seed packet for discover.
2018 if (Private
->Dhcp6Request
!= NULL
) {
2019 FreePool (Private
->Dhcp6Request
);
2021 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
2022 if (Private
->Dhcp6Request
!= NULL
) {
2023 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
2027 case Dhcp6SelectAdvertise
:
2029 // Select offer by the default policy or by order, and record the SelectIndex
2030 // and SelectProxyType.
2032 PxeBcSelectDhcp6Offer (Private
);
2034 if (Private
->SelectIndex
== 0) {
2035 Status
= EFI_ABORTED
;
2037 ASSERT (NewPacket
!= NULL
);
2038 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
2039 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
2040 ASSERT (*NewPacket
!= NULL
);
2041 if (*NewPacket
== NULL
) {
2044 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
2048 case Dhcp6RcvdReply
:
2050 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
2051 // without verification.
2053 ASSERT (Private
->SelectIndex
!= 0);
2054 Status
= PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
2055 if (EFI_ERROR (Status
)) {
2056 Status
= EFI_ABORTED
;
2069 Build and send out the request packet for the bootfile, and parse the reply.
2071 @param[in] Private The pointer to PxeBc private data.
2072 @param[in] Type PxeBc option boot item type.
2073 @param[in] Layer The pointer to option boot item layer.
2074 @param[in] UseBis Use BIS or not.
2075 @param[in] DestIp The pointer to the server address.
2077 @retval EFI_SUCCESS Successfully discovered the boot file.
2078 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
2079 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
2080 @retval Others Failed to discover the boot file.
2084 PxeBcDhcp6Discover (
2085 IN PXEBC_PRIVATE_DATA
*Private
,
2089 IN EFI_IP_ADDRESS
*DestIp
2092 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
2093 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
2094 EFI_PXE_BASE_CODE_MODE
*Mode
;
2095 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
2096 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
2098 EFI_DHCP6_PACKET
*Request
;
2100 EFI_DHCP6_PACKET
*Reply
;
2109 PxeBc
= &Private
->PxeBc
;
2111 Request
= Private
->Dhcp6Request
;
2112 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
2113 DestPort
= PXEBC_BS_DISCOVER_PORT
;
2115 if (!UseBis
&& Layer
!= NULL
) {
2116 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
2119 if (Request
== NULL
) {
2120 return EFI_DEVICE_ERROR
;
2123 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
2124 if (Discover
== NULL
) {
2125 return EFI_OUT_OF_RESOURCES
;
2129 // Build the discover packet by the cached request packet before.
2131 Xid
= NET_RANDOM (NetRandomInitSeed ());
2132 Discover
->TransactionId
= HTONL (Xid
);
2133 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
2134 RequestOpt
= Request
->Dhcp6
.Option
;
2135 DiscoverOpt
= Discover
->DhcpOptions
;
2136 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
2137 RequestLen
= DiscoverLen
;
2139 while (RequestLen
< Request
->Length
) {
2140 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
2141 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
2142 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
2143 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
2145 // Copy all the options except IA option.
2147 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
2148 DiscoverOpt
+= (OpLen
+ 4);
2149 DiscoverLen
+= (OpLen
+ 4);
2151 RequestOpt
+= (OpLen
+ 4);
2152 RequestLen
+= (OpLen
+ 4);
2155 Status
= PxeBc
->UdpWrite (
2161 &Private
->StationIp
,
2168 if (EFI_ERROR (Status
)) {
2173 // Cache the right PXE reply packet here, set valid flag later.
2174 // Especially for PXE discover packet, store it into mode data here.
2176 if (Private
->IsDoDiscover
) {
2177 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
2178 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
2180 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
2182 ReadSize
= (UINTN
) Reply
->Size
;
2185 // Start Udp6Read instance
2187 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
2188 if (EFI_ERROR (Status
)) {
2192 Status
= PxeBc
->UdpRead (
2194 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
,
2202 (VOID
*) &Reply
->Dhcp6
2205 // Stop Udp6Read instance
2207 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
2208 if (EFI_ERROR (Status
)) {
2215 if (Discover
!= NULL
) {
2216 FreePool (Discover
);
2224 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
2226 @param[in] Private The pointer to PxeBc private data.
2227 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
2229 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
2230 @retval Others Failed to finish the S.A.R.R. process.
2235 IN PXEBC_PRIVATE_DATA
*Private
,
2236 IN EFI_DHCP6_PROTOCOL
*Dhcp6
2239 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
2240 EFI_DHCP6_CONFIG_DATA Config
;
2241 EFI_DHCP6_MODE_DATA Mode
;
2242 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
2243 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
2244 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
2247 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
2248 EFI_STATUS TimerStatus
;
2250 UINT64 GetMappingTimeOut
;
2252 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
2254 Status
= EFI_SUCCESS
;
2255 PxeMode
= Private
->PxeBc
.Mode
;
2256 Ip6Cfg
= Private
->Ip6Cfg
;
2260 // Build option list for the request packet.
2262 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
2263 ASSERT (OptCount
> 0);
2265 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
2266 if (Retransmit
== NULL
) {
2267 return EFI_OUT_OF_RESOURCES
;
2270 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
2271 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
2273 Config
.OptionCount
= OptCount
;
2274 Config
.OptionList
= OptList
;
2275 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
2276 Config
.CallbackContext
= Private
;
2277 Config
.IaInfoEvent
= NULL
;
2278 Config
.RapidCommit
= FALSE
;
2279 Config
.ReconfigureAccept
= FALSE
;
2280 Config
.IaDescriptor
.IaId
= Private
->IaId
;
2281 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
2282 Config
.SolicitRetransmission
= Retransmit
;
2283 Retransmit
->Irt
= 4;
2284 Retransmit
->Mrc
= 4;
2285 Retransmit
->Mrt
= 32;
2286 Retransmit
->Mrd
= 60;
2289 // Configure the DHCPv6 instance for PXE boot.
2291 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
2292 FreePool (Retransmit
);
2293 if (EFI_ERROR (Status
)) {
2298 // Initialize the record fields for DHCPv6 offer in private data.
2300 Private
->IsProxyRecved
= FALSE
;
2301 Private
->OfferNum
= 0;
2302 Private
->SelectIndex
= 0;
2303 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
2304 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
2308 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2310 Status
= Dhcp6
->Start (Dhcp6
);
2311 if (Status
== EFI_NO_MAPPING
) {
2313 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2314 // and wait for duplicate address detection to finish.
2316 Dhcp6
->Stop (Dhcp6
);
2319 // Get Duplicate Address Detection Transmits count.
2321 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
2322 Status
= Ip6Cfg
->GetData (
2324 Ip6ConfigDataTypeDupAddrDetectTransmits
,
2328 if (EFI_ERROR (Status
)) {
2329 Dhcp6
->Configure (Dhcp6
, NULL
);
2333 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2334 if (EFI_ERROR (Status
)) {
2335 Dhcp6
->Configure (Dhcp6
, NULL
);
2339 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
2340 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
2341 if (EFI_ERROR (Status
)) {
2342 gBS
->CloseEvent (Timer
);
2343 Dhcp6
->Configure (Dhcp6
, NULL
);
2349 TimerStatus
= gBS
->CheckEvent (Timer
);
2350 if (!EFI_ERROR (TimerStatus
)) {
2351 Status
= Dhcp6
->Start (Dhcp6
);
2353 } while (TimerStatus
== EFI_NOT_READY
);
2355 gBS
->CloseEvent (Timer
);
2357 if (EFI_ERROR (Status
)) {
2358 if (Status
== EFI_ICMP_ERROR
) {
2359 PxeMode
->IcmpErrorReceived
= TRUE
;
2361 Dhcp6
->Configure (Dhcp6
, NULL
);
2366 // Get the acquired IPv6 address and store them.
2368 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
2369 if (EFI_ERROR (Status
)) {
2370 Dhcp6
->Stop (Dhcp6
);
2374 ASSERT ((Mode
.Ia
!= NULL
) && (Mode
.Ia
->State
== Dhcp6Bound
));
2376 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2377 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2378 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2379 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2380 // to find a valid router address.
2382 CopyMem (&Private
->TmpStationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2383 if (Mode
.ClientId
!= NULL
) {
2384 FreePool (Mode
.ClientId
);
2386 if (Mode
.Ia
!= NULL
) {
2390 // Check the selected offer whether BINL retry is needed.
2392 Status
= PxeBcHandleDhcp6Offer (Private
);
2393 if (EFI_ERROR (Status
)) {
2394 Dhcp6
->Stop (Dhcp6
);