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 postion 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
) {
150 if (NTOHS (Option
->OpCode
) == OptTag
) {
155 Offset
+= (NTOHS(Option
->OpLen
) + 4);
156 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
164 Parse the cached DHCPv6 packet, including all the options.
166 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
168 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
169 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
173 HttpBootParseDhcp6Packet (
174 IN HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
177 EFI_DHCP6_PACKET
*Offer
;
178 EFI_DHCP6_PACKET_OPTION
**Options
;
179 EFI_DHCP6_PACKET_OPTION
*Option
;
180 HTTP_BOOT_OFFER_TYPE OfferType
;
181 EFI_IPv6_ADDRESS IpAddr
;
182 BOOLEAN IsProxyOffer
;
185 BOOLEAN IpExpressedUri
;
191 IpExpressedUri
= FALSE
;
194 Offer
= &Cache6
->Packet
.Offer
;
195 Options
= Cache6
->OptList
;
197 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
199 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
201 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
204 // OpLen and OpCode here are both stored in network order, since they are from original packet.
206 while (Offset
< Length
) {
208 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
209 Options
[HTTP_BOOT_DHCP6_IDX_IA_NA
] = Option
;
210 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
212 // The server sends this option to inform the client about an URL to a boot file.
214 Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
215 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
216 Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
217 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
218 Options
[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS
] = Option
;
219 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
220 Options
[HTTP_BOOT_DHCP6_IDX_DNS_SERVER
] = Option
;
223 Offset
+= (NTOHS (Option
->OpLen
) + 4);
224 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
227 // The offer with assigned client address is NOT a proxy offer.
228 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
230 Option
= Options
[HTTP_BOOT_DHCP6_IDX_IA_NA
];
231 if (Option
!= NULL
) {
232 Option
= HttpBootParseDhcp6Options (
234 NTOHS (Option
->OpLen
),
235 DHCP6_OPT_STATUS_CODE
237 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
238 IsProxyOffer
= FALSE
;
243 // The offer with "HTTPClient" is a Http offer.
245 Option
= Options
[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS
];
247 if (Option
!= NULL
&&
248 NTOHS(Option
->OpLen
) >= 16 &&
249 CompareMem ((Option
->Data
+ 6), DEFAULT_CLASS_ID_DATA
, 10) == 0) {
254 // The offer with Domain Server is a DNS offer.
256 Option
= Options
[HTTP_BOOT_DHCP6_IDX_DNS_SERVER
];
257 if (Option
!= NULL
) {
262 // Http offer must have a boot URI.
264 if (IsHttpOffer
&& Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
265 return EFI_DEVICE_ERROR
;
269 // Try to retrieve the IP of HTTP server from URI.
272 Status
= HttpParseUrl (
273 (CHAR8
*) Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
,
274 (UINT32
) AsciiStrLen ((CHAR8
*) Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
278 if (EFI_ERROR (Status
)) {
279 return EFI_DEVICE_ERROR
;
282 Status
= HttpUrlGetIp6 (
283 (CHAR8
*) Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
,
287 IpExpressedUri
= !EFI_ERROR (Status
);
291 // Determine offer type of the DHCPv6 packet.
294 if (IpExpressedUri
) {
296 OfferType
= HttpOfferTypeProxyIpUri
;
298 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpIpUriDns
: HttpOfferTypeDhcpIpUri
;
302 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpNameUriDns
: HttpOfferTypeDhcpNameUri
;
304 OfferType
= HttpOfferTypeProxyNameUri
;
310 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpDns
: HttpOfferTypeDhcpOnly
;
312 return EFI_DEVICE_ERROR
;
316 Cache6
->OfferType
= OfferType
;
321 Cache the DHCPv6 packet.
323 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
324 @param[in] Src The pointer to the DHCPv6 packet to be cached.
326 @retval EFI_SUCCESS Packet is copied.
327 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
331 HttpBootCacheDhcp6Packet (
332 IN EFI_DHCP6_PACKET
*Dst
,
333 IN EFI_DHCP6_PACKET
*Src
336 if (Dst
->Size
< Src
->Length
) {
337 return EFI_BUFFER_TOO_SMALL
;
340 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
341 Dst
->Length
= Src
->Length
;
347 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
349 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
350 @param[in] RcvdOffer The pointer to the received offer packet.
352 @retval EFI_SUCCESS Cache and parse the packet successfully.
353 @retval Others Operation failed.
357 HttpBootCacheDhcp6Offer (
358 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
359 IN EFI_DHCP6_PACKET
*RcvdOffer
362 HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
;
363 EFI_DHCP6_PACKET
*Offer
;
364 HTTP_BOOT_OFFER_TYPE OfferType
;
367 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
368 Offer
= &Cache6
->Packet
.Offer
;
371 // Cache the content of DHCPv6 packet firstly.
373 Status
= HttpBootCacheDhcp6Packet(Offer
, RcvdOffer
);
374 if (EFI_ERROR (Status
)) {
379 // Validate the DHCPv6 packet, and parse the options and offer type.
381 if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6
))) {
386 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
388 OfferType
= Cache6
->OfferType
;
389 ASSERT (OfferType
< HttpOfferTypeMax
);
390 ASSERT (Private
->OfferCount
[OfferType
] < HTTP_BOOT_OFFER_MAX_NUM
);
391 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
392 Private
->OfferCount
[OfferType
]++;
399 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
400 to intercept events that occurred in the configuration process.
402 @param[in] This The pointer to the EFI DHCPv6 Protocol.
403 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
404 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
405 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
407 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
408 @param[out] NewPacket The packet that is used to replace the Packet above.
410 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
411 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
412 driver will continue to wait for more packets.
413 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
414 @retval EFI_OUT_OF_RESOURCES There are not enough resources.
419 HttpBootDhcp6CallBack (
420 IN EFI_DHCP6_PROTOCOL
*This
,
422 IN EFI_DHCP6_STATE CurrentState
,
423 IN EFI_DHCP6_EVENT Dhcp6Event
,
424 IN EFI_DHCP6_PACKET
*Packet
,
425 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
428 HTTP_BOOT_PRIVATE_DATA
*Private
;
429 EFI_DHCP6_PACKET
*SelectAd
;
433 if ((Dhcp6Event
!= Dhcp6SendSolicit
) &&
434 (Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
435 (Dhcp6Event
!= Dhcp6SendRequest
) &&
436 (Dhcp6Event
!= Dhcp6RcvdReply
) &&
437 (Dhcp6Event
!= Dhcp6SelectAdvertise
)) {
441 ASSERT (Packet
!= NULL
);
443 Private
= (HTTP_BOOT_PRIVATE_DATA
*) Context
;
444 Status
= EFI_SUCCESS
;
445 if (Private
->HttpBootCallback
!= NULL
&& Dhcp6Event
!= Dhcp6SelectAdvertise
) {
446 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
447 Status
= Private
->HttpBootCallback
->Callback (
448 Private
->HttpBootCallback
,
454 if (EFI_ERROR (Status
)) {
458 switch (Dhcp6Event
) {
460 case Dhcp6RcvdAdvertise
:
461 Status
= EFI_NOT_READY
;
462 if (Packet
->Length
> HTTP_BOOT_DHCP6_PACKET_MAX_SIZE
) {
464 // Ignore the incoming packets which exceed the maximum length.
468 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
470 // Cache the dhcp offers to OfferBuffer[] for select later, and record
471 // the OfferIndex and OfferCount.
472 // If error happens, just ignore this packet and continue to wait more offer.
474 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
;
494 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
506 Check whether IP driver could route the message which will be sent to ServerIp address.
508 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
509 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
511 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
512 @param[in] TimeOutInSecond Timeout value in seconds.
513 @param[out] GatewayAddr Pointer to store the gateway IP address.
515 @retval EFI_SUCCESS Found a valid gateway address successfully.
516 @retval EFI_TIMEOUT The operation is time out.
517 @retval Other Unexpect error happened.
521 HttpBootCheckRouteTable (
522 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
523 IN UINTN TimeOutInSecond
,
524 OUT EFI_IPv6_ADDRESS
*GatewayAddr
528 EFI_IP6_PROTOCOL
*Ip6
;
529 EFI_IP6_MODE_DATA Ip6ModeData
;
531 EFI_EVENT TimeOutEvt
;
533 BOOLEAN GatewayIsFound
;
535 ASSERT (GatewayAddr
!= NULL
);
536 ASSERT (Private
!= NULL
);
539 GatewayIsFound
= FALSE
;
542 Status
= EFI_SUCCESS
;
543 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
546 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
547 if (EFI_ERROR (Status
)) {
552 // Find out the gateway address which can route the message which send to ServerIp.
554 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
555 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
556 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
557 GatewayIsFound
= TRUE
;
562 if (Ip6ModeData
.AddressList
!= NULL
) {
563 FreePool (Ip6ModeData
.AddressList
);
565 if (Ip6ModeData
.GroupTable
!= NULL
) {
566 FreePool (Ip6ModeData
.GroupTable
);
568 if (Ip6ModeData
.RouteTable
!= NULL
) {
569 FreePool (Ip6ModeData
.RouteTable
);
571 if (Ip6ModeData
.NeighborCache
!= NULL
) {
572 FreePool (Ip6ModeData
.NeighborCache
);
574 if (Ip6ModeData
.PrefixTable
!= NULL
) {
575 FreePool (Ip6ModeData
.PrefixTable
);
577 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
578 FreePool (Ip6ModeData
.IcmpTypeList
);
581 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
588 // Delay 1 second then recheck it again.
590 if (TimeOutEvt
== NULL
) {
591 Status
= gBS
->CreateEvent (
598 if (EFI_ERROR (Status
)) {
603 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
604 if (EFI_ERROR (Status
)) {
607 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
613 if (TimeOutEvt
!= NULL
) {
614 gBS
->CloseEvent (TimeOutEvt
);
617 if (GatewayIsFound
) {
618 Status
= EFI_SUCCESS
;
619 } else if (RetryCount
== TimeOutInSecond
) {
620 Status
= EFI_TIMEOUT
;
627 Set the IP6 policy to Automatic.
629 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
631 @retval EFI_SUCCESS Switch the IP policy succesfully.
632 @retval Others Unexpect error happened.
636 HttpBootSetIp6Policy (
637 IN HTTP_BOOT_PRIVATE_DATA
*Private
640 EFI_IP6_CONFIG_POLICY Policy
;
641 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
645 Ip6Config
= Private
->Ip6Config
;
646 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
649 // Get and store the current policy of IP6 driver.
651 Status
= Ip6Config
->GetData (
653 Ip6ConfigDataTypePolicy
,
657 if (EFI_ERROR (Status
)) {
661 if (Policy
== Ip6ConfigPolicyManual
) {
662 Policy
= Ip6ConfigPolicyAutomatic
;
663 Status
= Ip6Config
->SetData (
665 Ip6ConfigDataTypePolicy
,
666 sizeof(EFI_IP6_CONFIG_POLICY
),
669 if (EFI_ERROR (Status
)) {
677 This function will register the default DNS addresses to the network device.
679 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
680 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
681 @param[in] DnsServerData Point a list of DNS server address in an array
682 of EFI_IPv6_ADDRESS instances.
684 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
685 @retval Others Failed to configure the address.
690 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
692 IN VOID
*DnsServerData
695 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
697 ASSERT (Private
->UsingIpv6
);
699 Ip6Config
= Private
->Ip6Config
;
701 return Ip6Config
->SetData (
703 Ip6ConfigDataTypeDnsServer
,
710 This function will register the IPv6 gateway address to the network device.
712 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
714 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
715 @retval Others Failed to configure the address.
719 HttpBootSetIp6Gateway (
720 IN HTTP_BOOT_PRIVATE_DATA
*Private
723 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
726 ASSERT (Private
->UsingIpv6
);
727 Ip6Config
= Private
->Ip6Config
;
730 // Set the default gateway address.
732 if (!Private
->NoGateway
&& !NetIp6IsUnspecifiedAddr (&Private
->GatewayIp
.v6
)) {
733 Status
= Ip6Config
->SetData (
735 Ip6ConfigDataTypeGateway
,
736 sizeof (EFI_IPv6_ADDRESS
),
737 &Private
->GatewayIp
.v6
739 if (EFI_ERROR(Status
)) {
748 This function will register the station IP address.
750 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
752 @retval EFI_SUCCESS The new IP address has been configured successfully.
753 @retval Others Failed to configure the address.
757 HttpBootSetIp6Address (
758 IN HTTP_BOOT_PRIVATE_DATA
*Private
762 EFI_IP6_PROTOCOL
*Ip6
;
763 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
764 EFI_IP6_CONFIG_POLICY Policy
;
765 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
766 EFI_IPv6_ADDRESS
*Ip6Addr
;
767 EFI_IPv6_ADDRESS GatewayAddr
;
768 EFI_IP6_CONFIG_DATA Ip6CfgData
;
774 ASSERT (Private
->UsingIpv6
);
779 Ip6Cfg
= Private
->Ip6Config
;
782 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
783 CopyMem (&CfgAddr
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
784 ZeroMem (&Ip6CfgData
, sizeof (EFI_IP6_CONFIG_DATA
));
786 Ip6CfgData
.AcceptIcmpErrors
= TRUE
;
787 Ip6CfgData
.DefaultProtocol
= IP6_ICMP
;
788 Ip6CfgData
.HopLimit
= HTTP_BOOT_DEFAULT_HOPLIMIT
;
789 Ip6CfgData
.ReceiveTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
790 Ip6CfgData
.TransmitTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
792 Status
= Ip6
->Configure (Ip6
, &Ip6CfgData
);
793 if (EFI_ERROR (Status
)) {
798 // Retrieve the gateway address from IP6 route table.
800 Status
= HttpBootCheckRouteTable (Private
, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
801 if (EFI_ERROR (Status
)) {
802 Private
->NoGateway
= TRUE
;
804 IP6_COPY_ADDRESS (&Private
->GatewayIp
.v6
, &GatewayAddr
);
808 // Set the new address by Ip6ConfigProtocol manually.
810 Policy
= Ip6ConfigPolicyManual
;
811 Status
= Ip6Cfg
->SetData (
813 Ip6ConfigDataTypePolicy
,
814 sizeof(EFI_IP6_CONFIG_POLICY
),
817 if (EFI_ERROR (Status
)) {
822 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
824 Status
= gBS
->CreateEvent (
827 HttpBootCommonNotify
,
831 if (EFI_ERROR (Status
)) {
836 // Set static host ip6 address. This is a asynchronous process.
838 Status
= Ip6Cfg
->RegisterDataNotify (
840 Ip6ConfigDataTypeManualAddress
,
843 if (EFI_ERROR(Status
)) {
847 Status
= Ip6Cfg
->SetData (
849 Ip6ConfigDataTypeManualAddress
,
850 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
),
853 if (EFI_ERROR (Status
) && Status
!= EFI_NOT_READY
) {
855 } else if (Status
== EFI_NOT_READY
) {
857 // Poll the network until the asynchronous process is finished.
859 while (!IsAddressOk
) {
863 // Check whether the Ip6 Address setting is successed.
866 Status
= Ip6Cfg
->GetData (
868 Ip6ConfigDataTypeManualAddress
,
872 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
873 Status
= EFI_DEVICE_ERROR
;
877 Ip6Addr
= AllocatePool (DataSize
);
878 if (Ip6Addr
== NULL
) {
879 return EFI_OUT_OF_RESOURCES
;
881 Status
= Ip6Cfg
->GetData (
883 Ip6ConfigDataTypeManualAddress
,
887 if (EFI_ERROR (Status
)) {
888 Status
= EFI_DEVICE_ERROR
;
892 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
893 if (CompareMem (Ip6Addr
+ Index
, &CfgAddr
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
897 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
898 Status
= EFI_ABORTED
;
904 if (MappedEvt
!= NULL
) {
905 Ip6Cfg
->UnregisterDataNotify (
907 Ip6ConfigDataTypeManualAddress
,
910 gBS
->CloseEvent (MappedEvt
);
913 if (Ip6Addr
!= NULL
) {
921 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
923 @param[in] Private Pointer to HTTP_BOOT private data.
925 @retval EFI_SUCCESS The S.A.R.R process successfully finished.
926 @retval Others Failed to finish the S.A.R.R process.
931 IN HTTP_BOOT_PRIVATE_DATA
*Private
934 EFI_DHCP6_PROTOCOL
*Dhcp6
;
935 EFI_DHCP6_CONFIG_DATA Config
;
936 EFI_DHCP6_MODE_DATA Mode
;
937 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
938 EFI_DHCP6_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP6_OPTION_MAX_NUM
];
940 UINT8 Buffer
[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE
];
943 Dhcp6
= Private
->Dhcp6
;
944 ASSERT (Dhcp6
!= NULL
);
947 // Build options list for the request packet.
949 OptCount
= HttpBootBuildDhcp6Options (Private
, OptList
, Buffer
);
950 ASSERT (OptCount
>0);
952 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
953 if (Retransmit
== NULL
) {
954 return EFI_OUT_OF_RESOURCES
;
957 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
958 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
960 Config
.OptionCount
= OptCount
;
961 Config
.OptionList
= OptList
;
962 Config
.Dhcp6Callback
= HttpBootDhcp6CallBack
;
963 Config
.CallbackContext
= Private
;
964 Config
.IaInfoEvent
= NULL
;
965 Config
.RapidCommit
= FALSE
;
966 Config
.ReconfigureAccept
= FALSE
;
967 Config
.IaDescriptor
.IaId
= NET_RANDOM (NetRandomInitSeed ());
968 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
969 Config
.SolicitRetransmission
= Retransmit
;
972 Retransmit
->Mrt
= 32;
973 Retransmit
->Mrd
= 60;
976 // Configure the DHCPv6 instance for HTTP boot.
978 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
979 FreePool (Retransmit
);
980 if (EFI_ERROR (Status
)) {
984 // Initialize the record fields for DHCPv6 offer in private data.
986 Private
->OfferNum
= 0;
987 Private
->SelectIndex
= 0;
988 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
989 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
992 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
994 Status
= Dhcp6
->Start (Dhcp6
);
995 if (EFI_ERROR (Status
)) {
1000 // Get the acquired IPv6 address and store them.
1002 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1003 if (EFI_ERROR (Status
)) {
1007 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1008 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1010 AsciiPrint ("\n Station IPv6 address is ");
1011 HttpBootShowIp6Addr (&Private
->StationIp
.v6
);
1015 if (EFI_ERROR (Status
)) {
1016 Dhcp6
->Stop (Dhcp6
);
1017 Dhcp6
->Configure (Dhcp6
, NULL
);
1019 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1020 Dhcp6
->Configure (Dhcp6
, &Config
);
1021 if (Mode
.ClientId
!= NULL
) {
1022 FreePool (Mode
.ClientId
);
1024 if (Mode
.Ia
!= NULL
) {