2 Functions implementation related with DHCPv6 for HTTP boot driver.
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "HttpBootDxe.h"
18 Build the options buffer for the DHCPv6 request packet.
20 @param[in] Private The pointer to HTTP BOOT driver private data.
21 @param[out] OptList The pointer to the option pointer array.
22 @param[in] Buffer The pointer to the buffer to contain the option list.
24 @return Index The count of the built-in options.
28 HttpBootBuildDhcp6Options (
29 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
30 OUT EFI_DHCP6_PACKET_OPTION
**OptList
,
34 HTTP_BOOT_DHCP6_OPTION_ENTRY OptEnt
;
39 OptList
[0] = (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
42 // Append client option request option
44 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ORO
);
45 OptList
[Index
]->OpLen
= HTONS (8);
46 OptEnt
.Oro
= (HTTP_BOOT_DHCP6_OPTION_ORO
*) OptList
[Index
]->Data
;
47 OptEnt
.Oro
->OpCode
[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL
);
48 OptEnt
.Oro
->OpCode
[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM
);
49 OptEnt
.Oro
->OpCode
[2] = HTONS(DHCP6_OPT_DNS_SERVERS
);
50 OptEnt
.Oro
->OpCode
[3] = HTONS(DHCP6_OPT_VENDOR_CLASS
);
52 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
55 // Append client network device interface option
57 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_UNDI
);
58 OptList
[Index
]->OpLen
= HTONS ((UINT16
)3);
59 OptEnt
.Undi
= (HTTP_BOOT_DHCP6_OPTION_UNDI
*) OptList
[Index
]->Data
;
61 if (Private
->Nii
!= NULL
) {
62 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
63 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
64 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
66 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
67 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
68 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
72 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
75 // Append client system architecture option
77 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_ARCH
);
78 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH
));
79 OptEnt
.Arch
= (HTTP_BOOT_DHCP6_OPTION_ARCH
*) OptList
[Index
]->Data
;
80 Value
= HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
);
81 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
83 OptList
[Index
] = GET_NEXT_DHCP6_OPTION (OptList
[Index
- 1]);
86 // Append vendor class identify option.
88 OptList
[Index
]->OpCode
= HTONS (DHCP6_OPT_VENDOR_CLASS
);
89 OptList
[Index
]->OpLen
= HTONS ((UINT16
) sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS
));
90 OptEnt
.VendorClass
= (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS
*) OptList
[Index
]->Data
;
91 OptEnt
.VendorClass
->Vendor
= HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM
);
92 OptEnt
.VendorClass
->ClassLen
= HTONS ((UINT16
) sizeof (HTTP_BOOT_CLASS_ID
));
94 &OptEnt
.VendorClass
->ClassId
,
95 DEFAULT_CLASS_ID_DATA
,
96 sizeof (HTTP_BOOT_CLASS_ID
)
98 HttpBootUintnToAscDecWithFormat (
99 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
,
100 OptEnt
.VendorClass
->ClassId
.ArchitectureType
,
101 sizeof (OptEnt
.VendorClass
->ClassId
.ArchitectureType
)
104 if (Private
->Nii
!= NULL
) {
106 OptEnt
.VendorClass
->ClassId
.InterfaceName
,
107 Private
->Nii
->StringId
,
108 sizeof (OptEnt
.VendorClass
->ClassId
.InterfaceName
)
110 HttpBootUintnToAscDecWithFormat (
111 Private
->Nii
->MajorVer
,
112 OptEnt
.VendorClass
->ClassId
.UndiMajor
,
113 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMajor
)
115 HttpBootUintnToAscDecWithFormat (
116 Private
->Nii
->MinorVer
,
117 OptEnt
.VendorClass
->ClassId
.UndiMinor
,
118 sizeof (OptEnt
.VendorClass
->ClassId
.UndiMinor
)
128 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
130 @param[in] Buffer The pointer to the option buffer.
131 @param[in] Length Length of the option buffer.
132 @param[in] OptTag The required option tag.
134 @retval NULL Failed to parse the required option.
135 @retval Others The postion of the required option in buffer.
138 EFI_DHCP6_PACKET_OPTION
*
139 HttpBootParseDhcp6Options (
145 EFI_DHCP6_PACKET_OPTION
*Option
;
148 Option
= (EFI_DHCP6_PACKET_OPTION
*) Buffer
;
152 // OpLen and OpCode here are both stored in network order.
154 while (Offset
< Length
) {
156 if (NTOHS (Option
->OpCode
) == OptTag
) {
161 Offset
+= (NTOHS(Option
->OpLen
) + 4);
162 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Buffer
+ Offset
);
170 Parse the cached DHCPv6 packet, including all the options.
172 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
174 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
175 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
179 HttpBootParseDhcp6Packet (
180 IN HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
183 EFI_DHCP6_PACKET
*Offer
;
184 EFI_DHCP6_PACKET_OPTION
**Options
;
185 EFI_DHCP6_PACKET_OPTION
*Option
;
186 HTTP_BOOT_OFFER_TYPE OfferType
;
187 EFI_IPv6_ADDRESS IpAddr
;
188 BOOLEAN IsProxyOffer
;
191 BOOLEAN IpExpressedUri
;
197 IpExpressedUri
= FALSE
;
200 Offer
= &Cache6
->Packet
.Offer
;
201 Options
= Cache6
->OptList
;
203 ZeroMem (Cache6
->OptList
, sizeof (Cache6
->OptList
));
205 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
);
207 Length
= GET_DHCP6_OPTION_SIZE (Offer
);
210 // OpLen and OpCode here are both stored in network order, since they are from original packet.
212 while (Offset
< Length
) {
214 if (NTOHS (Option
->OpCode
) == DHCP6_OPT_IA_NA
) {
215 Options
[HTTP_BOOT_DHCP6_IDX_IA_NA
] = Option
;
216 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_URL
) {
218 // The server sends this option to inform the client about an URL to a boot file.
220 Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
] = Option
;
221 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_BOOT_FILE_PARAM
) {
222 Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM
] = Option
;
223 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_VENDOR_CLASS
) {
224 Options
[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS
] = Option
;
225 } else if (NTOHS (Option
->OpCode
) == DHCP6_OPT_DNS_SERVERS
) {
226 Options
[HTTP_BOOT_DHCP6_IDX_DNS_SERVER
] = Option
;
229 Offset
+= (NTOHS (Option
->OpLen
) + 4);
230 Option
= (EFI_DHCP6_PACKET_OPTION
*) (Offer
->Dhcp6
.Option
+ Offset
);
233 // The offer with assigned client address is NOT a proxy offer.
234 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
236 Option
= Options
[HTTP_BOOT_DHCP6_IDX_IA_NA
];
237 if (Option
!= NULL
) {
238 Option
= HttpBootParseDhcp6Options (
240 NTOHS (Option
->OpLen
),
241 DHCP6_OPT_STATUS_CODE
243 if ((Option
!= NULL
&& Option
->Data
[0] == 0) || (Option
== NULL
)) {
244 IsProxyOffer
= FALSE
;
249 // The offer with "HTTPClient" is a Http offer.
251 Option
= Options
[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS
];
253 if (Option
!= NULL
&&
254 NTOHS(Option
->OpLen
) >= 16 &&
255 CompareMem ((Option
->Data
+ 6), DEFAULT_CLASS_ID_DATA
, 10) == 0) {
260 // The offer with Domain Server is a DNS offer.
262 Option
= Options
[HTTP_BOOT_DHCP6_IDX_DNS_SERVER
];
263 if (Option
!= NULL
) {
268 // Http offer must have a boot URI.
270 if (IsHttpOffer
&& Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
] == NULL
) {
271 return EFI_DEVICE_ERROR
;
275 // Try to retrieve the IP of HTTP server from URI.
278 Status
= HttpParseUrl (
279 (CHAR8
*) Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
,
280 (UINT32
) AsciiStrLen ((CHAR8
*) Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
284 if (EFI_ERROR (Status
)) {
285 return EFI_DEVICE_ERROR
;
288 Status
= HttpUrlGetIp6 (
289 (CHAR8
*) Options
[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL
]->Data
,
293 IpExpressedUri
= !EFI_ERROR (Status
);
297 // Determine offer type of the DHCPv6 packet.
300 if (IpExpressedUri
) {
302 OfferType
= HttpOfferTypeProxyIpUri
;
304 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpIpUriDns
: HttpOfferTypeDhcpIpUri
;
308 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpNameUriDns
: HttpOfferTypeDhcpNameUri
;
310 OfferType
= HttpOfferTypeProxyNameUri
;
316 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpDns
: HttpOfferTypeDhcpOnly
;
318 return EFI_DEVICE_ERROR
;
322 Cache6
->OfferType
= OfferType
;
327 Cache the DHCPv6 packet.
329 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
330 @param[in] Src The pointer to the DHCPv6 packet to be cached.
334 HttpBootCacheDhcp6Packet (
335 IN EFI_DHCP6_PACKET
*Dst
,
336 IN EFI_DHCP6_PACKET
*Src
339 ASSERT (Dst
->Size
>= Src
->Length
);
341 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
342 Dst
->Length
= Src
->Length
;
346 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
348 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
349 @param[in] RcvdOffer The pointer to the received offer packet.
353 HttpBootCacheDhcp6Offer (
354 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
355 IN EFI_DHCP6_PACKET
*RcvdOffer
358 HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
;
359 EFI_DHCP6_PACKET
*Offer
;
360 HTTP_BOOT_OFFER_TYPE OfferType
;
362 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
363 Offer
= &Cache6
->Packet
.Offer
;
366 // Cache the content of DHCPv6 packet firstly.
368 HttpBootCacheDhcp6Packet(Offer
, RcvdOffer
);
371 // Validate the DHCPv6 packet, and parse the options and offer type.
373 if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6
))) {
378 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
380 OfferType
= Cache6
->OfferType
;
381 ASSERT (OfferType
< HttpOfferTypeMax
);
382 ASSERT (Private
->OfferCount
[OfferType
] < HTTP_BOOT_OFFER_MAX_NUM
);
383 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
384 Private
->OfferCount
[OfferType
]++;
389 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
390 to intercept events that occurred in the configuration process.
392 @param[in] This The pointer to the EFI DHCPv6 Protocol.
393 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
394 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
395 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
397 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
398 @param[out] NewPacket The packet that is used to replace the Packet above.
400 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
401 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
402 driver will continue to wait for more packets.
403 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
404 @retval EFI_OUT_OF_RESOURCES There are not enough resources.
409 HttpBootDhcp6CallBack (
410 IN EFI_DHCP6_PROTOCOL
*This
,
412 IN EFI_DHCP6_STATE CurrentState
,
413 IN EFI_DHCP6_EVENT Dhcp6Event
,
414 IN EFI_DHCP6_PACKET
*Packet
,
415 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
418 HTTP_BOOT_PRIVATE_DATA
*Private
;
419 EFI_DHCP6_PACKET
*SelectAd
;
421 if ((Dhcp6Event
!= Dhcp6RcvdAdvertise
) && (Dhcp6Event
!= Dhcp6SelectAdvertise
)) {
425 ASSERT (Packet
!= NULL
);
427 Private
= (HTTP_BOOT_PRIVATE_DATA
*) Context
;
428 Status
= EFI_SUCCESS
;
429 switch (Dhcp6Event
) {
431 case Dhcp6RcvdAdvertise
:
432 Status
= EFI_NOT_READY
;
433 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
435 // Cache the dhcp offers to OfferBuffer[] for select later, and record
436 // the OfferIndex and OfferCount.
438 HttpBootCacheDhcp6Offer (Private
, Packet
);
442 case Dhcp6SelectAdvertise
:
444 // Select offer by the default policy or by order, and record the SelectIndex
445 // and SelectProxyType.
447 HttpBootSelectDhcpOffer (Private
);
449 if (Private
->SelectIndex
== 0) {
450 Status
= EFI_ABORTED
;
452 ASSERT (NewPacket
!= NULL
);
453 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
454 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
455 if (*NewPacket
== NULL
) {
456 return EFI_OUT_OF_RESOURCES
;
458 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
470 Check whether IP driver could route the message which will be sent to ServerIp address.
472 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
473 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
475 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
476 @param[in] TimeOutInSecond Timeout value in seconds.
477 @param[out] GatewayAddr Pointer to store the gateway IP address.
479 @retval EFI_SUCCESS Found a valid gateway address successfully.
480 @retval EFI_TIMEOUT The operation is time out.
481 @retval Other Unexpect error happened.
485 HttpBootCheckRouteTable (
486 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
487 IN UINTN TimeOutInSecond
,
488 OUT EFI_IPv6_ADDRESS
*GatewayAddr
492 EFI_IP6_PROTOCOL
*Ip6
;
493 EFI_IP6_MODE_DATA Ip6ModeData
;
495 EFI_EVENT TimeOutEvt
;
497 BOOLEAN GatewayIsFound
;
499 ASSERT (GatewayAddr
!= NULL
);
500 ASSERT (Private
!= NULL
);
503 GatewayIsFound
= FALSE
;
506 Status
= EFI_SUCCESS
;
507 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
510 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
511 if (EFI_ERROR (Status
)) {
516 // Find out the gateway address which can route the message which send to ServerIp.
518 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
519 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
520 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
521 GatewayIsFound
= TRUE
;
526 if (Ip6ModeData
.AddressList
!= NULL
) {
527 FreePool (Ip6ModeData
.AddressList
);
529 if (Ip6ModeData
.GroupTable
!= NULL
) {
530 FreePool (Ip6ModeData
.GroupTable
);
532 if (Ip6ModeData
.RouteTable
!= NULL
) {
533 FreePool (Ip6ModeData
.RouteTable
);
535 if (Ip6ModeData
.NeighborCache
!= NULL
) {
536 FreePool (Ip6ModeData
.NeighborCache
);
538 if (Ip6ModeData
.PrefixTable
!= NULL
) {
539 FreePool (Ip6ModeData
.PrefixTable
);
541 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
542 FreePool (Ip6ModeData
.IcmpTypeList
);
545 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
552 // Delay 1 second then recheck it again.
554 if (TimeOutEvt
== NULL
) {
555 Status
= gBS
->CreateEvent (
562 if (EFI_ERROR (Status
)) {
567 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
568 if (EFI_ERROR (Status
)) {
571 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
577 if (TimeOutEvt
!= NULL
) {
578 gBS
->CloseEvent (TimeOutEvt
);
581 if (GatewayIsFound
) {
582 Status
= EFI_SUCCESS
;
583 } else if (RetryCount
== TimeOutInSecond
) {
584 Status
= EFI_TIMEOUT
;
591 Set the IP6 policy to Automatic.
593 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
595 @retval EFI_SUCCESS Switch the IP policy succesfully.
596 @retval Others Unexpect error happened.
600 HttpBootSetIp6Policy (
601 IN HTTP_BOOT_PRIVATE_DATA
*Private
604 EFI_IP6_CONFIG_POLICY Policy
;
605 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
609 Ip6Config
= Private
->Ip6Config
;
610 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
613 // Get and store the current policy of IP6 driver.
615 Status
= Ip6Config
->GetData (
617 Ip6ConfigDataTypePolicy
,
621 if (EFI_ERROR (Status
)) {
625 if (Policy
== Ip6ConfigPolicyManual
) {
626 Policy
= Ip6ConfigPolicyAutomatic
;
627 Status
= Ip6Config
->SetData (
629 Ip6ConfigDataTypePolicy
,
630 sizeof(EFI_IP6_CONFIG_POLICY
),
633 if (EFI_ERROR (Status
)) {
641 This function will register the default DNS addresses to the network device.
643 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
644 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
645 @param[in] DnsServerData Point a list of DNS server address in an array
646 of EFI_IPv6_ADDRESS instances.
648 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
649 @retval Others Failed to configure the address.
654 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
656 IN VOID
*DnsServerData
659 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
661 ASSERT (Private
->UsingIpv6
);
663 Ip6Config
= Private
->Ip6Config
;
665 return Ip6Config
->SetData (
667 Ip6ConfigDataTypeDnsServer
,
674 This function will register the IPv6 gateway address to the network device.
676 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
678 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
679 @retval Others Failed to configure the address.
683 HttpBootSetIp6Gateway (
684 IN HTTP_BOOT_PRIVATE_DATA
*Private
687 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
690 ASSERT (Private
->UsingIpv6
);
691 Ip6Config
= Private
->Ip6Config
;
694 // Set the default gateway address.
696 if (!Private
->NoGateway
&& !NetIp6IsUnspecifiedAddr (&Private
->GatewayIp
.v6
)) {
697 Status
= Ip6Config
->SetData (
699 Ip6ConfigDataTypeGateway
,
700 sizeof (EFI_IPv6_ADDRESS
),
701 &Private
->GatewayIp
.v6
703 if (EFI_ERROR(Status
)) {
712 This function will register the station IP address.
714 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
716 @retval EFI_SUCCESS The new IP address has been configured successfully.
717 @retval Others Failed to configure the address.
721 HttpBootSetIp6Address (
722 IN HTTP_BOOT_PRIVATE_DATA
*Private
726 EFI_IP6_PROTOCOL
*Ip6
;
727 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
728 EFI_IP6_CONFIG_POLICY Policy
;
729 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
730 EFI_IPv6_ADDRESS
*Ip6Addr
;
731 EFI_IPv6_ADDRESS GatewayAddr
;
732 EFI_IP6_CONFIG_DATA Ip6CfgData
;
738 ASSERT (Private
->UsingIpv6
);
743 Ip6Cfg
= Private
->Ip6Config
;
746 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
747 CopyMem (&CfgAddr
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
748 ZeroMem (&Ip6CfgData
, sizeof (EFI_IP6_CONFIG_DATA
));
750 Ip6CfgData
.AcceptIcmpErrors
= TRUE
;
751 Ip6CfgData
.DefaultProtocol
= IP6_ICMP
;
752 Ip6CfgData
.HopLimit
= HTTP_BOOT_DEFAULT_HOPLIMIT
;
753 Ip6CfgData
.ReceiveTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
754 Ip6CfgData
.TransmitTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
756 Status
= Ip6
->Configure (Ip6
, &Ip6CfgData
);
757 if (EFI_ERROR (Status
)) {
762 // Retrieve the gateway address from IP6 route table.
764 Status
= HttpBootCheckRouteTable (Private
, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
765 if (EFI_ERROR (Status
)) {
766 Private
->NoGateway
= TRUE
;
768 IP6_COPY_ADDRESS (&Private
->GatewayIp
.v6
, &GatewayAddr
);
772 // Set the new address by Ip6ConfigProtocol manually.
774 Policy
= Ip6ConfigPolicyManual
;
775 Status
= Ip6Cfg
->SetData (
777 Ip6ConfigDataTypePolicy
,
778 sizeof(EFI_IP6_CONFIG_POLICY
),
781 if (EFI_ERROR (Status
)) {
786 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
788 Status
= gBS
->CreateEvent (
791 HttpBootCommonNotify
,
795 if (EFI_ERROR (Status
)) {
800 // Set static host ip6 address. This is a asynchronous process.
802 Status
= Ip6Cfg
->RegisterDataNotify (
804 Ip6ConfigDataTypeManualAddress
,
807 if (EFI_ERROR(Status
)) {
811 Status
= Ip6Cfg
->SetData (
813 Ip6ConfigDataTypeManualAddress
,
814 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
),
817 if (EFI_ERROR (Status
) && Status
!= EFI_NOT_READY
) {
819 } else if (Status
== EFI_NOT_READY
) {
821 // Poll the network until the asynchronous process is finished.
823 while (!IsAddressOk
) {
827 // Check whether the Ip6 Address setting is successed.
830 Status
= Ip6Cfg
->GetData (
832 Ip6ConfigDataTypeManualAddress
,
836 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
837 Status
= EFI_DEVICE_ERROR
;
841 Ip6Addr
= AllocatePool (DataSize
);
842 if (Ip6Addr
== NULL
) {
843 return EFI_OUT_OF_RESOURCES
;
845 Status
= Ip6Cfg
->GetData (
847 Ip6ConfigDataTypeManualAddress
,
851 if (EFI_ERROR (Status
)) {
852 Status
= EFI_DEVICE_ERROR
;
856 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
857 if (CompareMem (Ip6Addr
+ Index
, &CfgAddr
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
861 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
862 Status
= EFI_ABORTED
;
868 if (MappedEvt
!= NULL
) {
869 Ip6Cfg
->UnregisterDataNotify (
871 Ip6ConfigDataTypeManualAddress
,
874 gBS
->CloseEvent (MappedEvt
);
877 if (Ip6Addr
!= NULL
) {
885 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
887 @param[in] Private Pointer to HTTP_BOOT private data.
889 @retval EFI_SUCCESS The S.A.R.R process successfully finished.
890 @retval Others Failed to finish the S.A.R.R process.
895 IN HTTP_BOOT_PRIVATE_DATA
*Private
898 EFI_DHCP6_PROTOCOL
*Dhcp6
;
899 EFI_DHCP6_CONFIG_DATA Config
;
900 EFI_DHCP6_MODE_DATA Mode
;
901 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
902 EFI_DHCP6_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP6_OPTION_MAX_NUM
];
904 UINT8 Buffer
[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE
];
907 Dhcp6
= Private
->Dhcp6
;
908 ASSERT (Dhcp6
!= NULL
);
911 // Build options list for the request packet.
913 OptCount
= HttpBootBuildDhcp6Options (Private
, OptList
, Buffer
);
914 ASSERT (OptCount
>0);
916 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
917 if (Retransmit
== NULL
) {
918 return EFI_OUT_OF_RESOURCES
;
921 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
922 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
924 Config
.OptionCount
= OptCount
;
925 Config
.OptionList
= OptList
;
926 Config
.Dhcp6Callback
= HttpBootDhcp6CallBack
;
927 Config
.CallbackContext
= Private
;
928 Config
.IaInfoEvent
= NULL
;
929 Config
.RapidCommit
= FALSE
;
930 Config
.ReconfigureAccept
= FALSE
;
931 Config
.IaDescriptor
.IaId
= NET_RANDOM (NetRandomInitSeed ());
932 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
933 Config
.SolicitRetransmission
= Retransmit
;
936 Retransmit
->Mrt
= 32;
937 Retransmit
->Mrd
= 60;
940 // Configure the DHCPv6 instance for HTTP boot.
942 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
943 FreePool (Retransmit
);
944 if (EFI_ERROR (Status
)) {
948 // Initialize the record fields for DHCPv6 offer in private data.
950 Private
->OfferNum
= 0;
951 Private
->SelectIndex
= 0;
952 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
953 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
956 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
958 Status
= Dhcp6
->Start (Dhcp6
);
959 if (EFI_ERROR (Status
)) {
964 // Get the acquired IPv6 address and store them.
966 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
967 if (EFI_ERROR (Status
)) {
971 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
972 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
974 AsciiPrint ("\n Station IPv6 address is ");
975 HttpBootShowIp6Addr (&Private
->StationIp
.v6
);
979 if (EFI_ERROR (Status
)) {
981 Dhcp6
->Configure (Dhcp6
, NULL
);
983 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
984 Dhcp6
->Configure (Dhcp6
, &Config
);
985 if (Mode
.ClientId
!= NULL
) {
986 FreePool (Mode
.ClientId
);
988 if (Mode
.Ia
!= NULL
) {