2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2011, 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"
20 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
22 @param[in] Buffer The pointer to the option buffer.
23 @param[in] Length Length of the option buffer.
24 @param[in] OptTag The required option tag.
26 @retval NULL Failed to parse the required option.
27 @retval Others The postion of the required option in buffer.
30 EFI_DHCP6_PACKET_OPTION
*
31 PxeBcParseDhcp6Options (
37 EFI_DHCP6_PACKET_OPTION
*Option
;
40 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
44 // OpLen and OpCode here are both stored in network order.
46 while (Offset
< Length
) {
48 if (NTOHS (Option
->OpCode
) == OptTag
) {
53 Offset
+= (NTOHS(Option
->OpLen
) + 4);
54 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
62 Build the options buffer for the DHCPv6 request packet.
64 @param[in] Private The pointer to PxeBc private data.
65 @param[out] OptList The pointer to the option pointer array.
66 @param[in] Buffer The pointer to the buffer to contain the option list.
68 @return Index The count of the built-in options.
72 PxeBcBuildDhcp6Options (
73 IN PXEBC_PRIVATE_DATA
*Private
,
74 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
78 PXEBC_DHCP6_OPTION_ENTRY OptEnt
;
83 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
86 // Append client option request option
88 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ORO
);
89 OptList
[Index
]->OpLen
= HTONS (4);
90 OptEnt
.Oro
= (PXEBC_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
91 OptEnt
.Oro
->OpCode
[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL
);
92 OptEnt
.Oro
->OpCode
[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
);
94 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
97 // Append client network device interface option
99 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_UNDI
);
100 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
101 OptEnt
.Undi
= (PXEBC_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
103 if (Private
->Nii
!= NULL
) {
104 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
105 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
106 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
108 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
109 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
110 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
114 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
117 // Append client system architecture option
119 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_ARCH
);
120 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_ARCH
));
121 OptEnt
.Arch
= (PXEBC_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
122 Value
= HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
);
123 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
125 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
128 // Append vendor class option to store the PXE class identifier.
130 OptList
[Index
]->OpCode
= HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS
);
131 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS
));
132 OptEnt
.VendorClass
= (PXEBC_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
133 OptEnt
.VendorClass
->Vendor
= HTONL (PXEBC_DHCP6_ENTERPRISE_NUM
);
134 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (PXEBC_CLASS_ID
));
136 &OptEnt
.VendorClass
->ClassId
,
137 DEFAULT_CLASS_ID_DATA
,
138 sizeof (PXEBC_CLASS_ID
)
140 PxeBcUintnToAscDecWithFormat (
141 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE
,
142 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
143 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
146 if (Private
->Nii
!= NULL
) {
148 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
149 Private
->Nii
->StringId
,
150 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
152 PxeBcUintnToAscDecWithFormat (
153 Private
->Nii
->MajorVer
,
154 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
155 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
157 PxeBcUintnToAscDecWithFormat (
158 Private
->Nii
->MinorVer
,
159 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
160 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
171 Cache the DHCPv6 packet.
173 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
174 @param[in] Src The pointer to the DHCPv6 packet to be cached.
178 PxeBcCacheDhcp6Packet (
179 IN EFI_DHCP6_PACKET
*Dst
,
180 IN EFI_DHCP6_PACKET
*Src
183 ASSERT (Dst
->Size
>= Src
->Length
);
185 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
186 Dst
->Length
= Src
->Length
;
191 Free all the nodes in the list for boot file.
193 @param[in] Head The pointer to the head of list.
197 PxeBcFreeBootFileOption (
202 LIST_ENTRY
*NextEntry
;
203 PXEBC_DHCP6_OPTION_NODE
*Node
;
205 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, Head
) {
206 Node
= NET_LIST_USER_STRUCT (Entry
, PXEBC_DHCP6_OPTION_NODE
, Link
);
207 RemoveEntryList (Entry
);
214 Parse the Boot File URL option.
216 @param[out] FileName The pointer to the boot file name.
217 @param[in, out] SrvAddr The pointer to the boot server address.
218 @param[in] BootFile The pointer to the boot file URL option data.
219 @param[in] Length The length of the boot file URL option data.
221 @retval EFI_ABORTED User cancel operation.
222 @retval EFI_SUCCESS Selected the boot menu successfully.
223 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
227 PxeBcExtractBootFileUrl (
228 OUT UINT8
**FileName
,
229 IN OUT EFI_IPv6_ADDRESS
*SrvAddr
,
235 UINT8
*BootFileNamePtr
;
237 UINT16 BootFileNameLen
;
240 CHAR8
*ServerAddressOption
;
241 CHAR8
*ServerAddress
;
245 // The format of the Boot File URL option is:
248 // 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
249 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
250 // | OPT_BOOTFILE_URL | option-len |
251 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
253 // . bootfile-url (variable length) .
255 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
259 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
260 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
261 // As an example where the BOOTFILE_NAME is the EFI loader and
262 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
264 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
266 if (Length
<= PrefixLen
||
267 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
268 return EFI_NOT_FOUND
;
271 BootFile
= BootFile
+ PrefixLen
;
272 Length
= (UINT16
) (Length
- PrefixLen
);
274 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
275 if (TmpStr
== NULL
) {
276 return EFI_OUT_OF_RESOURCES
;
279 CopyMem (TmpStr
, BootFile
, Length
);
280 TmpStr
[Length
] = '\0';
283 // Get the part of SERVER_ADDRESS string.
285 ServerAddressOption
= TmpStr
;
286 if (*ServerAddressOption
!= PXEBC_ADDR_START_DELIMITER
) {
288 return EFI_INVALID_PARAMETER
;
291 ServerAddressOption
++;
292 ServerAddress
= ServerAddressOption
;
293 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
297 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
299 return EFI_INVALID_PARAMETER
;
302 *ServerAddress
= '\0';
305 // Convert the string of server address to Ipv6 address format and store it.
307 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
308 if (EFI_ERROR (Status
)) {
314 // Get the part of BOOTFILE_NAME string.
316 BootFileNamePtr
= (UINT8
*)((UINTN
)ServerAddress
+ 1);
317 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
319 return EFI_INVALID_PARAMETER
;
323 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
324 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
326 // Extract boot file name from URL.
328 BootFileName
= (UINT8
*) AllocateZeroPool (BootFileNameLen
);
329 if (BootFileName
== NULL
) {
331 return EFI_OUT_OF_RESOURCES
;
333 *FileName
= BootFileName
;
336 // Decode percent-encoding in boot file name.
338 while (*BootFileNamePtr
!= '\0') {
339 if (*BootFileNamePtr
== '%') {
340 TmpChar
= *(BootFileNamePtr
+ 3);
341 *(BootFileNamePtr
+ 3) = '\0';
342 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
344 *(BootFileNamePtr
+ 3) = TmpChar
;
345 BootFileNamePtr
+= 3;
347 *BootFileName
= *BootFileNamePtr
;
352 *BootFileName
= '\0';
362 Parse the Boot File Parameter option.
364 @param[in] BootFilePara The pointer to boot file parameter option data.
365 @param[out] BootFileSize The pointer to the parsed boot file size.
367 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
368 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
372 PxeBcExtractBootFileParam (
373 IN CHAR8
*BootFilePara
,
374 OUT UINT16
*BootFileSize
382 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
383 Length
= NTOHS (Length
);
386 // The BootFile Size should be 1~5 byte ASCII strings
388 if (Length
< 1 || Length
> 5) {
389 return EFI_NOT_FOUND
;
393 // Extract the value of BootFile Size.
395 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
397 for (Index
= 0; Index
< Length
; Index
++) {
398 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
399 return EFI_NOT_FOUND
;
402 Size
= (Size
+ Digit
) * 10;
406 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
407 return EFI_NOT_FOUND
;
410 *BootFileSize
= (UINT16
) Size
;
416 Parse the cached DHCPv6 packet, including all the options.
418 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
420 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
421 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
425 PxeBcParseDhcp6Packet (
426 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
429 EFI_DHCP6_PACKET
*Offer
;
430 EFI_DHCP6_PACKET_OPTION
**Options
;
431 EFI_DHCP6_PACKET_OPTION
*Option
;
432 PXEBC_OFFER_TYPE OfferType
;
433 BOOLEAN IsProxyOffer
;
437 UINT32 EnterpriseNum
;
441 Offer
= &Cache6
->Packet
.Offer
;
442 Options
= Cache6
->OptList
;
444 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
446 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
448 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
451 // OpLen and OpCode here are both stored in network order, since they are from original packet.
453 while (Offset
< Length
) {
455 if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_IA_NA
) {
456 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
457 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_URL
) {
459 // The server sends this option to inform the client about an URL to a boot file.
461 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
462 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
) {
463 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
464 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_VENDOR_CLASS
) {
465 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
468 Offset
+= (NTOHS (Option
->OpLen
) + 4);
469 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
473 // The offer with assigned client address is a proxy offer.
474 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
476 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
477 if (Option
!= NULL
) {
478 Option
= PxeBcParseDhcp6Options (
480 NTOHS (Option
->OpLen
),
481 PXEBC_DHCP6_OPT_STATUS_CODE
483 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
484 IsProxyOffer
= FALSE
;
489 // The offer with "PXEClient" is a pxe offer.
491 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
492 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
494 if (Option
!= NULL
&&
495 NTOHS(Option
->OpLen
) >= 13 &&
496 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
497 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
502 // Determine offer type of the dhcp6 packet.
506 // It's a binl offer only with PXEClient.
508 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
511 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
513 OfferType
= PxeOfferTypeDhcpOnly
;
516 Cache6
->OfferType
= OfferType
;
523 Cache the DHCPv6 ack packet, and parse it on demand.
525 @param[in] Private The pointer to PxeBc private data.
526 @param[in] Ack The pointer to the DHCPv6 ack packet.
527 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
532 IN PXEBC_PRIVATE_DATA
*Private
,
533 IN EFI_DHCP6_PACKET
*Ack
,
537 EFI_PXE_BASE_CODE_MODE
*Mode
;
539 Mode
= Private
->PxeBc
.Mode
;
541 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
545 // Parse the ack packet and store it into mode data if needed.
547 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
548 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
549 Mode
->DhcpAckReceived
= TRUE
;
555 Cache the DHCPv6 proxy offer packet according to the received order.
557 @param[in] Private The pointer to PxeBc private data.
558 @param[in] OfferIndex The received order of offer packets.
562 PxeBcCopyDhcp6Proxy (
563 IN PXEBC_PRIVATE_DATA
*Private
,
567 EFI_PXE_BASE_CODE_MODE
*Mode
;
568 EFI_DHCP6_PACKET
*Offer
;
570 ASSERT (OfferIndex
< Private
->OfferNum
);
571 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
573 Mode
= Private
->PxeBc
.Mode
;
574 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
577 // Cache the proxy offer packet and parse it.
579 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
580 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
583 // Store this packet into mode data.
585 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
586 Mode
->ProxyOfferReceived
= TRUE
;
590 Seek the address of the first byte of the option header.
592 @param[in] Buf The pointer to the buffer.
593 @param[in] SeekLen The length to seek.
594 @param[in] OptType The option type.
596 @retval NULL If it failed to seek the option.
597 @retval others The position to the option.
601 PxeBcDhcp6SeekOption (
615 while (Cursor
< Buf
+ SeekLen
) {
616 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
617 if (OpCode
== HTONS (OptType
)) {
621 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
622 Cursor
+= (DataLen
+ 4);
630 Build and send out the request packet for the bootfile, and parse the reply.
632 @param[in] Private The pointer to PxeBc private data.
633 @param[in] Index PxeBc option boot item type.
635 @retval EFI_SUCCESS Successfully discovered the boot file.
636 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
637 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
638 @retval Others Failed to discover the boot file.
642 PxeBcRequestBootService (
643 IN PXEBC_PRIVATE_DATA
*Private
,
647 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
648 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
649 EFI_PXE_BASE_CODE_MODE
*Mode
;
650 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
651 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
653 EFI_DHCP6_PACKET
*Request
;
655 EFI_DHCP6_PACKET
*Reply
;
663 EFI_DHCP6_PACKET
*ProxyOffer
;
666 PxeBc
= &Private
->PxeBc
;
668 Request
= Private
->Dhcp6Request
;
669 ProxyOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
670 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
671 DestPort
= PXEBC_BS_DISCOVER_PORT
;
674 if (Request
== NULL
) {
675 return EFI_DEVICE_ERROR
;
678 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
679 if (Discover
== NULL
) {
680 return EFI_OUT_OF_RESOURCES
;
684 // Build the request packet by the cached request packet before.
686 Discover
->TransactionId
= ProxyOffer
->Dhcp6
.Header
.TransactionId
;
687 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
688 RequestOpt
= Request
->Dhcp6
.Option
;
689 DiscoverOpt
= Discover
->DhcpOptions
;
690 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
691 RequestLen
= DiscoverLen
;
694 // Find Server ID Option from ProxyOffer.
696 Option
= PxeBcDhcp6SeekOption (
697 ProxyOffer
->Dhcp6
.Option
,
698 ProxyOffer
->Length
- 4,
699 PXEBC_DHCP6_OPT_SERVER_ID
701 if (Option
== NULL
) {
702 return EFI_NOT_FOUND
;
706 // Add Server ID Option.
708 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
709 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
710 DiscoverOpt
+= (OpLen
+ 4);
711 DiscoverLen
+= (OpLen
+ 4);
713 while (RequestLen
< Request
->Length
) {
714 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
715 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
716 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
717 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
718 OpCode
!= PXEBC_DHCP6_OPT_SERVER_ID
721 // Copy all the options except IA option and Server ID
723 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
724 DiscoverOpt
+= (OpLen
+ 4);
725 DiscoverLen
+= (OpLen
+ 4);
727 RequestOpt
+= (OpLen
+ 4);
728 RequestLen
+= (OpLen
+ 4);
732 // Update Elapsed option in the package
734 Option
= PxeBcDhcp6SeekOption (
735 Discover
->DhcpOptions
,
736 (UINT32
)(RequestLen
- 4),
737 PXEBC_DHCP6_OPT_ELAPSED_TIME
739 if (Option
!= NULL
) {
740 CalcElapsedTime (Private
);
741 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
744 Status
= PxeBc
->UdpWrite (
758 if (EFI_ERROR (Status
)) {
763 // Cache the right PXE reply packet here, set valid flag later.
764 // Especially for PXE discover packet, store it into mode data here.
766 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
767 ReadSize
= (UINTN
) Reply
->Size
;
770 // Start Udp6Read instance
772 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
773 if (EFI_ERROR (Status
)) {
777 Status
= PxeBc
->UdpRead (
787 (VOID
*) &Reply
->Dhcp6
790 // Stop Udp6Read instance
792 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
794 if (EFI_ERROR (Status
)) {
801 Reply
->Length
= (UINT32
) ReadSize
;
808 Retry to request bootfile name by the BINL offer.
810 @param[in] Private The pointer to PxeBc private data.
811 @param[in] Index The received order of offer packets.
813 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
814 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
818 PxeBcRetryDhcp6Binl (
819 IN PXEBC_PRIVATE_DATA
*Private
,
823 EFI_PXE_BASE_CODE_MODE
*Mode
;
824 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
825 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
828 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
829 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
830 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
832 Mode
= Private
->PxeBc
.Mode
;
833 Private
->IsDoDiscover
= FALSE
;
834 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
836 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
838 // Parse out the next server address from the last offer, and store it
840 Status
= PxeBcExtractBootFileUrl (
841 &Private
->BootFileName
,
842 &Private
->ServerIp
.v6
,
843 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
844 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
846 if (EFI_ERROR (Status
)) {
851 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
853 Status
= PxeBcRequestBootService (Private
, Index
);
855 if (EFI_ERROR (Status
)) {
859 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
860 Status
= PxeBcParseDhcp6Packet (Cache6
);
861 if (EFI_ERROR (Status
)) {
865 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
866 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
867 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
869 // This BINL ack doesn't have discovery option set or multicast option set
870 // or bootfile name specified.
872 return EFI_DEVICE_ERROR
;
875 Mode
->ProxyOfferReceived
= TRUE
;
877 &Mode
->ProxyOffer
.Dhcpv6
,
878 &Cache6
->Packet
.Offer
.Dhcp6
,
879 Cache6
->Packet
.Offer
.Length
887 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
889 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
890 @param[in] RcvdOffer The pointer to the received offer packet.
894 PxeBcCacheDhcp6Offer (
895 IN PXEBC_PRIVATE_DATA
*Private
,
896 IN EFI_DHCP6_PACKET
*RcvdOffer
899 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
900 EFI_DHCP6_PACKET
*Offer
;
901 PXEBC_OFFER_TYPE OfferType
;
903 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
904 Offer
= &Cache6
->Packet
.Offer
;
907 // Cache the content of DHCPv6 packet firstly.
909 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
912 // Validate the DHCPv6 packet, and parse the options and offer type.
914 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
919 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
921 OfferType
= Cache6
->OfferType
;
922 ASSERT (OfferType
< PxeOfferTypeMax
);
923 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
925 if (IS_PROXY_OFFER (OfferType
)) {
927 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
929 Private
->IsProxyRecved
= TRUE
;
931 if (OfferType
== PxeOfferTypeProxyBinl
) {
933 // Cache all proxy BINL offers.
935 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
936 Private
->OfferCount
[OfferType
]++;
937 } else if (Private
->OfferCount
[OfferType
] > 0) {
939 // Only cache the first PXE10/WFM11a offer, and discard the others.
941 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
942 Private
->OfferCount
[OfferType
] = 1;
948 // It's a DHCPv6 offer with yiaddr, and cache them all.
950 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
951 Private
->OfferCount
[OfferType
]++;
959 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
961 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
965 PxeBcSelectDhcp6Offer (
966 IN PXEBC_PRIVATE_DATA
*Private
971 PXEBC_OFFER_TYPE OfferType
;
973 Private
->SelectIndex
= 0;
975 if (Private
->IsOfferSorted
) {
977 // Select offer by default policy.
979 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
981 // 1. DhcpPxe10 offer
983 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
985 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
987 // 2. DhcpWfm11a offer
989 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
991 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
992 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
994 // 3. DhcpOnly offer and ProxyPxe10 offer.
996 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
997 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
999 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1000 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1002 // 4. DhcpOnly offer and ProxyWfm11a offer.
1004 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1005 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1007 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1009 // 5. DhcpBinl offer.
1011 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1013 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1014 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1016 // 6. DhcpOnly offer and ProxyBinl offer.
1018 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1019 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1023 // 7. DhcpOnly offer with bootfilename.
1025 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1026 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1027 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1028 Private
->SelectIndex
= OfferIndex
+ 1;
1035 // Select offer by received order.
1037 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1039 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1041 if (IS_PROXY_OFFER (OfferType
)) {
1043 // Skip proxy offers
1048 if (!Private
->IsProxyRecved
&&
1049 OfferType
== PxeOfferTypeDhcpOnly
&&
1050 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1052 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1057 Private
->SelectIndex
= Index
+ 1;
1065 Handle the DHCPv6 offer packet.
1067 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1069 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1070 @retval EFI_NO_RESPONSE No response to the following request packet.
1074 PxeBcHandleDhcp6Offer (
1075 IN PXEBC_PRIVATE_DATA
*Private
1078 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1080 PXEBC_OFFER_TYPE OfferType
;
1085 ASSERT (Private
->SelectIndex
> 0);
1086 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1087 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1088 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1089 Status
= EFI_SUCCESS
;
1091 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1093 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1095 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1096 Status
= EFI_NO_RESPONSE
;
1098 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1100 if (Private
->IsProxyRecved
) {
1102 // DhcpOnly offer is selected, so need try to request bootfilename.
1105 if (Private
->IsOfferSorted
) {
1107 // The proxy offer should be determined if select by default policy.
1108 // IsOfferSorted means all offers are labeled by OfferIndex.
1110 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1112 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1114 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1116 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1118 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1119 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1123 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1124 Status
= EFI_NO_RESPONSE
;
1128 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1130 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1134 // The proxy offer should not be determined if select by received order.
1136 Status
= EFI_NO_RESPONSE
;
1138 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1140 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1142 if (!IS_PROXY_OFFER (OfferType
)) {
1144 // Skip non proxy dhcp offers.
1149 if (OfferType
== PxeOfferTypeProxyBinl
) {
1151 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1153 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1158 Private
->SelectProxyType
= OfferType
;
1160 Status
= EFI_SUCCESS
;
1165 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1167 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1169 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1173 // Othewise, the bootfilename must be included in DhcpOnly offer.
1175 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1179 if (!EFI_ERROR (Status
)) {
1181 // All PXE boot information is ready by now.
1183 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1184 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1192 Unregister the address by Ip6Config protocol.
1194 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1198 PxeBcUnregisterIp6Address (
1199 IN PXEBC_PRIVATE_DATA
*Private
1202 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1204 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1205 // Keep the point and there is no enough requirements to do recovery.
1212 Register the ready address by Ip6Config protocol.
1214 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1215 @param[in] Address The pointer to the ready address.
1217 @retval EFI_SUCCESS Registered the address succesfully.
1218 @retval Others Failed to register the address.
1222 PxeBcRegisterIp6Address (
1223 IN PXEBC_PRIVATE_DATA
*Private
,
1224 IN EFI_IPv6_ADDRESS
*Address
1227 EFI_IP6_PROTOCOL
*Ip6
;
1228 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1229 EFI_IP6_CONFIG_POLICY Policy
;
1230 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1232 EFI_EVENT TimeOutEvt
;
1233 EFI_EVENT MappedEvt
;
1236 Status
= EFI_SUCCESS
;
1239 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1240 Ip6Cfg
= Private
->Ip6Cfg
;
1243 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1244 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1247 // Get and store the current policy of IP6 driver.
1249 Status
= Ip6Cfg
->GetData (
1251 Ip6ConfigDataTypePolicy
,
1255 if (EFI_ERROR (Status
)) {
1260 // There is no channel between IP6 and PXE driver about address setting,
1261 // so it has to set the new address by Ip6ConfigProtocol manually.
1263 Policy
= Ip6ConfigPolicyManual
;
1264 Status
= Ip6Cfg
->SetData (
1266 Ip6ConfigDataTypePolicy
,
1267 sizeof(EFI_IP6_CONFIG_POLICY
),
1270 if (EFI_ERROR (Status
)) {
1272 // There is no need to recover later.
1274 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1279 // Create a timer as setting address timeout event since DAD in IP6 driver.
1281 Status
= gBS
->CreateEvent (
1288 if (EFI_ERROR (Status
)) {
1293 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1295 Status
= gBS
->CreateEvent (
1299 &Private
->IsAddressOk
,
1302 if (EFI_ERROR (Status
)) {
1306 Status
= Ip6Cfg
->RegisterDataNotify (
1308 Ip6ConfigDataTypeManualAddress
,
1311 if (EFI_ERROR(Status
)) {
1315 Status
= Ip6Cfg
->SetData (
1317 Ip6ConfigDataTypeManualAddress
,
1318 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1321 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1326 // Start the 5 secondes timer to wait for setting address.
1328 Status
= EFI_NO_MAPPING
;
1329 gBS
->SetTimer (TimeOutEvt
, TimerRelative
, PXEBC_DHCP6_MAPPING_TIMEOUT
);
1331 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1333 if (Private
->IsAddressOk
) {
1334 Status
= EFI_SUCCESS
;
1340 if (MappedEvt
!= NULL
) {
1341 Ip6Cfg
->UnregisterDataNotify (
1343 Ip6ConfigDataTypeManualAddress
,
1346 gBS
->CloseEvent (MappedEvt
);
1348 if (TimeOutEvt
!= NULL
) {
1349 gBS
->CloseEvent (TimeOutEvt
);
1356 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1357 to intercept events that occurred in the configuration process.
1359 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1360 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1361 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1362 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1364 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1365 @param[out] NewPacket The packet that is used to replace the Packet above.
1367 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1368 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1369 driver will continue to wait for more packets.
1370 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1375 PxeBcDhcp6CallBack (
1376 IN EFI_DHCP6_PROTOCOL
*This
,
1378 IN EFI_DHCP6_STATE CurrentState
,
1379 IN EFI_DHCP6_EVENT Dhcp6Event
,
1380 IN EFI_DHCP6_PACKET
*Packet
,
1381 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1384 PXEBC_PRIVATE_DATA
*Private
;
1385 EFI_PXE_BASE_CODE_MODE
*Mode
;
1386 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1387 EFI_DHCP6_PACKET
*SelectAd
;
1391 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1392 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1393 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1394 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1395 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1399 ASSERT (Packet
!= NULL
);
1401 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1402 Mode
= Private
->PxeBc
.Mode
;
1403 Callback
= Private
->PxeBcCallback
;
1406 // Callback to user when any traffic ocurred if has.
1408 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1409 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1410 Status
= Callback
->Callback (
1415 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1417 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1422 Status
= EFI_SUCCESS
;
1424 switch (Dhcp6Event
) {
1426 case Dhcp6SendSolicit
:
1428 // Record the first Solicate msg time
1430 if (Private
->SolicitTimes
== 0) {
1431 CalcElapsedTime (Private
);
1432 Private
->SolicitTimes
++;
1435 // Cache the dhcp discover packet to mode data directly.
1437 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1440 case Dhcp6RcvdAdvertise
:
1441 Status
= EFI_NOT_READY
;
1442 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1444 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1445 // the OfferIndex and OfferCount.
1447 PxeBcCacheDhcp6Offer (Private
, Packet
);
1451 case Dhcp6SendRequest
:
1453 // Store the request packet as seed packet for discover.
1455 if (Private
->Dhcp6Request
!= NULL
) {
1456 FreePool (Private
->Dhcp6Request
);
1458 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1459 if (Private
->Dhcp6Request
!= NULL
) {
1460 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1464 case Dhcp6SelectAdvertise
:
1466 // Select offer by the default policy or by order, and record the SelectIndex
1467 // and SelectProxyType.
1469 PxeBcSelectDhcp6Offer (Private
);
1471 if (Private
->SelectIndex
== 0) {
1472 Status
= EFI_ABORTED
;
1474 ASSERT (NewPacket
!= NULL
);
1475 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1476 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1477 ASSERT (*NewPacket
!= NULL
);
1478 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1482 case Dhcp6RcvdReply
:
1484 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1485 // without verification.
1487 ASSERT (Private
->SelectIndex
!= 0);
1488 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1500 Build and send out the request packet for the bootfile, and parse the reply.
1502 @param[in] Private The pointer to PxeBc private data.
1503 @param[in] Type PxeBc option boot item type.
1504 @param[in] Layer The pointer to option boot item layer.
1505 @param[in] UseBis Use BIS or not.
1506 @param[in] DestIp The pointer to the server address.
1508 @retval EFI_SUCCESS Successfully discovered the boot file.
1509 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1510 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1511 @retval Others Failed to discover the boot file.
1515 PxeBcDhcp6Discover (
1516 IN PXEBC_PRIVATE_DATA
*Private
,
1520 IN EFI_IP_ADDRESS
*DestIp
1523 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
1524 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
1525 EFI_PXE_BASE_CODE_MODE
*Mode
;
1526 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1527 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
1529 EFI_DHCP6_PACKET
*Request
;
1531 EFI_DHCP6_PACKET
*Reply
;
1541 PxeBc
= &Private
->PxeBc
;
1543 Request
= Private
->Dhcp6Request
;
1544 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
1545 DestPort
= PXEBC_BS_DISCOVER_PORT
;
1548 if (!UseBis
&& Layer
!= NULL
) {
1549 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1552 if (Request
== NULL
) {
1553 return EFI_DEVICE_ERROR
;
1556 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
1557 if (Discover
== NULL
) {
1558 return EFI_OUT_OF_RESOURCES
;
1562 // Build the discover packet by the cached request packet before.
1564 Xid
= NET_RANDOM (NetRandomInitSeed ());
1565 Discover
->TransactionId
= HTONL (Xid
);
1566 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
1567 RequestOpt
= Request
->Dhcp6
.Option
;
1568 DiscoverOpt
= Discover
->DhcpOptions
;
1569 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
1570 RequestLen
= DiscoverLen
;
1572 while (RequestLen
< Request
->Length
) {
1573 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
1574 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
1575 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
1576 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
1578 // Copy all the options except IA option.
1580 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
1581 DiscoverOpt
+= (OpLen
+ 4);
1582 DiscoverLen
+= (OpLen
+ 4);
1584 RequestOpt
+= (OpLen
+ 4);
1585 RequestLen
+= (OpLen
+ 4);
1588 Status
= PxeBc
->UdpWrite (
1594 &Private
->StationIp
,
1601 if (EFI_ERROR (Status
)) {
1606 // Cache the right PXE reply packet here, set valid flag later.
1607 // Especially for PXE discover packet, store it into mode data here.
1609 if (Private
->IsDoDiscover
) {
1610 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
1611 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
1613 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1615 ReadSize
= (UINTN
) Reply
->Size
;
1617 Status
= PxeBc
->UdpRead (
1620 &Private
->StationIp
,
1627 (VOID
*) &Reply
->Dhcp6
1629 if (EFI_ERROR (Status
)) {
1638 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1640 @param[in] Private The pointer to PxeBc private data.
1641 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1643 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1644 @retval Others Failed to finish the S.A.R.R. process.
1649 IN PXEBC_PRIVATE_DATA
*Private
,
1650 IN EFI_DHCP6_PROTOCOL
*Dhcp6
1653 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1654 EFI_DHCP6_CONFIG_DATA Config
;
1655 EFI_DHCP6_MODE_DATA Mode
;
1656 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
1657 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
1658 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
1662 Status
= EFI_SUCCESS
;
1663 PxeMode
= Private
->PxeBc
.Mode
;
1666 // Build option list for the request packet.
1668 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
1669 ASSERT (OptCount
> 0);
1671 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
1672 if (Retransmit
== NULL
) {
1673 return EFI_OUT_OF_RESOURCES
;
1676 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
1677 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1679 Config
.OptionCount
= OptCount
;
1680 Config
.OptionList
= OptList
;
1681 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
1682 Config
.CallbackContext
= Private
;
1683 Config
.IaInfoEvent
= NULL
;
1684 Config
.RapidCommit
= FALSE
;
1685 Config
.ReconfigureAccept
= FALSE
;
1686 Config
.IaDescriptor
.IaId
= 1;
1687 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
1688 Config
.SolicitRetransmission
= Retransmit
;
1689 Retransmit
->Irt
= 4;
1690 Retransmit
->Mrc
= 4;
1691 Retransmit
->Mrt
= 32;
1692 Retransmit
->Mrd
= 60;
1695 // Configure the DHCPv6 instance for PXE boot.
1697 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
1698 if (EFI_ERROR (Status
)) {
1699 FreePool (Retransmit
);
1704 // Initialize the record fields for DHCPv6 offer in private data.
1706 Private
->IsProxyRecved
= FALSE
;
1707 Private
->OfferNum
= 0;
1708 Private
->SelectIndex
= 0;
1709 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1710 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1714 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1716 Status
= Dhcp6
->Start (Dhcp6
);
1717 if (EFI_ERROR (Status
)) {
1718 if (Status
== EFI_ICMP_ERROR
) {
1719 PxeMode
->IcmpErrorReceived
= TRUE
;
1721 Dhcp6
->Configure (Dhcp6
, NULL
);
1726 // Get the acquired IPv6 address and store them.
1728 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1729 if (EFI_ERROR (Status
)) {
1730 Dhcp6
->Stop (Dhcp6
);
1734 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1735 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1736 CopyMem (&PxeMode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1738 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1739 if (EFI_ERROR (Status
)) {
1740 Dhcp6
->Stop (Dhcp6
);
1744 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, NULL
);
1745 if (EFI_ERROR (Status
)) {
1746 PxeBcUnregisterIp6Address (Private
);
1747 Dhcp6
->Stop (Dhcp6
);
1752 // Check the selected offer whether BINL retry is needed.
1754 Status
= PxeBcHandleDhcp6Offer (Private
);
1755 if (EFI_ERROR (Status
)) {
1756 PxeBcUnregisterIp6Address (Private
);
1757 Dhcp6
->Stop (Dhcp6
);
1761 AsciiPrint ("\n Station IP address is ");
1763 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);