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 CHAR8
*BootFileNamePtr
;
237 UINT16 BootFileNameLen
;
240 CHAR8
*ServerAddressOption
;
241 CHAR8
*ServerAddress
;
246 // The format of the Boot File URL option is:
249 // 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
250 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
251 // | OPT_BOOTFILE_URL | option-len |
252 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
254 // . bootfile-url (variable length) .
256 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
260 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
261 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
262 // As an example where the BOOTFILE_NAME is the EFI loader and
263 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
265 PrefixLen
= (UINT16
) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
);
267 if (Length
<= PrefixLen
||
268 CompareMem (BootFile
, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX
, PrefixLen
) != 0) {
269 return EFI_NOT_FOUND
;
272 BootFile
= BootFile
+ PrefixLen
;
273 Length
= (UINT16
) (Length
- PrefixLen
);
275 TmpStr
= (CHAR8
*) AllocateZeroPool (Length
+ 1);
276 if (TmpStr
== NULL
) {
277 return EFI_OUT_OF_RESOURCES
;
280 CopyMem (TmpStr
, BootFile
, Length
);
281 TmpStr
[Length
] = '\0';
284 // Get the part of SERVER_ADDRESS string.
286 ServerAddressOption
= TmpStr
;
287 if (*ServerAddressOption
!= PXEBC_ADDR_START_DELIMITER
) {
289 return EFI_INVALID_PARAMETER
;
292 ServerAddressOption
++;
293 ServerAddress
= ServerAddressOption
;
294 while (*ServerAddress
!= '\0' && *ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
298 if (*ServerAddress
!= PXEBC_ADDR_END_DELIMITER
) {
300 return EFI_INVALID_PARAMETER
;
303 *ServerAddress
= '\0';
306 // Convert the string of server address to Ipv6 address format and store it.
308 Status
= NetLibAsciiStrToIp6 (ServerAddressOption
, SrvAddr
);
309 if (EFI_ERROR (Status
)) {
315 // Get the part of BOOTFILE_NAME string.
317 BootFileNamePtr
= (CHAR8
*)((UINTN
)ServerAddress
+ 1);
318 if (*BootFileNamePtr
!= PXEBC_TFTP_URL_SEPARATOR
) {
320 return EFI_INVALID_PARAMETER
;
324 BootFileNameLen
= (UINT16
)(Length
- (UINT16
) ((UINTN
)BootFileNamePtr
- (UINTN
)TmpStr
) + 1);
325 if (BootFileNameLen
!= 0 || FileName
!= NULL
) {
327 // Remove trailing mode=octet if present and ignore. All other modes are
328 // invalid for netboot6, so reject them.
330 ModeStr
= AsciiStrStr (BootFileNamePtr
, ";mode=octet");
331 if (ModeStr
!= NULL
&& *(ModeStr
+ AsciiStrLen (";mode=octet")) == '\0') {
333 } else if (AsciiStrStr (BootFileNamePtr
, ";mode=") != NULL
) {
334 return EFI_INVALID_PARAMETER
;
338 // Extract boot file name from URL.
340 BootFileName
= (CHAR8
*) AllocateZeroPool (BootFileNameLen
);
341 if (BootFileName
== NULL
) {
343 return EFI_OUT_OF_RESOURCES
;
345 *FileName
= (UINT8
*) BootFileName
;
348 // Decode percent-encoding in boot file name.
350 while (*BootFileNamePtr
!= '\0') {
351 if (*BootFileNamePtr
== '%') {
352 TmpChar
= *(BootFileNamePtr
+ 3);
353 *(BootFileNamePtr
+ 3) = '\0';
354 *BootFileName
= (UINT8
) AsciiStrHexToUintn ((CHAR8
*)(BootFileNamePtr
+ 1));
356 *(BootFileNamePtr
+ 3) = TmpChar
;
357 BootFileNamePtr
+= 3;
359 *BootFileName
= *BootFileNamePtr
;
364 *BootFileName
= '\0';
374 Parse the Boot File Parameter option.
376 @param[in] BootFilePara The pointer to boot file parameter option data.
377 @param[out] BootFileSize The pointer to the parsed boot file size.
379 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
380 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
384 PxeBcExtractBootFileParam (
385 IN CHAR8
*BootFilePara
,
386 OUT UINT16
*BootFileSize
394 CopyMem (&Length
, BootFilePara
, sizeof (UINT16
));
395 Length
= NTOHS (Length
);
398 // The BootFile Size should be 1~5 byte ASCII strings
400 if (Length
< 1 || Length
> 5) {
401 return EFI_NOT_FOUND
;
405 // Extract the value of BootFile Size.
407 BootFilePara
= BootFilePara
+ sizeof (UINT16
);
409 for (Index
= 0; Index
< Length
; Index
++) {
410 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit
, *(BootFilePara
+ Index
)))) {
411 return EFI_NOT_FOUND
;
414 Size
= (Size
+ Digit
) * 10;
418 if (Size
> PXEBC_DHCP6_MAX_BOOT_FILE_SIZE
) {
419 return EFI_NOT_FOUND
;
422 *BootFileSize
= (UINT16
) Size
;
428 Parse the cached DHCPv6 packet, including all the options.
430 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
432 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
433 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
437 PxeBcParseDhcp6Packet (
438 IN PXEBC_DHCP6_PACKET_CACHE
*Cache6
441 EFI_DHCP6_PACKET
*Offer
;
442 EFI_DHCP6_PACKET_OPTION
**Options
;
443 EFI_DHCP6_PACKET_OPTION
*Option
;
444 PXEBC_OFFER_TYPE OfferType
;
445 BOOLEAN IsProxyOffer
;
449 UINT32 EnterpriseNum
;
453 Offer
= &Cache6
->Packet
.Offer
;
454 Options
= Cache6
->OptList
;
456 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
458 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
460 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
463 // OpLen and OpCode here are both stored in network order, since they are from original packet.
465 while (Offset
< Length
) {
467 if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_IA_NA
) {
468 Options
[PXEBC_DHCP6_IDX_IA_NA
] = Option
;
469 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_URL
) {
471 // The server sends this option to inform the client about an URL to a boot file.
473 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
474 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM
) {
475 Options
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
476 } else if (NTOHS (Option
->OpCode
) == PXEBC_DHCP6_OPT_VENDOR_CLASS
) {
477 Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
] = Option
;
480 Offset
+= (NTOHS (Option
->OpLen
) + 4);
481 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
485 // The offer with assigned client address is a proxy offer.
486 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
488 Option
= Options
[PXEBC_DHCP6_IDX_IA_NA
];
489 if (Option
!= NULL
) {
490 Option
= PxeBcParseDhcp6Options (
492 NTOHS (Option
->OpLen
),
493 PXEBC_DHCP6_OPT_STATUS_CODE
495 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
496 IsProxyOffer
= FALSE
;
501 // The offer with "PXEClient" is a pxe offer.
503 Option
= Options
[PXEBC_DHCP6_IDX_VENDOR_CLASS
];
504 EnterpriseNum
= HTONL(PXEBC_DHCP6_ENTERPRISE_NUM
);
506 if (Option
!= NULL
&&
507 NTOHS(Option
->OpLen
) >= 13 &&
508 CompareMem (Option
->Data
, &EnterpriseNum
, sizeof (UINT32
)) == 0 &&
509 CompareMem (&Option
->Data
[6], DEFAULT_CLASS_ID_DATA
, 9) == 0) {
514 // Determine offer type of the dhcp6 packet.
518 // It's a binl offer only with PXEClient.
520 OfferType
= IsProxyOffer
? PxeOfferTypeProxyBinl
: PxeOfferTypeDhcpBinl
;
523 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
525 OfferType
= PxeOfferTypeDhcpOnly
;
528 Cache6
->OfferType
= OfferType
;
535 Cache the DHCPv6 ack packet, and parse it on demand.
537 @param[in] Private The pointer to PxeBc private data.
538 @param[in] Ack The pointer to the DHCPv6 ack packet.
539 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
544 IN PXEBC_PRIVATE_DATA
*Private
,
545 IN EFI_DHCP6_PACKET
*Ack
,
549 EFI_PXE_BASE_CODE_MODE
*Mode
;
551 Mode
= Private
->PxeBc
.Mode
;
553 PxeBcCacheDhcp6Packet (&Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, Ack
);
557 // Parse the ack packet and store it into mode data if needed.
559 PxeBcParseDhcp6Packet (&Private
->DhcpAck
.Dhcp6
);
560 CopyMem (&Mode
->DhcpAck
.Dhcpv6
, &Ack
->Dhcp6
, Ack
->Length
);
561 Mode
->DhcpAckReceived
= TRUE
;
567 Cache the DHCPv6 proxy offer packet according to the received order.
569 @param[in] Private The pointer to PxeBc private data.
570 @param[in] OfferIndex The received order of offer packets.
574 PxeBcCopyDhcp6Proxy (
575 IN PXEBC_PRIVATE_DATA
*Private
,
579 EFI_PXE_BASE_CODE_MODE
*Mode
;
580 EFI_DHCP6_PACKET
*Offer
;
582 ASSERT (OfferIndex
< Private
->OfferNum
);
583 ASSERT (OfferIndex
< PXEBC_OFFER_MAX_NUM
);
585 Mode
= Private
->PxeBc
.Mode
;
586 Offer
= &Private
->OfferBuffer
[OfferIndex
].Dhcp6
.Packet
.Offer
;
589 // Cache the proxy offer packet and parse it.
591 PxeBcCacheDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
, Offer
);
592 PxeBcParseDhcp6Packet (&Private
->ProxyOffer
.Dhcp6
);
595 // Store this packet into mode data.
597 CopyMem (&Mode
->ProxyOffer
.Dhcpv6
, &Offer
->Dhcp6
, Offer
->Length
);
598 Mode
->ProxyOfferReceived
= TRUE
;
602 Seek the address of the first byte of the option header.
604 @param[in] Buf The pointer to the buffer.
605 @param[in] SeekLen The length to seek.
606 @param[in] OptType The option type.
608 @retval NULL If it failed to seek the option.
609 @retval others The position to the option.
613 PxeBcDhcp6SeekOption (
627 while (Cursor
< Buf
+ SeekLen
) {
628 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
629 if (OpCode
== HTONS (OptType
)) {
633 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
634 Cursor
+= (DataLen
+ 4);
642 Build and send out the request packet for the bootfile, and parse the reply.
644 @param[in] Private The pointer to PxeBc private data.
645 @param[in] Index PxeBc option boot item type.
647 @retval EFI_SUCCESS Successfully discovered the boot file.
648 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
649 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
650 @retval Others Failed to discover the boot file.
654 PxeBcRequestBootService (
655 IN PXEBC_PRIVATE_DATA
*Private
,
659 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
660 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
661 EFI_PXE_BASE_CODE_MODE
*Mode
;
662 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
663 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
665 EFI_DHCP6_PACKET
*Request
;
667 EFI_DHCP6_PACKET
*Reply
;
675 EFI_DHCP6_PACKET
*ProxyOffer
;
678 PxeBc
= &Private
->PxeBc
;
680 Request
= Private
->Dhcp6Request
;
681 ProxyOffer
= &Private
->OfferBuffer
[Index
].Dhcp6
.Packet
.Offer
;
682 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
683 DestPort
= PXEBC_BS_DISCOVER_PORT
;
686 if (Request
== NULL
) {
687 return EFI_DEVICE_ERROR
;
690 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
691 if (Discover
== NULL
) {
692 return EFI_OUT_OF_RESOURCES
;
696 // Build the request packet by the cached request packet before.
698 Discover
->TransactionId
= ProxyOffer
->Dhcp6
.Header
.TransactionId
;
699 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
700 RequestOpt
= Request
->Dhcp6
.Option
;
701 DiscoverOpt
= Discover
->DhcpOptions
;
702 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
703 RequestLen
= DiscoverLen
;
706 // Find Server ID Option from ProxyOffer.
708 Option
= PxeBcDhcp6SeekOption (
709 ProxyOffer
->Dhcp6
.Option
,
710 ProxyOffer
->Length
- 4,
711 PXEBC_DHCP6_OPT_SERVER_ID
713 if (Option
== NULL
) {
714 return EFI_NOT_FOUND
;
718 // Add Server ID Option.
720 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) Option
)->OpLen
);
721 CopyMem (DiscoverOpt
, Option
, OpLen
+ 4);
722 DiscoverOpt
+= (OpLen
+ 4);
723 DiscoverLen
+= (OpLen
+ 4);
725 while (RequestLen
< Request
->Length
) {
726 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
727 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
728 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
729 OpCode
!= EFI_DHCP6_IA_TYPE_TA
&&
730 OpCode
!= PXEBC_DHCP6_OPT_SERVER_ID
733 // Copy all the options except IA option and Server ID
735 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
736 DiscoverOpt
+= (OpLen
+ 4);
737 DiscoverLen
+= (OpLen
+ 4);
739 RequestOpt
+= (OpLen
+ 4);
740 RequestLen
+= (OpLen
+ 4);
744 // Update Elapsed option in the package
746 Option
= PxeBcDhcp6SeekOption (
747 Discover
->DhcpOptions
,
748 (UINT32
)(RequestLen
- 4),
749 PXEBC_DHCP6_OPT_ELAPSED_TIME
751 if (Option
!= NULL
) {
752 CalcElapsedTime (Private
);
753 WriteUnaligned16 ((UINT16
*)(Option
+ 4), HTONS((UINT16
) Private
->ElapsedTime
));
756 Status
= PxeBc
->UdpWrite (
770 if (EFI_ERROR (Status
)) {
775 // Cache the right PXE reply packet here, set valid flag later.
776 // Especially for PXE discover packet, store it into mode data here.
778 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
779 ReadSize
= (UINTN
) Reply
->Size
;
782 // Start Udp6Read instance
784 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
785 if (EFI_ERROR (Status
)) {
789 Status
= PxeBc
->UdpRead (
799 (VOID
*) &Reply
->Dhcp6
802 // Stop Udp6Read instance
804 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
806 if (EFI_ERROR (Status
)) {
813 Reply
->Length
= (UINT32
) ReadSize
;
820 Retry to request bootfile name by the BINL offer.
822 @param[in] Private The pointer to PxeBc private data.
823 @param[in] Index The received order of offer packets.
825 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
826 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
830 PxeBcRetryDhcp6Binl (
831 IN PXEBC_PRIVATE_DATA
*Private
,
835 EFI_PXE_BASE_CODE_MODE
*Mode
;
836 PXEBC_DHCP6_PACKET_CACHE
*Offer
;
837 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
840 ASSERT (Index
< PXEBC_OFFER_MAX_NUM
);
841 ASSERT (Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeDhcpBinl
||
842 Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
== PxeOfferTypeProxyBinl
);
844 Mode
= Private
->PxeBc
.Mode
;
845 Private
->IsDoDiscover
= FALSE
;
846 Offer
= &Private
->OfferBuffer
[Index
].Dhcp6
;
848 ASSERT (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
850 // Parse out the next server address from the last offer, and store it
852 Status
= PxeBcExtractBootFileUrl (
853 &Private
->BootFileName
,
854 &Private
->ServerIp
.v6
,
855 (CHAR8
*) (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
856 NTOHS (Offer
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
858 if (EFI_ERROR (Status
)) {
863 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
865 Status
= PxeBcRequestBootService (Private
, Index
);
867 if (EFI_ERROR (Status
)) {
871 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
872 Status
= PxeBcParseDhcp6Packet (Cache6
);
873 if (EFI_ERROR (Status
)) {
877 if (Cache6
->OfferType
!= PxeOfferTypeProxyPxe10
&&
878 Cache6
->OfferType
!= PxeOfferTypeProxyWfm11a
&&
879 Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
881 // This BINL ack doesn't have discovery option set or multicast option set
882 // or bootfile name specified.
884 return EFI_DEVICE_ERROR
;
887 Mode
->ProxyOfferReceived
= TRUE
;
889 &Mode
->ProxyOffer
.Dhcpv6
,
890 &Cache6
->Packet
.Offer
.Dhcp6
,
891 Cache6
->Packet
.Offer
.Length
899 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
901 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
902 @param[in] RcvdOffer The pointer to the received offer packet.
906 PxeBcCacheDhcp6Offer (
907 IN PXEBC_PRIVATE_DATA
*Private
,
908 IN EFI_DHCP6_PACKET
*RcvdOffer
911 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
912 EFI_DHCP6_PACKET
*Offer
;
913 PXEBC_OFFER_TYPE OfferType
;
915 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
916 Offer
= &Cache6
->Packet
.Offer
;
919 // Cache the content of DHCPv6 packet firstly.
921 PxeBcCacheDhcp6Packet (Offer
, RcvdOffer
);
924 // Validate the DHCPv6 packet, and parse the options and offer type.
926 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6
))) {
931 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
933 OfferType
= Cache6
->OfferType
;
934 ASSERT (OfferType
< PxeOfferTypeMax
);
935 ASSERT (Private
->OfferCount
[OfferType
] < PXEBC_OFFER_MAX_NUM
);
937 if (IS_PROXY_OFFER (OfferType
)) {
939 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
941 Private
->IsProxyRecved
= TRUE
;
943 if (OfferType
== PxeOfferTypeProxyBinl
) {
945 // Cache all proxy BINL offers.
947 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
948 Private
->OfferCount
[OfferType
]++;
949 } else if (Private
->OfferCount
[OfferType
] > 0) {
951 // Only cache the first PXE10/WFM11a offer, and discard the others.
953 Private
->OfferIndex
[OfferType
][0] = Private
->OfferNum
;
954 Private
->OfferCount
[OfferType
] = 1;
960 // It's a DHCPv6 offer with yiaddr, and cache them all.
962 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
963 Private
->OfferCount
[OfferType
]++;
971 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
973 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
977 PxeBcSelectDhcp6Offer (
978 IN PXEBC_PRIVATE_DATA
*Private
983 PXEBC_OFFER_TYPE OfferType
;
985 Private
->SelectIndex
= 0;
987 if (Private
->IsOfferSorted
) {
989 // Select offer by default policy.
991 if (Private
->OfferCount
[PxeOfferTypeDhcpPxe10
] > 0) {
993 // 1. DhcpPxe10 offer
995 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpPxe10
][0] + 1;
997 } else if (Private
->OfferCount
[PxeOfferTypeDhcpWfm11a
] > 0) {
999 // 2. DhcpWfm11a offer
1001 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpWfm11a
][0] + 1;
1003 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1004 Private
->OfferCount
[PxeOfferTypeProxyPxe10
] > 0) {
1006 // 3. DhcpOnly offer and ProxyPxe10 offer.
1008 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1009 Private
->SelectProxyType
= PxeOfferTypeProxyPxe10
;
1011 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1012 Private
->OfferCount
[PxeOfferTypeProxyWfm11a
] > 0) {
1014 // 4. DhcpOnly offer and ProxyWfm11a offer.
1016 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1017 Private
->SelectProxyType
= PxeOfferTypeProxyWfm11a
;
1019 } else if (Private
->OfferCount
[PxeOfferTypeDhcpBinl
] > 0) {
1021 // 5. DhcpBinl offer.
1023 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpBinl
][0] + 1;
1025 } else if (Private
->OfferCount
[PxeOfferTypeDhcpOnly
] > 0 &&
1026 Private
->OfferCount
[PxeOfferTypeProxyBinl
] > 0) {
1028 // 6. DhcpOnly offer and ProxyBinl offer.
1030 Private
->SelectIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][0] + 1;
1031 Private
->SelectProxyType
= PxeOfferTypeProxyBinl
;
1035 // 7. DhcpOnly offer with bootfilename.
1037 for (Index
= 0; Index
< Private
->OfferCount
[PxeOfferTypeDhcpOnly
]; Index
++) {
1038 OfferIndex
= Private
->OfferIndex
[PxeOfferTypeDhcpOnly
][Index
];
1039 if (Private
->OfferBuffer
[OfferIndex
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
) {
1040 Private
->SelectIndex
= OfferIndex
+ 1;
1047 // Select offer by received order.
1049 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1051 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1053 if (IS_PROXY_OFFER (OfferType
)) {
1055 // Skip proxy offers
1060 if (!Private
->IsProxyRecved
&&
1061 OfferType
== PxeOfferTypeDhcpOnly
&&
1062 Private
->OfferBuffer
[Index
].Dhcp6
.OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
1064 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1069 Private
->SelectIndex
= Index
+ 1;
1077 Handle the DHCPv6 offer packet.
1079 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1081 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1082 @retval EFI_NO_RESPONSE No response to the following request packet.
1086 PxeBcHandleDhcp6Offer (
1087 IN PXEBC_PRIVATE_DATA
*Private
1090 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
1092 PXEBC_OFFER_TYPE OfferType
;
1097 ASSERT (Private
->SelectIndex
> 0);
1098 SelectIndex
= (UINT32
) (Private
->SelectIndex
- 1);
1099 ASSERT (SelectIndex
< PXEBC_OFFER_MAX_NUM
);
1100 Cache6
= &Private
->OfferBuffer
[SelectIndex
].Dhcp6
;
1101 Status
= EFI_SUCCESS
;
1103 if (Cache6
->OfferType
== PxeOfferTypeDhcpBinl
) {
1105 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1107 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, SelectIndex
))) {
1108 Status
= EFI_NO_RESPONSE
;
1110 } else if (Cache6
->OfferType
== PxeOfferTypeDhcpOnly
) {
1112 if (Private
->IsProxyRecved
) {
1114 // DhcpOnly offer is selected, so need try to request bootfilename.
1117 if (Private
->IsOfferSorted
) {
1119 // The proxy offer should be determined if select by default policy.
1120 // IsOfferSorted means all offers are labeled by OfferIndex.
1122 ASSERT (Private
->OfferCount
[Private
->SelectProxyType
] > 0);
1124 if (Private
->SelectProxyType
== PxeOfferTypeProxyBinl
) {
1126 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1128 for (Index
= 0; Index
< Private
->OfferCount
[Private
->SelectProxyType
]; Index
++) {
1130 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][Index
];
1131 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, ProxyIndex
))) {
1135 if (Index
== Private
->OfferCount
[Private
->SelectProxyType
]) {
1136 Status
= EFI_NO_RESPONSE
;
1140 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1142 ProxyIndex
= Private
->OfferIndex
[Private
->SelectProxyType
][0];
1146 // The proxy offer should not be determined if select by received order.
1148 Status
= EFI_NO_RESPONSE
;
1150 for (Index
= 0; Index
< Private
->OfferNum
; Index
++) {
1152 OfferType
= Private
->OfferBuffer
[Index
].Dhcp6
.OfferType
;
1154 if (!IS_PROXY_OFFER (OfferType
)) {
1156 // Skip non proxy dhcp offers.
1161 if (OfferType
== PxeOfferTypeProxyBinl
) {
1163 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1165 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private
, Index
))) {
1170 Private
->SelectProxyType
= OfferType
;
1172 Status
= EFI_SUCCESS
;
1177 if (!EFI_ERROR (Status
) && Private
->SelectProxyType
!= PxeOfferTypeProxyBinl
) {
1179 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1181 PxeBcCopyDhcp6Proxy (Private
, ProxyIndex
);
1185 // Othewise, the bootfilename must be included in DhcpOnly offer.
1187 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
1191 if (!EFI_ERROR (Status
)) {
1193 // All PXE boot information is ready by now.
1195 PxeBcCopyDhcp6Ack (Private
, &Private
->DhcpAck
.Dhcp6
.Packet
.Ack
, TRUE
);
1196 Private
->PxeBc
.Mode
->DhcpDiscoverValid
= TRUE
;
1204 Unregister the address by Ip6Config protocol.
1206 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1210 PxeBcUnregisterIp6Address (
1211 IN PXEBC_PRIVATE_DATA
*Private
1214 if (Private
->Ip6Policy
!= PXEBC_IP6_POLICY_MAX
) {
1216 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1217 // Keep the point and there is no enough requirements to do recovery.
1224 Register the ready address by Ip6Config protocol.
1226 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1227 @param[in] Address The pointer to the ready address.
1229 @retval EFI_SUCCESS Registered the address succesfully.
1230 @retval Others Failed to register the address.
1234 PxeBcRegisterIp6Address (
1235 IN PXEBC_PRIVATE_DATA
*Private
,
1236 IN EFI_IPv6_ADDRESS
*Address
1239 EFI_IP6_PROTOCOL
*Ip6
;
1240 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
1241 EFI_IP6_CONFIG_POLICY Policy
;
1242 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
1244 EFI_EVENT TimeOutEvt
;
1245 EFI_EVENT MappedEvt
;
1248 Status
= EFI_SUCCESS
;
1251 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
1252 Ip6Cfg
= Private
->Ip6Cfg
;
1255 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
1256 CopyMem (&CfgAddr
.Address
, Address
, sizeof (EFI_IPv6_ADDRESS
));
1259 // Get and store the current policy of IP6 driver.
1261 Status
= Ip6Cfg
->GetData (
1263 Ip6ConfigDataTypePolicy
,
1267 if (EFI_ERROR (Status
)) {
1272 // There is no channel between IP6 and PXE driver about address setting,
1273 // so it has to set the new address by Ip6ConfigProtocol manually.
1275 Policy
= Ip6ConfigPolicyManual
;
1276 Status
= Ip6Cfg
->SetData (
1278 Ip6ConfigDataTypePolicy
,
1279 sizeof(EFI_IP6_CONFIG_POLICY
),
1282 if (EFI_ERROR (Status
)) {
1284 // There is no need to recover later.
1286 Private
->Ip6Policy
= PXEBC_IP6_POLICY_MAX
;
1291 // Create a timer as setting address timeout event since DAD in IP6 driver.
1293 Status
= gBS
->CreateEvent (
1300 if (EFI_ERROR (Status
)) {
1305 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1307 Status
= gBS
->CreateEvent (
1311 &Private
->IsAddressOk
,
1314 if (EFI_ERROR (Status
)) {
1318 Status
= Ip6Cfg
->RegisterDataNotify (
1320 Ip6ConfigDataTypeManualAddress
,
1323 if (EFI_ERROR(Status
)) {
1327 Status
= Ip6Cfg
->SetData (
1329 Ip6ConfigDataTypeManualAddress
,
1330 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS
),
1333 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_READY
) {
1338 // Start the 5 secondes timer to wait for setting address.
1340 Status
= EFI_NO_MAPPING
;
1341 gBS
->SetTimer (TimeOutEvt
, TimerRelative
, PXEBC_DHCP6_MAPPING_TIMEOUT
);
1343 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
1345 if (Private
->IsAddressOk
) {
1346 Status
= EFI_SUCCESS
;
1352 if (MappedEvt
!= NULL
) {
1353 Ip6Cfg
->UnregisterDataNotify (
1355 Ip6ConfigDataTypeManualAddress
,
1358 gBS
->CloseEvent (MappedEvt
);
1360 if (TimeOutEvt
!= NULL
) {
1361 gBS
->CloseEvent (TimeOutEvt
);
1368 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1369 to intercept events that occurred in the configuration process.
1371 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1372 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1373 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1374 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1376 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1377 @param[out] NewPacket The packet that is used to replace the Packet above.
1379 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1380 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1381 driver will continue to wait for more packets.
1382 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1387 PxeBcDhcp6CallBack (
1388 IN EFI_DHCP6_PROTOCOL
*This
,
1390 IN EFI_DHCP6_STATE CurrentState
,
1391 IN EFI_DHCP6_EVENT Dhcp6Event
,
1392 IN EFI_DHCP6_PACKET
*Packet
,
1393 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
1396 PXEBC_PRIVATE_DATA
*Private
;
1397 EFI_PXE_BASE_CODE_MODE
*Mode
;
1398 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
*Callback
;
1399 EFI_DHCP6_PACKET
*SelectAd
;
1403 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
1404 (Dhcp6Event
!= Dhcp6SelectAdvertise
) &&
1405 (Dhcp6Event
!= Dhcp6SendSolicit
) &&
1406 (Dhcp6Event
!= Dhcp6SendRequest
) &&
1407 (Dhcp6Event
!= Dhcp6RcvdReply
)) {
1411 ASSERT (Packet
!= NULL
);
1413 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
1414 Mode
= Private
->PxeBc
.Mode
;
1415 Callback
= Private
->PxeBcCallback
;
1418 // Callback to user when any traffic ocurred if has.
1420 if (Dhcp6Event
!= Dhcp6SelectAdvertise
&& Callback
!= NULL
) {
1421 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
1422 Status
= Callback
->Callback (
1427 (EFI_PXE_BASE_CODE_PACKET
*) &Packet
->Dhcp6
1429 if (Status
!= EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
) {
1434 Status
= EFI_SUCCESS
;
1436 switch (Dhcp6Event
) {
1438 case Dhcp6SendSolicit
:
1440 // Record the first Solicate msg time
1442 if (Private
->SolicitTimes
== 0) {
1443 CalcElapsedTime (Private
);
1444 Private
->SolicitTimes
++;
1447 // Cache the dhcp discover packet to mode data directly.
1449 CopyMem (&Mode
->DhcpDiscover
.Dhcpv4
, &Packet
->Dhcp6
, Packet
->Length
);
1452 case Dhcp6RcvdAdvertise
:
1453 Status
= EFI_NOT_READY
;
1454 if (Private
->OfferNum
< PXEBC_OFFER_MAX_NUM
) {
1456 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1457 // the OfferIndex and OfferCount.
1459 PxeBcCacheDhcp6Offer (Private
, Packet
);
1463 case Dhcp6SendRequest
:
1465 // Store the request packet as seed packet for discover.
1467 if (Private
->Dhcp6Request
!= NULL
) {
1468 FreePool (Private
->Dhcp6Request
);
1470 Private
->Dhcp6Request
= AllocateZeroPool (Packet
->Size
);
1471 if (Private
->Dhcp6Request
!= NULL
) {
1472 CopyMem (Private
->Dhcp6Request
, Packet
, Packet
->Size
);
1476 case Dhcp6SelectAdvertise
:
1478 // Select offer by the default policy or by order, and record the SelectIndex
1479 // and SelectProxyType.
1481 PxeBcSelectDhcp6Offer (Private
);
1483 if (Private
->SelectIndex
== 0) {
1484 Status
= EFI_ABORTED
;
1486 ASSERT (NewPacket
!= NULL
);
1487 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
1488 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
1489 ASSERT (*NewPacket
!= NULL
);
1490 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
1494 case Dhcp6RcvdReply
:
1496 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1497 // without verification.
1499 ASSERT (Private
->SelectIndex
!= 0);
1500 PxeBcCopyDhcp6Ack (Private
, Packet
, FALSE
);
1512 Build and send out the request packet for the bootfile, and parse the reply.
1514 @param[in] Private The pointer to PxeBc private data.
1515 @param[in] Type PxeBc option boot item type.
1516 @param[in] Layer The pointer to option boot item layer.
1517 @param[in] UseBis Use BIS or not.
1518 @param[in] DestIp The pointer to the server address.
1520 @retval EFI_SUCCESS Successfully discovered the boot file.
1521 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1522 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1523 @retval Others Failed to discover the boot file.
1527 PxeBcDhcp6Discover (
1528 IN PXEBC_PRIVATE_DATA
*Private
,
1532 IN EFI_IP_ADDRESS
*DestIp
1535 EFI_PXE_BASE_CODE_UDP_PORT SrcPort
;
1536 EFI_PXE_BASE_CODE_UDP_PORT DestPort
;
1537 EFI_PXE_BASE_CODE_MODE
*Mode
;
1538 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1539 EFI_PXE_BASE_CODE_DHCPV6_PACKET
*Discover
;
1541 EFI_DHCP6_PACKET
*Request
;
1543 EFI_DHCP6_PACKET
*Reply
;
1553 PxeBc
= &Private
->PxeBc
;
1555 Request
= Private
->Dhcp6Request
;
1556 SrcPort
= PXEBC_BS_DISCOVER_PORT
;
1557 DestPort
= PXEBC_BS_DISCOVER_PORT
;
1560 if (!UseBis
&& Layer
!= NULL
) {
1561 *Layer
&= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK
;
1564 if (Request
== NULL
) {
1565 return EFI_DEVICE_ERROR
;
1568 Discover
= AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET
));
1569 if (Discover
== NULL
) {
1570 return EFI_OUT_OF_RESOURCES
;
1574 // Build the discover packet by the cached request packet before.
1576 Xid
= NET_RANDOM (NetRandomInitSeed ());
1577 Discover
->TransactionId
= HTONL (Xid
);
1578 Discover
->MessageType
= Request
->Dhcp6
.Header
.MessageType
;
1579 RequestOpt
= Request
->Dhcp6
.Option
;
1580 DiscoverOpt
= Discover
->DhcpOptions
;
1581 DiscoverLen
= sizeof (EFI_DHCP6_HEADER
);
1582 RequestLen
= DiscoverLen
;
1584 while (RequestLen
< Request
->Length
) {
1585 OpCode
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpCode
);
1586 OpLen
= NTOHS (((EFI_DHCP6_PACKET_OPTION
*) RequestOpt
)->OpLen
);
1587 if (OpCode
!= EFI_DHCP6_IA_TYPE_NA
&&
1588 OpCode
!= EFI_DHCP6_IA_TYPE_TA
) {
1590 // Copy all the options except IA option.
1592 CopyMem (DiscoverOpt
, RequestOpt
, OpLen
+ 4);
1593 DiscoverOpt
+= (OpLen
+ 4);
1594 DiscoverLen
+= (OpLen
+ 4);
1596 RequestOpt
+= (OpLen
+ 4);
1597 RequestLen
+= (OpLen
+ 4);
1600 Status
= PxeBc
->UdpWrite (
1606 &Private
->StationIp
,
1613 if (EFI_ERROR (Status
)) {
1618 // Cache the right PXE reply packet here, set valid flag later.
1619 // Especially for PXE discover packet, store it into mode data here.
1621 if (Private
->IsDoDiscover
) {
1622 CopyMem (&Mode
->PxeDiscover
.Dhcpv6
, Discover
, DiscoverLen
);
1623 Reply
= &Private
->PxeReply
.Dhcp6
.Packet
.Ack
;
1625 Reply
= &Private
->ProxyOffer
.Dhcp6
.Packet
.Offer
;
1627 ReadSize
= (UINTN
) Reply
->Size
;
1630 // Start Udp6Read instance
1632 Status
= Private
->Udp6Read
->Configure (Private
->Udp6Read
, &Private
->Udp6CfgData
);
1633 if (EFI_ERROR (Status
)) {
1637 Status
= PxeBc
->UdpRead (
1640 &Private
->StationIp
,
1647 (VOID
*) &Reply
->Dhcp6
1650 // Stop Udp6Read instance
1652 Private
->Udp6Read
->Configure (Private
->Udp6Read
, NULL
);
1653 if (EFI_ERROR (Status
)) {
1662 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1664 @param[in] Private The pointer to PxeBc private data.
1665 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1667 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1668 @retval Others Failed to finish the S.A.R.R. process.
1673 IN PXEBC_PRIVATE_DATA
*Private
,
1674 IN EFI_DHCP6_PROTOCOL
*Dhcp6
1677 EFI_PXE_BASE_CODE_MODE
*PxeMode
;
1678 EFI_DHCP6_CONFIG_DATA Config
;
1679 EFI_DHCP6_MODE_DATA Mode
;
1680 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
1681 EFI_DHCP6_PACKET_OPTION
*OptList
[PXEBC_DHCP6_OPTION_MAX_NUM
];
1682 UINT8 Buffer
[PXEBC_DHCP6_OPTION_MAX_SIZE
];
1686 Status
= EFI_SUCCESS
;
1687 PxeMode
= Private
->PxeBc
.Mode
;
1690 // Build option list for the request packet.
1692 OptCount
= PxeBcBuildDhcp6Options (Private
, OptList
, Buffer
);
1693 ASSERT (OptCount
> 0);
1695 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
1696 if (Retransmit
== NULL
) {
1697 return EFI_OUT_OF_RESOURCES
;
1700 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
1701 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1703 Config
.OptionCount
= OptCount
;
1704 Config
.OptionList
= OptList
;
1705 Config
.Dhcp6Callback
= PxeBcDhcp6CallBack
;
1706 Config
.CallbackContext
= Private
;
1707 Config
.IaInfoEvent
= NULL
;
1708 Config
.RapidCommit
= FALSE
;
1709 Config
.ReconfigureAccept
= FALSE
;
1710 Config
.IaDescriptor
.IaId
= 1;
1711 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
1712 Config
.SolicitRetransmission
= Retransmit
;
1713 Retransmit
->Irt
= 4;
1714 Retransmit
->Mrc
= 4;
1715 Retransmit
->Mrt
= 32;
1716 Retransmit
->Mrd
= 60;
1719 // Configure the DHCPv6 instance for PXE boot.
1721 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
1722 if (EFI_ERROR (Status
)) {
1723 FreePool (Retransmit
);
1728 // Initialize the record fields for DHCPv6 offer in private data.
1730 Private
->IsProxyRecved
= FALSE
;
1731 Private
->OfferNum
= 0;
1732 Private
->SelectIndex
= 0;
1733 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1734 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1738 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1740 Status
= Dhcp6
->Start (Dhcp6
);
1741 if (EFI_ERROR (Status
)) {
1742 if (Status
== EFI_ICMP_ERROR
) {
1743 PxeMode
->IcmpErrorReceived
= TRUE
;
1745 Dhcp6
->Configure (Dhcp6
, NULL
);
1750 // Get the acquired IPv6 address and store them.
1752 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1753 if (EFI_ERROR (Status
)) {
1754 Dhcp6
->Stop (Dhcp6
);
1758 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1759 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1760 CopyMem (&PxeMode
->StationIp
.v6
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
1762 Status
= PxeBcRegisterIp6Address (Private
, &Private
->StationIp
.v6
);
1763 if (EFI_ERROR (Status
)) {
1764 Dhcp6
->Stop (Dhcp6
);
1768 Status
= PxeBcFlushStaionIp (Private
, &Private
->StationIp
, NULL
);
1769 if (EFI_ERROR (Status
)) {
1770 PxeBcUnregisterIp6Address (Private
);
1771 Dhcp6
->Stop (Dhcp6
);
1776 // Check the selected offer whether BINL retry is needed.
1778 Status
= PxeBcHandleDhcp6Offer (Private
);
1779 if (EFI_ERROR (Status
)) {
1780 PxeBcUnregisterIp6Address (Private
);
1781 Dhcp6
->Stop (Dhcp6
);
1785 AsciiPrint ("\n Station IP address is ");
1787 PxeBcShowIp6Addr (&Private
->StationIp
.v6
);