2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PxeBcImpl.h"
19 // Well-known multi-cast address defined in section-24.1 of rfc-3315
21 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
23 EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress
= {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
26 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
28 @param[in] Buffer The pointer to the option buffer.
29 @param[in] Length Length of the option buffer.
30 @param[in] OptTag The required option tag.
32 @retval NULL Failed to parse the required option.
33 @retval Others The postion of the required option in buffer.
36 EFI_DHCP6_PACKET_OPTION
*
37 PxeBcParseDhcp6Options (
43 EFI_DHCP6_PACKET_OPTION
*Option
;
46 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
50 // OpLen and OpCode here are both stored in network order.
52 while (Offset
< Length
) {
54 if (NTOHS (Option
->OpCode
) == OptTag
) {
59 Offset
+= (NTOHS(Option
->OpLen
) + 4);
60 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
68 Build the options buffer for the DHCPv6 request packet.
70 @param[in] Private The pointer to PxeBc private data.
71 @param[out] OptList The pointer to the option pointer array.
72 @param[in] Buffer The pointer to the buffer to contain the option list.
74 @return Index The count of the built-in options.
78 PxeBcBuildDhcp6Options (
79 IN PXEBC_PRIVATE_DATA
*Private
,
80 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
84 PXEBC_DHCP6_OPTION_ENTRY OptEnt
;
89 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
92 // Append client option request option
94 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ORO
);
95 OptList
[Index
]->OpLen
= HTONS (4);
96 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
97 OptEnt
.Oro
->OpCode
[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL
);
98 OptEnt
.Oro
->OpCode
[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
);
100 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
103 // Append client network device interface option
105 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_UNDI
);
106 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
107 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
109 if (Private
->Nii
!= NULL
) {
110 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
111 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
112 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
114 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
115 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
116 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
120 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
123 // Append client system architecture option
125 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ARCH
);
126 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
127 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
128 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
129 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
131 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
134 // Append vendor class option to store the PXE class identifier.
136 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS
);
137 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
138 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
139 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
140 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
142 &OptEnt
.VendorClass
->ClassId
,
143 DEFAULT_CLASS_ID_DATA
,
144 sizeof (PXEBC_CLASS_ID
)
146 PxeBcUintnToAscDecWithFormat (
147 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
148 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
149 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
152 if (Private
->Nii
!= NULL
) {
154 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
155 Private
->Nii
->StringId
,
156 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
158 PxeBcUintnToAscDecWithFormat (
159 Private
->Nii
->MajorVer
,
160 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
161 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
163 PxeBcUintnToAscDecWithFormat (
164 Private
->Nii
->MinorVer
,
165 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
166 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
177 Cache the DHCPv6 packet.
179 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
180 @param[in] Src The pointer to the DHCPv6 packet to be cached.
184 PxeBcCacheDhcp6Packet (
185 IN EFI_DHCP6_PACKET
*Dst
,
186 IN EFI_DHCP6_PACKET
*Src
189 ASSERT (Dst
->Size
>= Src
->Length
);
191 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
192 Dst
->Length
= Src
->Length
;
197 Free all the nodes in the list for boot file.
199 @param[in] Head The pointer to the head of list.
203 PxeBcFreeBootFileOption (
208 LIST_ENTRY
*NextEntry
;
209 PXEBC_DHCP6_OPTION_NODE
*Node
;
211 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
212 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
213 RemoveEntryList (Entry
);
220 Parse the Boot File URL option.
222 @param[out] FileName The pointer to the boot file name.
223 @param[in, out] SrvAddr The pointer to the boot server address.
224 @param[in] BootFile The pointer to the boot file URL option data.
225 @param[in] Length The length of the boot file URL option data.
227 @retval EFI_ABORTED User cancel operation.
228 @retval EFI_SUCCESS Selected the boot menu successfully.
229 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
233 PxeBcExtractBootFileUrl (
234 OUT UINT8
**FileName
,
235 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
241 CHAR8
*BootFileNamePtr
;
243 UINT16 BootFileNameLen
;
246 CHAR8
*ServerAddressOption
;
247 CHAR8
*ServerAddress
;
252 // The format of the Boot File URL option is:
255 // 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
256 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
257 // | OPT_BOOTFILE_URL | option-len |
258 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
260 // . bootfile-url (variable length) .
262 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
266 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
267 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
268 // As an example where the BOOTFILE_NAME is the EFI loader and
269 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
271 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
273 if (Length
<= PrefixLen
||
274 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
275 return EFI_NOT_FOUND
;
278 BootFile
= BootFile
+ PrefixLen
;
279 Length
= (UINT16
) (Length
- PrefixLen
);
281 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
282 if (TmpStr
== NULL
) {
283 return EFI_OUT_OF_RESOURCES
;
286 CopyMem (TmpStr
, BootFile
, Length
);
287 TmpStr
[Length
] = '\0';
290 // Get the part of SERVER_ADDRESS string.
292 ServerAddressOption
= TmpStr
;
293 if (*ServerAddressOption
!= PXEBC_ADDR_START_DELIMITER
) {
295 return EFI_INVALID_PARAMETER
;
298 ServerAddressOption
++;
299 ServerAddress
= ServerAddressOption
;
300 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
304 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
306 return EFI_INVALID_PARAMETER
;
309 *ServerAddress
= '\0';
312 // Convert the string of server address to Ipv6 address format and store it.
314 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
315 if (EFI_ERROR (Status
)) {
321 // Get the part of BOOTFILE_NAME string.
323 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
324 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
326 return EFI_INVALID_PARAMETER
;
330 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
331 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
333 // Remove trailing mode=octet if present and ignore. All other modes are
334 // invalid for netboot6, so reject them.
336 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
337 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
339 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
340 return EFI_INVALID_PARAMETER
;
344 // Extract boot file name from URL.
346 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
347 if (BootFileName
== NULL
) {
349 return EFI_OUT_OF_RESOURCES
;
351 *FileName
= (UINT8
*) BootFileName
;
354 // Decode percent-encoding in boot file name.
356 while (*BootFileNamePtr
!= '\0') {
357 if (*BootFileNamePtr
== '%') {
358 TmpChar
= *(BootFileNamePtr
+ 3);
359 *(BootFileNamePtr
+ 3) = '\0';
360 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
362 *(BootFileNamePtr
+ 3) = TmpChar
;
363 BootFileNamePtr
+= 3;
365 *BootFileName
= *BootFileNamePtr
;
370 *BootFileName
= '\0';
380 Parse the Boot File Parameter option.
382 @param[in] BootFilePara The pointer to boot file parameter option data.
383 @param[out] BootFileSize The pointer to the parsed boot file size.
385 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
386 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
390 PxeBcExtractBootFileParam (
391 IN CHAR8
*BootFilePara
,
392 OUT UINT16
*BootFileSize
400 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
401 Length
= NTOHS (Length
);
404 // The BootFile Size should be 1~5 byte ASCII strings
406 if (Length
< 1 || Length
> 5) {
407 return EFI_NOT_FOUND
;
411 // Extract the value of BootFile Size.
413 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
415 for (Index
= 0; Index
< Length
; Index
++) {
416 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
417 return EFI_NOT_FOUND
;
420 Size
= (Size
+ Digit
) * 10;
424 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
425 return EFI_NOT_FOUND
;
428 *BootFileSize
= (UINT16
) Size
;
434 Parse the cached DHCPv6 packet, including all the options.
436 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
438 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
439 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
443 PxeBcParseDhcp6Packet (
444 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
447 EFI_DHCP6_PACKET
*Offer
;
448 EFI_DHCP6_PACKET_OPTION
**Options
;
449 EFI_DHCP6_PACKET_OPTION
*Option
;
450 PXEBC_OFFER_TYPE OfferType
;
451 BOOLEAN IsProxyOffer
;
455 UINT32 EnterpriseNum
;
459 Offer
= &Cache6
->Packet
.Offer
;
460 Options
= Cache6
->OptList
;
462 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
464 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
466 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
469 // OpLen and OpCode here are both stored in network order, since they are from original packet.
471 while (Offset
< Length
) {
473 if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_IA_NA
) {
474 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
475 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_URL
) {
477 // The server sends this option to inform the client about an URL to a boot file.
479 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
480 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
) {
481 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
482 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_VENDOR_CLASS
) {
483 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
486 Offset
+= (NTOHS (Option
->OpLen
) + 4);
487 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
491 // The offer with assigned client address is a proxy offer.
492 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
494 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
495 if (Option
!= NULL
) {
496 Option
= PxeBcParseDhcp6Options (
498 NTOHS (Option
->OpLen
),
499 PXEBC_DHCP6_OPT_STATUS_CODE
501 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
502 IsProxyOffer
= FALSE
;
507 // The offer with "PXEClient" is a pxe offer.
509 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
510 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
512 if (Option
!= NULL
&&
513 NTOHS(Option
->OpLen
) >= 13 &&
514 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
515 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
520 // Determine offer type of the dhcp6 packet.
524 // It's a binl offer only with PXEClient.
526 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
529 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
531 OfferType
= PxeOfferTypeDhcpOnly
;
534 Cache6
->OfferType
= OfferType
;
541 Cache the DHCPv6 ack packet, and parse it on demand.
543 @param[in] Private The pointer to PxeBc private data.
544 @param[in] Ack The pointer to the DHCPv6 ack packet.
545 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
550 IN PXEBC_PRIVATE_DATA
*Private
,
551 IN EFI_DHCP6_PACKET
*Ack
,
555 EFI_PXE_BASE_CODE_MODE
*Mode
;
557 Mode
= Private
->PxeBc
.Mode
;
559 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
563 // Parse the ack packet and store it into mode data if needed.
565 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
566 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
567 Mode
->DhcpAckReceived
= TRUE
;
573 Cache the DHCPv6 proxy offer packet according to the received order.
575 @param[in] Private The pointer to PxeBc private data.
576 @param[in] OfferIndex The received order of offer packets.
580 PxeBcCopyDhcp6Proxy (
581 IN PXEBC_PRIVATE_DATA
*Private
,
585 EFI_PXE_BASE_CODE_MODE
*Mode
;
586 EFI_DHCP6_PACKET
*Offer
;
588 ASSERT (OfferIndex
< Private
->OfferNum
);
589 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
591 Mode
= Private
->PxeBc
.Mode
;
592 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
595 // Cache the proxy offer packet and parse it.
597 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
598 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
601 // Store this packet into mode data.
603 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
604 Mode
->ProxyOfferReceived
= TRUE
;
608 Seek the address of the first byte of the option header.
610 @param[in] Buf The pointer to the buffer.
611 @param[in] SeekLen The length to seek.
612 @param[in] OptType The option type.
614 @retval NULL If it failed to seek the option.
615 @retval others The position to the option.
619 PxeBcDhcp6SeekOption (
633 while (Cursor
< Buf
+ SeekLen
) {
634 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
635 if (OpCode
== HTONS (OptType
)) {
639 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
640 Cursor
+= (DataLen
+ 4);
648 Build and send out the request packet for the bootfile, and parse the reply.
650 @param[in] Private The pointer to PxeBc private data.
651 @param[in] Index PxeBc option boot item type.
653 @retval EFI_SUCCESS Successfully discovered the boot file.
654 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
655 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
656 @retval Others Failed to discover the boot file.
660 PxeBcRequestBootService (
661 IN PXEBC_PRIVATE_DATA
*Private
,
665 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
666 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
667 EFI_PXE_BASE_CODE_MODE
*Mode
;
668 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
669 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
671 EFI_DHCP6_PACKET
*Request
;
673 EFI_DHCP6_PACKET
*Reply
;
681 EFI_DHCP6_PACKET
*ProxyOffer
;
684 PxeBc
= &Private
->PxeBc
;
686 Request
= Private
->Dhcp6Request
;
687 ProxyOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
688 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
689 DestPort
= PXEBC_BS_DISCOVER_PORT
;
692 if (Request
== NULL
) {
693 return EFI_DEVICE_ERROR
;
696 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
697 if (Discover
== NULL
) {
698 return EFI_OUT_OF_RESOURCES
;
702 // Build the request packet by the cached request packet before.
704 Discover
->TransactionId
= ProxyOffer
->Dhcp6
.Header
.TransactionId
;
705 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
706 RequestOpt
= Request
->Dhcp6
.Option
;
707 DiscoverOpt
= Discover
->DhcpOptions
;
708 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
709 RequestLen
= DiscoverLen
;
712 // Find Server ID Option from ProxyOffer.
714 Option
= PxeBcDhcp6SeekOption (
715 ProxyOffer
->Dhcp6
.Option
,
716 ProxyOffer
->Length
- 4,
717 PXEBC_DHCP6_OPT_SERVER_ID
719 if (Option
== NULL
) {
720 return EFI_NOT_FOUND
;
724 // Add Server ID Option.
726 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
727 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
728 DiscoverOpt
+= (OpLen
+ 4);
729 DiscoverLen
+= (OpLen
+ 4);
731 while (RequestLen
< Request
->Length
) {
732 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
733 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
734 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
735 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
736 OpCode
!= PXEBC_DHCP6_OPT_SERVER_ID
739 // Copy all the options except IA option and Server ID
741 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
742 DiscoverOpt
+= (OpLen
+ 4);
743 DiscoverLen
+= (OpLen
+ 4);
745 RequestOpt
+= (OpLen
+ 4);
746 RequestLen
+= (OpLen
+ 4);
750 // Update Elapsed option in the package
752 Option
= PxeBcDhcp6SeekOption (
753 Discover
->DhcpOptions
,
754 (UINT32
)(RequestLen
- 4),
755 PXEBC_DHCP6_OPT_ELAPSED_TIME
757 if (Option
!= NULL
) {
758 CalcElapsedTime (Private
);
759 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
762 Status
= PxeBc
->UdpWrite (
776 if (EFI_ERROR (Status
)) {
781 // Cache the right PXE reply packet here, set valid flag later.
782 // Especially for PXE discover packet, store it into mode data here.
784 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
785 ReadSize
= (UINTN
) Reply
->Size
;
788 // Start Udp6Read instance
790 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
791 if (EFI_ERROR (Status
)) {
795 Status
= PxeBc
->UdpRead (
797 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
,
805 (VOID
*) &Reply
->Dhcp6
808 // Stop Udp6Read instance
810 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
812 if (EFI_ERROR (Status
)) {
819 Reply
->Length
= (UINT32
) ReadSize
;
826 Retry to request bootfile name by the BINL offer.
828 @param[in] Private The pointer to PxeBc private data.
829 @param[in] Index The received order of offer packets.
831 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
832 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
836 PxeBcRetryDhcp6Binl (
837 IN PXEBC_PRIVATE_DATA
*Private
,
841 EFI_PXE_BASE_CODE_MODE
*Mode
;
842 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
843 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
846 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
847 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
848 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
850 Mode
= Private
->PxeBc
.Mode
;
851 Private
->IsDoDiscover
= FALSE
;
852 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
853 if (Offer
->OfferType
== PxeOfferTypeDhcpBinl
) {
855 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
858 &Private
->ServerIp
.v6
,
859 &mAllDhcpRelayAndServersAddress
,
860 sizeof (EFI_IPv6_ADDRESS
)
863 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
865 // Parse out the next server address from the last offer, and store it
867 Status
= PxeBcExtractBootFileUrl (
868 &Private
->BootFileName
,
869 &Private
->ServerIp
.v6
,
870 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
871 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
873 if (EFI_ERROR (Status
)) {
879 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
881 Status
= PxeBcRequestBootService (Private
, Index
);
883 if (EFI_ERROR (Status
)) {
887 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
888 Status
= PxeBcParseDhcp6Packet (Cache6
);
889 if (EFI_ERROR (Status
)) {
893 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
894 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
895 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
897 // This BINL ack doesn't have discovery option set or multicast option set
898 // or bootfile name specified.
900 return EFI_DEVICE_ERROR
;
903 Mode
->ProxyOfferReceived
= TRUE
;
905 &Mode
->ProxyOffer
.Dhcpv6
,
906 &Cache6
->Packet
.Offer
.Dhcp6
,
907 Cache6
->Packet
.Offer
.Length
915 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
917 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
918 @param[in] RcvdOffer The pointer to the received offer packet.
922 PxeBcCacheDhcp6Offer (
923 IN PXEBC_PRIVATE_DATA
*Private
,
924 IN EFI_DHCP6_PACKET
*RcvdOffer
927 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
928 EFI_DHCP6_PACKET
*Offer
;
929 PXEBC_OFFER_TYPE OfferType
;
931 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
932 Offer
= &Cache6
->Packet
.Offer
;
935 // Cache the content of DHCPv6 packet firstly.
937 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
940 // Validate the DHCPv6 packet, and parse the options and offer type.
942 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
947 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
949 OfferType
= Cache6
->OfferType
;
950 ASSERT (OfferType
< PxeOfferTypeMax
);
951 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
953 if (IS_PROXY_OFFER (OfferType
)) {
955 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
957 Private
->IsProxyRecved
= TRUE
;
959 if (OfferType
== PxeOfferTypeProxyBinl
) {
961 // Cache all proxy BINL offers.
963 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
964 Private
->OfferCount
[OfferType
]++;
965 } else if (Private
->OfferCount
[OfferType
] > 0) {
967 // Only cache the first PXE10/WFM11a offer, and discard the others.
969 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
970 Private
->OfferCount
[OfferType
] = 1;
976 // It's a DHCPv6 offer with yiaddr, and cache them all.
978 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
979 Private
->OfferCount
[OfferType
]++;
987 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
989 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
993 PxeBcSelectDhcp6Offer (
994 IN PXEBC_PRIVATE_DATA
*Private
999 PXEBC_OFFER_TYPE OfferType
;
1001 Private
->SelectIndex
= 0;
1003 if (Private
->IsOfferSorted
) {
1005 // Select offer by default policy.
1007 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
1009 // 1. DhcpPxe10 offer
1011 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
1013 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
1015 // 2. DhcpWfm11a offer
1017 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1019 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1020 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1022 // 3. DhcpOnly offer and ProxyPxe10 offer.
1024 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1025 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1027 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1028 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1030 // 4. DhcpOnly offer and ProxyWfm11a offer.
1032 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1033 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1035 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1037 // 5. DhcpBinl offer.
1039 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1041 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1042 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1044 // 6. DhcpOnly offer and ProxyBinl offer.
1046 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1047 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1051 // 7. DhcpOnly offer with bootfilename.
1053 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1054 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1055 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1056 Private
->SelectIndex
= OfferIndex
+ 1;
1063 // Select offer by received order.
1065 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1067 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1069 if (IS_PROXY_OFFER (OfferType
)) {
1071 // Skip proxy offers
1076 if (!Private
->IsProxyRecved
&&
1077 OfferType
== PxeOfferTypeDhcpOnly
&&
1078 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1080 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1085 Private
->SelectIndex
= Index
+ 1;
1093 Handle the DHCPv6 offer packet.
1095 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1097 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1098 @retval EFI_NO_RESPONSE No response to the following request packet.
1102 PxeBcHandleDhcp6Offer (
1103 IN PXEBC_PRIVATE_DATA
*Private
1106 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1108 PXEBC_OFFER_TYPE OfferType
;
1113 ASSERT (Private
->SelectIndex
> 0);
1114 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1115 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1116 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1117 Status
= EFI_SUCCESS
;
1119 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1121 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1123 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1124 Status
= EFI_NO_RESPONSE
;
1126 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1128 if (Private
->IsProxyRecved
) {
1130 // DhcpOnly offer is selected, so need try to request bootfilename.
1133 if (Private
->IsOfferSorted
) {
1135 // The proxy offer should be determined if select by default policy.
1136 // IsOfferSorted means all offers are labeled by OfferIndex.
1138 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1140 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1142 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1144 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1146 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1147 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1151 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1152 Status
= EFI_NO_RESPONSE
;
1156 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1158 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1162 // The proxy offer should not be determined if select by received order.
1164 Status
= EFI_NO_RESPONSE
;
1166 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1168 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1170 if (!IS_PROXY_OFFER (OfferType
)) {
1172 // Skip non proxy dhcp offers.
1177 if (OfferType
== PxeOfferTypeProxyBinl
) {
1179 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1181 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1186 Private
->SelectProxyType
= OfferType
;
1188 Status
= EFI_SUCCESS
;
1193 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1195 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1197 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1201 // Othewise, the bootfilename must be included in DhcpOnly offer.
1203 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1207 if (!EFI_ERROR (Status
)) {
1209 // All PXE boot information is ready by now.
1211 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1212 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1220 Unregister the address by Ip6Config protocol.
1222 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1226 PxeBcUnregisterIp6Address (
1227 IN PXEBC_PRIVATE_DATA
*Private
1230 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1232 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1233 // Keep the point and there is no enough requirements to do recovery.
1240 Register the ready address by Ip6Config protocol.
1242 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1243 @param[in] Address The pointer to the ready address.
1245 @retval EFI_SUCCESS Registered the address succesfully.
1246 @retval Others Failed to register the address.
1250 PxeBcRegisterIp6Address (
1251 IN PXEBC_PRIVATE_DATA
*Private
,
1252 IN EFI_IPv6_ADDRESS
*Address
1255 EFI_IP6_PROTOCOL
*Ip6
;
1256 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1257 EFI_IP6_CONFIG_POLICY Policy
;
1258 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1260 EFI_EVENT TimeOutEvt
;
1261 EFI_EVENT MappedEvt
;
1263 UINT64 DadTriggerTime
;
1264 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
1266 Status
= EFI_SUCCESS
;
1269 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1270 Ip6Cfg
= Private
->Ip6Cfg
;
1273 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1274 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1277 // Get and store the current policy of IP6 driver.
1279 Status
= Ip6Cfg
->GetData (
1281 Ip6ConfigDataTypePolicy
,
1285 if (EFI_ERROR (Status
)) {
1290 // There is no channel between IP6 and PXE driver about address setting,
1291 // so it has to set the new address by Ip6ConfigProtocol manually.
1293 Policy
= Ip6ConfigPolicyManual
;
1294 Status
= Ip6Cfg
->SetData (
1296 Ip6ConfigDataTypePolicy
,
1297 sizeof(EFI_IP6_CONFIG_POLICY
),
1300 if (EFI_ERROR (Status
)) {
1302 // There is no need to recover later.
1304 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1309 // Get Duplicate Address Detection Transmits count.
1311 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
1312 Status
= Ip6Cfg
->GetData (
1314 Ip6ConfigDataTypeDupAddrDetectTransmits
,
1318 if (EFI_ERROR (Status
)) {
1323 // Create a timer as setting address timeout event since DAD in IP6 driver.
1325 Status
= gBS
->CreateEvent (
1332 if (EFI_ERROR (Status
)) {
1337 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1339 Status
= gBS
->CreateEvent (
1343 &Private
->IsAddressOk
,
1346 if (EFI_ERROR (Status
)) {
1350 Status
= Ip6Cfg
->RegisterDataNotify (
1352 Ip6ConfigDataTypeManualAddress
,
1355 if (EFI_ERROR(Status
)) {
1359 Status
= Ip6Cfg
->SetData (
1361 Ip6ConfigDataTypeManualAddress
,
1362 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1365 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1370 // Start the 5 secondes timer to wait for setting address.
1372 Status
= EFI_NO_MAPPING
;
1373 DadTriggerTime
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
1374 gBS
->SetTimer (TimeOutEvt
, TimerRelative
, DadTriggerTime
);
1376 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1378 if (Private
->IsAddressOk
) {
1379 Status
= EFI_SUCCESS
;
1385 if (MappedEvt
!= NULL
) {
1386 Ip6Cfg
->UnregisterDataNotify (
1388 Ip6ConfigDataTypeManualAddress
,
1391 gBS
->CloseEvent (MappedEvt
);
1393 if (TimeOutEvt
!= NULL
) {
1394 gBS
->CloseEvent (TimeOutEvt
);
1401 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1402 to intercept events that occurred in the configuration process.
1404 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1405 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1406 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1407 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1409 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1410 @param[out] NewPacket The packet that is used to replace the Packet above.
1412 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1413 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1414 driver will continue to wait for more packets.
1415 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1420 PxeBcDhcp6CallBack (
1421 IN EFI_DHCP6_PROTOCOL
*This
,
1423 IN EFI_DHCP6_STATE CurrentState
,
1424 IN EFI_DHCP6_EVENT Dhcp6Event
,
1425 IN EFI_DHCP6_PACKET
*Packet
,
1426 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1429 PXEBC_PRIVATE_DATA
*Private
;
1430 EFI_PXE_BASE_CODE_MODE
*Mode
;
1431 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1432 EFI_DHCP6_PACKET
*SelectAd
;
1436 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1437 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1438 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1439 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1440 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1444 ASSERT (Packet
!= NULL
);
1446 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1447 Mode
= Private
->PxeBc
.Mode
;
1448 Callback
= Private
->PxeBcCallback
;
1451 // Callback to user when any traffic ocurred if has.
1453 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1454 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1455 Status
= Callback
->Callback (
1460 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1462 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1467 Status
= EFI_SUCCESS
;
1469 switch (Dhcp6Event
) {
1471 case Dhcp6SendSolicit
:
1473 // Record the first Solicate msg time
1475 if (Private
->SolicitTimes
== 0) {
1476 CalcElapsedTime (Private
);
1477 Private
->SolicitTimes
++;
1480 // Cache the dhcp discover packet to mode data directly.
1482 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1485 case Dhcp6RcvdAdvertise
:
1486 Status
= EFI_NOT_READY
;
1487 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1489 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1490 // the OfferIndex and OfferCount.
1492 PxeBcCacheDhcp6Offer (Private
, Packet
);
1496 case Dhcp6SendRequest
:
1498 // Store the request packet as seed packet for discover.
1500 if (Private
->Dhcp6Request
!= NULL
) {
1501 FreePool (Private
->Dhcp6Request
);
1503 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1504 if (Private
->Dhcp6Request
!= NULL
) {
1505 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1509 case Dhcp6SelectAdvertise
:
1511 // Select offer by the default policy or by order, and record the SelectIndex
1512 // and SelectProxyType.
1514 PxeBcSelectDhcp6Offer (Private
);
1516 if (Private
->SelectIndex
== 0) {
1517 Status
= EFI_ABORTED
;
1519 ASSERT (NewPacket
!= NULL
);
1520 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1521 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1522 ASSERT (*NewPacket
!= NULL
);
1523 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1527 case Dhcp6RcvdReply
:
1529 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1530 // without verification.
1532 ASSERT (Private
->SelectIndex
!= 0);
1533 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1545 Build and send out the request packet for the bootfile, and parse the reply.
1547 @param[in] Private The pointer to PxeBc private data.
1548 @param[in] Type PxeBc option boot item type.
1549 @param[in] Layer The pointer to option boot item layer.
1550 @param[in] UseBis Use BIS or not.
1551 @param[in] DestIp The pointer to the server address.
1553 @retval EFI_SUCCESS Successfully discovered the boot file.
1554 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1555 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1556 @retval Others Failed to discover the boot file.
1560 PxeBcDhcp6Discover (
1561 IN PXEBC_PRIVATE_DATA
*Private
,
1565 IN EFI_IP_ADDRESS
*DestIp
1568 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
1569 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
1570 EFI_PXE_BASE_CODE_MODE
*Mode
;
1571 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1572 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
1574 EFI_DHCP6_PACKET
*Request
;
1576 EFI_DHCP6_PACKET
*Reply
;
1586 PxeBc
= &Private
->PxeBc
;
1588 Request
= Private
->Dhcp6Request
;
1589 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
1590 DestPort
= PXEBC_BS_DISCOVER_PORT
;
1593 if (!UseBis
&& Layer
!= NULL
) {
1594 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1597 if (Request
== NULL
) {
1598 return EFI_DEVICE_ERROR
;
1601 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
1602 if (Discover
== NULL
) {
1603 return EFI_OUT_OF_RESOURCES
;
1607 // Build the discover packet by the cached request packet before.
1609 Xid
= NET_RANDOM (NetRandomInitSeed ());
1610 Discover
->TransactionId
= HTONL (Xid
);
1611 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
1612 RequestOpt
= Request
->Dhcp6
.Option
;
1613 DiscoverOpt
= Discover
->DhcpOptions
;
1614 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
1615 RequestLen
= DiscoverLen
;
1617 while (RequestLen
< Request
->Length
) {
1618 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
1619 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
1620 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
1621 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
1623 // Copy all the options except IA option.
1625 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
1626 DiscoverOpt
+= (OpLen
+ 4);
1627 DiscoverLen
+= (OpLen
+ 4);
1629 RequestOpt
+= (OpLen
+ 4);
1630 RequestLen
+= (OpLen
+ 4);
1633 Status
= PxeBc
->UdpWrite (
1639 &Private
->StationIp
,
1646 if (EFI_ERROR (Status
)) {
1651 // Cache the right PXE reply packet here, set valid flag later.
1652 // Especially for PXE discover packet, store it into mode data here.
1654 if (Private
->IsDoDiscover
) {
1655 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
1656 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
1658 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1660 ReadSize
= (UINTN
) Reply
->Size
;
1663 // Start Udp6Read instance
1665 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
1666 if (EFI_ERROR (Status
)) {
1670 Status
= PxeBc
->UdpRead (
1673 &Private
->StationIp
,
1680 (VOID
*) &Reply
->Dhcp6
1683 // Stop Udp6Read instance
1685 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1686 if (EFI_ERROR (Status
)) {
1695 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1697 @param[in] Private The pointer to PxeBc private data.
1698 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1700 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1701 @retval Others Failed to finish the S.A.R.R. process.
1706 IN PXEBC_PRIVATE_DATA
*Private
,
1707 IN EFI_DHCP6_PROTOCOL
*Dhcp6
1710 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1711 EFI_DHCP6_CONFIG_DATA Config
;
1712 EFI_DHCP6_MODE_DATA Mode
;
1713 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
1714 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
1715 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
1718 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1719 EFI_STATUS TimerStatus
;
1721 UINT64 GetMappingTimeOut
;
1723 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
1725 Status
= EFI_SUCCESS
;
1726 PxeMode
= Private
->PxeBc
.Mode
;
1727 Ip6Cfg
= Private
->Ip6Cfg
;
1731 // Build option list for the request packet.
1733 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
1734 ASSERT (OptCount
> 0);
1736 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
1737 if (Retransmit
== NULL
) {
1738 return EFI_OUT_OF_RESOURCES
;
1741 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
1742 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1744 Config
.OptionCount
= OptCount
;
1745 Config
.OptionList
= OptList
;
1746 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
1747 Config
.CallbackContext
= Private
;
1748 Config
.IaInfoEvent
= NULL
;
1749 Config
.RapidCommit
= FALSE
;
1750 Config
.ReconfigureAccept
= FALSE
;
1751 Config
.IaDescriptor
.IaId
= 1;
1752 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
1753 Config
.SolicitRetransmission
= Retransmit
;
1754 Retransmit
->Irt
= 4;
1755 Retransmit
->Mrc
= 4;
1756 Retransmit
->Mrt
= 32;
1757 Retransmit
->Mrd
= 60;
1760 // Configure the DHCPv6 instance for PXE boot.
1762 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
1763 FreePool (Retransmit
);
1764 if (EFI_ERROR (Status
)) {
1769 // Initialize the record fields for DHCPv6 offer in private data.
1771 Private
->IsProxyRecved
= FALSE
;
1772 Private
->OfferNum
= 0;
1773 Private
->SelectIndex
= 0;
1774 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1775 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1779 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1781 Status
= Dhcp6
->Start (Dhcp6
);
1782 if (Status
== EFI_NO_MAPPING
) {
1784 // IP6 Linklocal address is not available for use, so stop current Dhcp process
1785 // and wait for duplicate address detection to finish.
1787 Dhcp6
->Stop (Dhcp6
);
1790 // Get Duplicate Address Detection Transmits count.
1792 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
1793 Status
= Ip6Cfg
->GetData (
1795 Ip6ConfigDataTypeDupAddrDetectTransmits
,
1799 if (EFI_ERROR (Status
)) {
1800 Dhcp6
->Configure (Dhcp6
, NULL
);
1804 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
1805 if (EFI_ERROR (Status
)) {
1806 Dhcp6
->Configure (Dhcp6
, NULL
);
1810 GetMappingTimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ PXEBC_DAD_ADDITIONAL_DELAY
;
1811 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
1812 if (EFI_ERROR (Status
)) {
1813 gBS
->CloseEvent (Timer
);
1814 Dhcp6
->Configure (Dhcp6
, NULL
);
1820 TimerStatus
= gBS
->CheckEvent (Timer
);
1821 if (!EFI_ERROR (TimerStatus
)) {
1822 Status
= Dhcp6
->Start (Dhcp6
);
1824 } while (TimerStatus
== EFI_NOT_READY
);
1826 gBS
->CloseEvent (Timer
);
1828 if (EFI_ERROR (Status
)) {
1829 if (Status
== EFI_ICMP_ERROR
) {
1830 PxeMode
->IcmpErrorReceived
= TRUE
;
1832 Dhcp6
->Configure (Dhcp6
, NULL
);
1837 // Get the acquired IPv6 address and store them.
1839 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1840 if (EFI_ERROR (Status
)) {
1841 Dhcp6
->Stop (Dhcp6
);
1845 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1846 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1847 CopyMem (&PxeMode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1849 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1850 if (EFI_ERROR (Status
)) {
1851 Dhcp6
->Stop (Dhcp6
);
1855 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, NULL
);
1856 if (EFI_ERROR (Status
)) {
1857 PxeBcUnregisterIp6Address (Private
);
1858 Dhcp6
->Stop (Dhcp6
);
1863 // Check the selected offer whether BINL retry is needed.
1865 Status
= PxeBcHandleDhcp6Offer (Private
);
1866 if (EFI_ERROR (Status
)) {
1867 PxeBcUnregisterIp6Address (Private
);
1868 Dhcp6
->Stop (Dhcp6
);
1872 AsciiPrint ("\n Station IP address is ");
1874 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);