2 Functions implementation related with DHCPv6 for HTTP boot driver.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "HttpBootDxe.h"
12 Build the options buffer for the DHCPv6 request packet.
14 @param[in] Private The pointer to HTTP BOOT driver private data.
15 @param[out] OptList The pointer to the option pointer array.
16 @param[in] Buffer The pointer to the buffer to contain the option list.
18 @return Index The count of the built-in options.
22 HttpBootBuildDhcp6Options (
23 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
24 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
28 HTTP_BOOT_DHCP6_OPTION_ENTRY OptEnt
;
33 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*)Buffer
;
36 // Append client option request option
38 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ORO
);
39 OptList
[Index
]->OpLen
= HTONS (8);
40 OptEnt
.Oro
= (HTTP_BOOT_DHCP6_OPTION_ORO
*)OptList
[Index
]->Data
;
41 OptEnt
.Oro
->OpCode
[0] = HTONS (DHCP6_OPT_BOOT_FILE_URL
);
42 OptEnt
.Oro
->OpCode
[1] = HTONS (DHCP6_OPT_BOOT_FILE_PARAM
);
43 OptEnt
.Oro
->OpCode
[2] = HTONS (DHCP6_OPT_DNS_SERVERS
);
44 OptEnt
.Oro
->OpCode
[3] = HTONS (DHCP6_OPT_VENDOR_CLASS
);
46 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
49 // Append client network device interface option
51 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
52 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
53 OptEnt
.Undi
= (HTTP_BOOT_DHCP6_OPTION_UNDI
*)OptList
[Index
]->Data
;
55 if (Private
->Nii
!= NULL
) {
56 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
57 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
58 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
60 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
61 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
62 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
66 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
69 // Append client system architecture option
71 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
72 OptList
[Index
]->OpLen
= HTONS ((UINT16
)sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH
));
73 OptEnt
.Arch
= (HTTP_BOOT_DHCP6_OPTION_ARCH
*)OptList
[Index
]->Data
;
74 Value
= HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
);
75 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
77 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
80 // Append vendor class identify option.
82 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
83 OptList
[Index
]->OpLen
= HTONS ((UINT16
)sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS
));
84 OptEnt
.VendorClass
= (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS
*)OptList
[Index
]->Data
;
85 OptEnt
.VendorClass
->Vendor
= HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM
);
86 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
)sizeof (HTTP_BOOT_CLASS_ID
));
88 &OptEnt
.VendorClass
->ClassId
,
89 DEFAULT_CLASS_ID_DATA
,
90 sizeof (HTTP_BOOT_CLASS_ID
)
92 HttpBootUintnToAscDecWithFormat (
93 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
,
94 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
95 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
98 if (Private
->Nii
!= NULL
) {
100 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
101 Private
->Nii
->StringId
,
102 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
104 HttpBootUintnToAscDecWithFormat (
105 Private
->Nii
->MajorVer
,
106 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
107 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
109 HttpBootUintnToAscDecWithFormat (
110 Private
->Nii
->MinorVer
,
111 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
112 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
122 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
124 @param[in] Buffer The pointer to the option buffer.
125 @param[in] Length Length of the option buffer.
126 @param[in] OptTag The required option tag.
128 @retval NULL Failed to parse the required option.
129 @retval Others The position of the required option in buffer.
132 EFI_DHCP6_PACKET_OPTION
*
133 HttpBootParseDhcp6Options (
139 EFI_DHCP6_PACKET_OPTION
*Option
;
142 Option
= (EFI_DHCP6_PACKET_OPTION
*)Buffer
;
146 // OpLen and OpCode here are both stored in network order.
148 while (Offset
< Length
) {
149 if (NTOHS (Option
->OpCode
) == OptTag
) {
153 Offset
+= (NTOHS (Option
->OpLen
) + 4);
154 Option
= (EFI_DHCP6_PACKET_OPTION
*)(Buffer
+ Offset
);
161 Parse the cached DHCPv6 packet, including all the options.
163 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
165 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
166 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
170 HttpBootParseDhcp6Packet (
171 IN HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
174 EFI_DHCP6_PACKET
*Offer
;
175 EFI_DHCP6_PACKET_OPTION
**Options
;
176 EFI_DHCP6_PACKET_OPTION
*Option
;
177 HTTP_BOOT_OFFER_TYPE OfferType
;
178 EFI_IPv6_ADDRESS IpAddr
;
179 BOOLEAN IsProxyOffer
;
182 BOOLEAN IpExpressedUri
;
188 IpExpressedUri
= FALSE
;
191 Offer
= &Cache6
->Packet
.Offer
;
192 Options
= Cache6
->OptList
;
194 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
196 Option
= (EFI_DHCP6_PACKET_OPTION
*)(Offer
->Dhcp6
.Option
);
198 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
201 // OpLen and OpCode here are both stored in network order, since they are from original packet.
203 while (Offset
< Length
) {
204 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
205 Options
[HTTP_BOOT_DHCP6_IDX_IA_NA
] = Option
;
206 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
208 // The server sends this option to inform the client about an URL to a boot file.
210 Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
211 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
212 Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
213 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
214 Options
[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS
] = Option
;
215 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
216 Options
[HTTP_BOOT_DHCP6_IDX_DNS_SERVER
] = Option
;
219 Offset
+= (NTOHS (Option
->OpLen
) + 4);
220 Option
= (EFI_DHCP6_PACKET_OPTION
*)(Offer
->Dhcp6
.Option
+ Offset
);
224 // The offer with assigned client address is NOT a proxy offer.
225 // An ia_na option, embedded with valid ia_addr option and a status_code of success.
227 Option
= Options
[HTTP_BOOT_DHCP6_IDX_IA_NA
];
228 if (Option
!= NULL
) {
229 Option
= HttpBootParseDhcp6Options (
231 NTOHS (Option
->OpLen
),
232 DHCP6_OPT_STATUS_CODE
234 if (((Option
!= NULL
) && (Option
->Data
[0] == 0)) || (Option
== NULL
)) {
235 IsProxyOffer
= FALSE
;
240 // The offer with "HTTPClient" is a Http offer.
242 Option
= Options
[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS
];
244 if ((Option
!= NULL
) &&
245 (NTOHS (Option
->OpLen
) >= 16) &&
246 (CompareMem ((Option
->Data
+ 6), DEFAULT_CLASS_ID_DATA
, 10) == 0))
252 // The offer with Domain Server is a DNS offer.
254 Option
= Options
[HTTP_BOOT_DHCP6_IDX_DNS_SERVER
];
255 if (Option
!= NULL
) {
260 // Http offer must have a boot URI.
262 if (IsHttpOffer
&& (Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
] == NULL
)) {
263 return EFI_DEVICE_ERROR
;
267 // Try to retrieve the IP of HTTP server from URI.
270 Status
= HttpParseUrl (
271 (CHAR8
*)Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
,
272 (UINT32
)AsciiStrLen ((CHAR8
*)Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
276 if (EFI_ERROR (Status
)) {
277 return EFI_DEVICE_ERROR
;
280 Status
= HttpUrlGetIp6 (
281 (CHAR8
*)Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
,
285 IpExpressedUri
= !EFI_ERROR (Status
);
289 // Determine offer type of the DHCPv6 packet.
292 if (IpExpressedUri
) {
294 OfferType
= HttpOfferTypeProxyIpUri
;
296 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpIpUriDns
: HttpOfferTypeDhcpIpUri
;
300 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpNameUriDns
: HttpOfferTypeDhcpNameUri
;
302 OfferType
= HttpOfferTypeProxyNameUri
;
307 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpDns
: HttpOfferTypeDhcpOnly
;
309 return EFI_DEVICE_ERROR
;
313 Cache6
->OfferType
= OfferType
;
318 Cache the DHCPv6 packet.
320 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
321 @param[in] Src The pointer to the DHCPv6 packet to be cached.
323 @retval EFI_SUCCESS Packet is copied.
324 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
328 HttpBootCacheDhcp6Packet (
329 IN EFI_DHCP6_PACKET
*Dst
,
330 IN EFI_DHCP6_PACKET
*Src
333 if (Dst
->Size
< Src
->Length
) {
334 return EFI_BUFFER_TOO_SMALL
;
337 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
338 Dst
->Length
= Src
->Length
;
344 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
346 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
347 @param[in] RcvdOffer The pointer to the received offer packet.
349 @retval EFI_SUCCESS Cache and parse the packet successfully.
350 @retval Others Operation failed.
354 HttpBootCacheDhcp6Offer (
355 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
356 IN EFI_DHCP6_PACKET
*RcvdOffer
359 HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
;
360 EFI_DHCP6_PACKET
*Offer
;
361 HTTP_BOOT_OFFER_TYPE OfferType
;
364 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
365 Offer
= &Cache6
->Packet
.Offer
;
368 // Cache the content of DHCPv6 packet firstly.
370 Status
= HttpBootCacheDhcp6Packet (Offer
, RcvdOffer
);
371 if (EFI_ERROR (Status
)) {
376 // Validate the DHCPv6 packet, and parse the options and offer type.
378 if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6
))) {
383 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
385 OfferType
= Cache6
->OfferType
;
386 ASSERT (OfferType
< HttpOfferTypeMax
);
387 ASSERT (Private
->OfferCount
[OfferType
] < HTTP_BOOT_OFFER_MAX_NUM
);
388 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
389 Private
->OfferCount
[OfferType
]++;
396 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
397 to intercept events that occurred in the configuration process.
399 @param[in] This The pointer to the EFI DHCPv6 Protocol.
400 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
401 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
402 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
404 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
405 @param[out] NewPacket The packet that is used to replace the Packet above.
407 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
408 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
409 driver will continue to wait for more packets.
410 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
411 @retval EFI_OUT_OF_RESOURCES There are not enough resources.
416 HttpBootDhcp6CallBack (
417 IN EFI_DHCP6_PROTOCOL
*This
,
419 IN EFI_DHCP6_STATE CurrentState
,
420 IN EFI_DHCP6_EVENT Dhcp6Event
,
421 IN EFI_DHCP6_PACKET
*Packet
,
422 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
425 HTTP_BOOT_PRIVATE_DATA
*Private
;
426 EFI_DHCP6_PACKET
*SelectAd
;
430 if ((Dhcp6Event
!= Dhcp6SendSolicit
) &&
431 (Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
432 (Dhcp6Event
!= Dhcp6SendRequest
) &&
433 (Dhcp6Event
!= Dhcp6RcvdReply
) &&
434 (Dhcp6Event
!= Dhcp6SelectAdvertise
))
439 ASSERT (Packet
!= NULL
);
441 Private
= (HTTP_BOOT_PRIVATE_DATA
*)Context
;
442 Status
= EFI_SUCCESS
;
443 if ((Private
->HttpBootCallback
!= NULL
) && (Dhcp6Event
!= Dhcp6SelectAdvertise
)) {
444 Received
= (BOOLEAN
)(Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
445 Status
= Private
->HttpBootCallback
->Callback (
446 Private
->HttpBootCallback
,
452 if (EFI_ERROR (Status
)) {
457 switch (Dhcp6Event
) {
458 case Dhcp6RcvdAdvertise
:
459 Status
= EFI_NOT_READY
;
460 if (Packet
->Length
> HTTP_BOOT_DHCP6_PACKET_MAX_SIZE
) {
462 // Ignore the incoming packets which exceed the maximum length.
467 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
469 // Cache the dhcp offers to OfferBuffer[] for select later, and record
470 // the OfferIndex and OfferCount.
471 // If error happens, just ignore this packet and continue to wait more offer.
473 HttpBootCacheDhcp6Offer (Private
, Packet
);
478 case Dhcp6SelectAdvertise
:
480 // Select offer by the default policy or by order, and record the SelectIndex
481 // and SelectProxyType.
483 HttpBootSelectDhcpOffer (Private
);
485 if (Private
->SelectIndex
== 0) {
486 Status
= EFI_ABORTED
;
488 ASSERT (NewPacket
!= NULL
);
489 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
490 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
491 if (*NewPacket
== NULL
) {
492 return EFI_OUT_OF_RESOURCES
;
495 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
508 Check whether IP driver could route the message which will be sent to ServerIp address.
510 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
511 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
513 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
514 @param[in] TimeOutInSecond Timeout value in seconds.
515 @param[out] GatewayAddr Pointer to store the gateway IP address.
517 @retval EFI_SUCCESS Found a valid gateway address successfully.
518 @retval EFI_TIMEOUT The operation is time out.
519 @retval Other Unexpected error happened.
523 HttpBootCheckRouteTable (
524 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
525 IN UINTN TimeOutInSecond
,
526 OUT EFI_IPv6_ADDRESS
*GatewayAddr
530 EFI_IP6_PROTOCOL
*Ip6
;
531 EFI_IP6_MODE_DATA Ip6ModeData
;
533 EFI_EVENT TimeOutEvt
;
535 BOOLEAN GatewayIsFound
;
537 ASSERT (GatewayAddr
!= NULL
);
538 ASSERT (Private
!= NULL
);
541 GatewayIsFound
= FALSE
;
544 Status
= EFI_SUCCESS
;
545 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
548 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
549 if (EFI_ERROR (Status
)) {
554 // Find out the gateway address which can route the message which send to ServerIp.
556 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
557 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
558 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
559 GatewayIsFound
= TRUE
;
564 if (Ip6ModeData
.AddressList
!= NULL
) {
565 FreePool (Ip6ModeData
.AddressList
);
568 if (Ip6ModeData
.GroupTable
!= NULL
) {
569 FreePool (Ip6ModeData
.GroupTable
);
572 if (Ip6ModeData
.RouteTable
!= NULL
) {
573 FreePool (Ip6ModeData
.RouteTable
);
576 if (Ip6ModeData
.NeighborCache
!= NULL
) {
577 FreePool (Ip6ModeData
.NeighborCache
);
580 if (Ip6ModeData
.PrefixTable
!= NULL
) {
581 FreePool (Ip6ModeData
.PrefixTable
);
584 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
585 FreePool (Ip6ModeData
.IcmpTypeList
);
588 if (GatewayIsFound
|| (RetryCount
== TimeOutInSecond
)) {
595 // Delay 1 second then recheck it again.
597 if (TimeOutEvt
== NULL
) {
598 Status
= gBS
->CreateEvent (
605 if (EFI_ERROR (Status
)) {
610 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
611 if (EFI_ERROR (Status
)) {
615 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
621 if (TimeOutEvt
!= NULL
) {
622 gBS
->CloseEvent (TimeOutEvt
);
625 if (GatewayIsFound
) {
626 Status
= EFI_SUCCESS
;
627 } else if (RetryCount
== TimeOutInSecond
) {
628 Status
= EFI_TIMEOUT
;
635 Set the IP6 policy to Automatic.
637 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
639 @retval EFI_SUCCESS Switch the IP policy successfully.
640 @retval Others Unexpected error happened.
644 HttpBootSetIp6Policy (
645 IN HTTP_BOOT_PRIVATE_DATA
*Private
648 EFI_IP6_CONFIG_POLICY Policy
;
649 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
653 Ip6Config
= Private
->Ip6Config
;
654 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
657 // Get and store the current policy of IP6 driver.
659 Status
= Ip6Config
->GetData (
661 Ip6ConfigDataTypePolicy
,
665 if (EFI_ERROR (Status
)) {
669 if (Policy
== Ip6ConfigPolicyManual
) {
670 Policy
= Ip6ConfigPolicyAutomatic
;
671 Status
= Ip6Config
->SetData (
673 Ip6ConfigDataTypePolicy
,
674 sizeof (EFI_IP6_CONFIG_POLICY
),
677 if (EFI_ERROR (Status
)) {
686 This function will register the default DNS addresses to the network device.
688 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
689 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
690 @param[in] DnsServerData Point a list of DNS server address in an array
691 of EFI_IPv6_ADDRESS instances.
693 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
694 @retval Others Failed to configure the address.
699 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
701 IN VOID
*DnsServerData
704 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
706 ASSERT (Private
->UsingIpv6
);
708 Ip6Config
= Private
->Ip6Config
;
710 return Ip6Config
->SetData (
712 Ip6ConfigDataTypeDnsServer
,
719 This function will register the IPv6 gateway address to the network device.
721 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
723 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
724 @retval Others Failed to configure the address.
728 HttpBootSetIp6Gateway (
729 IN HTTP_BOOT_PRIVATE_DATA
*Private
732 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
735 ASSERT (Private
->UsingIpv6
);
736 Ip6Config
= Private
->Ip6Config
;
739 // Set the default gateway address.
741 if (!Private
->NoGateway
&& !NetIp6IsUnspecifiedAddr (&Private
->GatewayIp
.v6
)) {
742 Status
= Ip6Config
->SetData (
744 Ip6ConfigDataTypeGateway
,
745 sizeof (EFI_IPv6_ADDRESS
),
746 &Private
->GatewayIp
.v6
748 if (EFI_ERROR (Status
)) {
757 This function will register the station IP address.
759 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
761 @retval EFI_SUCCESS The new IP address has been configured successfully.
762 @retval Others Failed to configure the address.
766 HttpBootSetIp6Address (
767 IN HTTP_BOOT_PRIVATE_DATA
*Private
771 EFI_IP6_PROTOCOL
*Ip6
;
772 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
773 EFI_IP6_CONFIG_POLICY Policy
;
774 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
775 EFI_IPv6_ADDRESS
*Ip6Addr
;
776 EFI_IPv6_ADDRESS GatewayAddr
;
777 EFI_IP6_CONFIG_DATA Ip6CfgData
;
783 ASSERT (Private
->UsingIpv6
);
788 Ip6Cfg
= Private
->Ip6Config
;
791 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
792 CopyMem (&CfgAddr
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
793 ZeroMem (&Ip6CfgData
, sizeof (EFI_IP6_CONFIG_DATA
));
795 Ip6CfgData
.AcceptIcmpErrors
= TRUE
;
796 Ip6CfgData
.DefaultProtocol
= IP6_ICMP
;
797 Ip6CfgData
.HopLimit
= HTTP_BOOT_DEFAULT_HOPLIMIT
;
798 Ip6CfgData
.ReceiveTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
799 Ip6CfgData
.TransmitTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
801 Status
= Ip6
->Configure (Ip6
, &Ip6CfgData
);
802 if (EFI_ERROR (Status
)) {
807 // Retrieve the gateway address from IP6 route table.
809 Status
= HttpBootCheckRouteTable (Private
, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
810 if (EFI_ERROR (Status
)) {
811 Private
->NoGateway
= TRUE
;
813 IP6_COPY_ADDRESS (&Private
->GatewayIp
.v6
, &GatewayAddr
);
817 // Set the new address by Ip6ConfigProtocol manually.
819 Policy
= Ip6ConfigPolicyManual
;
820 Status
= Ip6Cfg
->SetData (
822 Ip6ConfigDataTypePolicy
,
823 sizeof (EFI_IP6_CONFIG_POLICY
),
826 if (EFI_ERROR (Status
)) {
831 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
833 Status
= gBS
->CreateEvent (
836 HttpBootCommonNotify
,
840 if (EFI_ERROR (Status
)) {
845 // Set static host ip6 address. This is a asynchronous process.
847 Status
= Ip6Cfg
->RegisterDataNotify (
849 Ip6ConfigDataTypeManualAddress
,
852 if (EFI_ERROR (Status
)) {
856 Status
= Ip6Cfg
->SetData (
858 Ip6ConfigDataTypeManualAddress
,
859 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
),
862 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
864 } else if (Status
== EFI_NOT_READY
) {
866 // Poll the network until the asynchronous process is finished.
868 while (!IsAddressOk
) {
873 // Check whether the Ip6 Address setting is successed.
876 Status
= Ip6Cfg
->GetData (
878 Ip6ConfigDataTypeManualAddress
,
882 if ((Status
!= EFI_BUFFER_TOO_SMALL
) || (DataSize
== 0)) {
883 Status
= EFI_DEVICE_ERROR
;
887 Ip6Addr
= AllocatePool (DataSize
);
888 if (Ip6Addr
== NULL
) {
889 return EFI_OUT_OF_RESOURCES
;
892 Status
= Ip6Cfg
->GetData (
894 Ip6ConfigDataTypeManualAddress
,
898 if (EFI_ERROR (Status
)) {
899 Status
= EFI_DEVICE_ERROR
;
903 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
904 if (CompareMem (Ip6Addr
+ Index
, &CfgAddr
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
909 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
910 Status
= EFI_ABORTED
;
916 if (MappedEvt
!= NULL
) {
917 Ip6Cfg
->UnregisterDataNotify (
919 Ip6ConfigDataTypeManualAddress
,
922 gBS
->CloseEvent (MappedEvt
);
925 if (Ip6Addr
!= NULL
) {
933 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
935 @param[in] Private Pointer to HTTP_BOOT private data.
937 @retval EFI_SUCCESS The S.A.R.R process successfully finished.
938 @retval Others Failed to finish the S.A.R.R process.
943 IN HTTP_BOOT_PRIVATE_DATA
*Private
946 EFI_DHCP6_PROTOCOL
*Dhcp6
;
947 EFI_DHCP6_CONFIG_DATA Config
;
948 EFI_DHCP6_MODE_DATA Mode
;
949 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
950 EFI_DHCP6_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP6_OPTION_MAX_NUM
];
952 UINT8 Buffer
[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE
];
955 Dhcp6
= Private
->Dhcp6
;
956 ASSERT (Dhcp6
!= NULL
);
959 // Build options list for the request packet.
961 OptCount
= HttpBootBuildDhcp6Options (Private
, OptList
, Buffer
);
962 ASSERT (OptCount
> 0);
964 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
965 if (Retransmit
== NULL
) {
966 return EFI_OUT_OF_RESOURCES
;
969 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
970 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
972 Config
.OptionCount
= OptCount
;
973 Config
.OptionList
= OptList
;
974 Config
.Dhcp6Callback
= HttpBootDhcp6CallBack
;
975 Config
.CallbackContext
= Private
;
976 Config
.IaInfoEvent
= NULL
;
977 Config
.RapidCommit
= FALSE
;
978 Config
.ReconfigureAccept
= FALSE
;
979 Config
.IaDescriptor
.IaId
= NET_RANDOM (NetRandomInitSeed ());
980 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
981 Config
.SolicitRetransmission
= Retransmit
;
984 Retransmit
->Mrt
= 32;
985 Retransmit
->Mrd
= 60;
988 // Configure the DHCPv6 instance for HTTP boot.
990 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
991 FreePool (Retransmit
);
992 if (EFI_ERROR (Status
)) {
997 // Initialize the record fields for DHCPv6 offer in private data.
999 Private
->OfferNum
= 0;
1000 Private
->SelectIndex
= 0;
1001 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
1002 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
1005 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1007 Status
= Dhcp6
->Start (Dhcp6
);
1008 if (EFI_ERROR (Status
)) {
1013 // Get the acquired IPv6 address and store them.
1015 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1016 if (EFI_ERROR (Status
)) {
1020 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1021 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1023 AsciiPrint ("\n Station IPv6 address is ");
1024 HttpBootShowIp6Addr (&Private
->StationIp
.v6
);
1028 if (EFI_ERROR (Status
)) {
1029 Dhcp6
->Stop (Dhcp6
);
1030 Dhcp6
->Configure (Dhcp6
, NULL
);
1032 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1033 Dhcp6
->Configure (Dhcp6
, &Config
);
1034 if (Mode
.ClientId
!= NULL
) {
1035 FreePool (Mode
.ClientId
);
1038 if (Mode
.Ia
!= NULL
) {