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
;
422 ASSERT (Packet
!= NULL
);
424 Private
= (HTTP_BOOT_PRIVATE_DATA
*) Context
;
425 Status
= EFI_SUCCESS
;
426 switch (Dhcp6Event
) {
428 case Dhcp6RcvdAdvertise
:
429 Status
= EFI_NOT_READY
;
430 if (Packet
->Length
> HTTP_BOOT_DHCP6_PACKET_MAX_SIZE
) {
432 // Ignore the incoming packets which exceed the maximum length.
436 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
438 // Cache the dhcp offers to OfferBuffer[] for select later, and record
439 // the OfferIndex and OfferCount.
441 HttpBootCacheDhcp6Offer (Private
, Packet
);
445 case Dhcp6SelectAdvertise
:
447 // Select offer by the default policy or by order, and record the SelectIndex
448 // and SelectProxyType.
450 HttpBootSelectDhcpOffer (Private
);
452 if (Private
->SelectIndex
== 0) {
453 Status
= EFI_ABORTED
;
455 ASSERT (NewPacket
!= NULL
);
456 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
457 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
458 if (*NewPacket
== NULL
) {
459 return EFI_OUT_OF_RESOURCES
;
461 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
473 Check whether IP driver could route the message which will be sent to ServerIp address.
475 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
476 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
478 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
479 @param[in] TimeOutInSecond Timeout value in seconds.
480 @param[out] GatewayAddr Pointer to store the gateway IP address.
482 @retval EFI_SUCCESS Found a valid gateway address successfully.
483 @retval EFI_TIMEOUT The operation is time out.
484 @retval Other Unexpect error happened.
488 HttpBootCheckRouteTable (
489 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
490 IN UINTN TimeOutInSecond
,
491 OUT EFI_IPv6_ADDRESS
*GatewayAddr
495 EFI_IP6_PROTOCOL
*Ip6
;
496 EFI_IP6_MODE_DATA Ip6ModeData
;
498 EFI_EVENT TimeOutEvt
;
500 BOOLEAN GatewayIsFound
;
502 ASSERT (GatewayAddr
!= NULL
);
503 ASSERT (Private
!= NULL
);
506 GatewayIsFound
= FALSE
;
509 Status
= EFI_SUCCESS
;
510 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
513 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
514 if (EFI_ERROR (Status
)) {
519 // Find out the gateway address which can route the message which send to ServerIp.
521 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
522 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
523 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
524 GatewayIsFound
= TRUE
;
529 if (Ip6ModeData
.AddressList
!= NULL
) {
530 FreePool (Ip6ModeData
.AddressList
);
532 if (Ip6ModeData
.GroupTable
!= NULL
) {
533 FreePool (Ip6ModeData
.GroupTable
);
535 if (Ip6ModeData
.RouteTable
!= NULL
) {
536 FreePool (Ip6ModeData
.RouteTable
);
538 if (Ip6ModeData
.NeighborCache
!= NULL
) {
539 FreePool (Ip6ModeData
.NeighborCache
);
541 if (Ip6ModeData
.PrefixTable
!= NULL
) {
542 FreePool (Ip6ModeData
.PrefixTable
);
544 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
545 FreePool (Ip6ModeData
.IcmpTypeList
);
548 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
555 // Delay 1 second then recheck it again.
557 if (TimeOutEvt
== NULL
) {
558 Status
= gBS
->CreateEvent (
565 if (EFI_ERROR (Status
)) {
570 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
571 if (EFI_ERROR (Status
)) {
574 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
580 if (TimeOutEvt
!= NULL
) {
581 gBS
->CloseEvent (TimeOutEvt
);
584 if (GatewayIsFound
) {
585 Status
= EFI_SUCCESS
;
586 } else if (RetryCount
== TimeOutInSecond
) {
587 Status
= EFI_TIMEOUT
;
594 Set the IP6 policy to Automatic.
596 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
598 @retval EFI_SUCCESS Switch the IP policy succesfully.
599 @retval Others Unexpect error happened.
603 HttpBootSetIp6Policy (
604 IN HTTP_BOOT_PRIVATE_DATA
*Private
607 EFI_IP6_CONFIG_POLICY Policy
;
608 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
612 Ip6Config
= Private
->Ip6Config
;
613 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
616 // Get and store the current policy of IP6 driver.
618 Status
= Ip6Config
->GetData (
620 Ip6ConfigDataTypePolicy
,
624 if (EFI_ERROR (Status
)) {
628 if (Policy
== Ip6ConfigPolicyManual
) {
629 Policy
= Ip6ConfigPolicyAutomatic
;
630 Status
= Ip6Config
->SetData (
632 Ip6ConfigDataTypePolicy
,
633 sizeof(EFI_IP6_CONFIG_POLICY
),
636 if (EFI_ERROR (Status
)) {
644 This function will register the default DNS addresses to the network device.
646 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
647 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
648 @param[in] DnsServerData Point a list of DNS server address in an array
649 of EFI_IPv6_ADDRESS instances.
651 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
652 @retval Others Failed to configure the address.
657 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
659 IN VOID
*DnsServerData
662 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
664 ASSERT (Private
->UsingIpv6
);
666 Ip6Config
= Private
->Ip6Config
;
668 return Ip6Config
->SetData (
670 Ip6ConfigDataTypeDnsServer
,
677 This function will register the IPv6 gateway address to the network device.
679 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
681 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
682 @retval Others Failed to configure the address.
686 HttpBootSetIp6Gateway (
687 IN HTTP_BOOT_PRIVATE_DATA
*Private
690 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
693 ASSERT (Private
->UsingIpv6
);
694 Ip6Config
= Private
->Ip6Config
;
697 // Set the default gateway address.
699 if (!Private
->NoGateway
&& !NetIp6IsUnspecifiedAddr (&Private
->GatewayIp
.v6
)) {
700 Status
= Ip6Config
->SetData (
702 Ip6ConfigDataTypeGateway
,
703 sizeof (EFI_IPv6_ADDRESS
),
704 &Private
->GatewayIp
.v6
706 if (EFI_ERROR(Status
)) {
715 This function will register the station IP address.
717 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
719 @retval EFI_SUCCESS The new IP address has been configured successfully.
720 @retval Others Failed to configure the address.
724 HttpBootSetIp6Address (
725 IN HTTP_BOOT_PRIVATE_DATA
*Private
729 EFI_IP6_PROTOCOL
*Ip6
;
730 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
731 EFI_IP6_CONFIG_POLICY Policy
;
732 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
733 EFI_IPv6_ADDRESS
*Ip6Addr
;
734 EFI_IPv6_ADDRESS GatewayAddr
;
735 EFI_IP6_CONFIG_DATA Ip6CfgData
;
741 ASSERT (Private
->UsingIpv6
);
746 Ip6Cfg
= Private
->Ip6Config
;
749 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
750 CopyMem (&CfgAddr
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
751 ZeroMem (&Ip6CfgData
, sizeof (EFI_IP6_CONFIG_DATA
));
753 Ip6CfgData
.AcceptIcmpErrors
= TRUE
;
754 Ip6CfgData
.DefaultProtocol
= IP6_ICMP
;
755 Ip6CfgData
.HopLimit
= HTTP_BOOT_DEFAULT_HOPLIMIT
;
756 Ip6CfgData
.ReceiveTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
757 Ip6CfgData
.TransmitTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
759 Status
= Ip6
->Configure (Ip6
, &Ip6CfgData
);
760 if (EFI_ERROR (Status
)) {
765 // Retrieve the gateway address from IP6 route table.
767 Status
= HttpBootCheckRouteTable (Private
, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
768 if (EFI_ERROR (Status
)) {
769 Private
->NoGateway
= TRUE
;
771 IP6_COPY_ADDRESS (&Private
->GatewayIp
.v6
, &GatewayAddr
);
775 // Set the new address by Ip6ConfigProtocol manually.
777 Policy
= Ip6ConfigPolicyManual
;
778 Status
= Ip6Cfg
->SetData (
780 Ip6ConfigDataTypePolicy
,
781 sizeof(EFI_IP6_CONFIG_POLICY
),
784 if (EFI_ERROR (Status
)) {
789 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
791 Status
= gBS
->CreateEvent (
794 HttpBootCommonNotify
,
798 if (EFI_ERROR (Status
)) {
803 // Set static host ip6 address. This is a asynchronous process.
805 Status
= Ip6Cfg
->RegisterDataNotify (
807 Ip6ConfigDataTypeManualAddress
,
810 if (EFI_ERROR(Status
)) {
814 Status
= Ip6Cfg
->SetData (
816 Ip6ConfigDataTypeManualAddress
,
817 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
),
820 if (EFI_ERROR (Status
) && Status
!= EFI_NOT_READY
) {
822 } else if (Status
== EFI_NOT_READY
) {
824 // Poll the network until the asynchronous process is finished.
826 while (!IsAddressOk
) {
830 // Check whether the Ip6 Address setting is successed.
833 Status
= Ip6Cfg
->GetData (
835 Ip6ConfigDataTypeManualAddress
,
839 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
840 Status
= EFI_DEVICE_ERROR
;
844 Ip6Addr
= AllocatePool (DataSize
);
845 if (Ip6Addr
== NULL
) {
846 return EFI_OUT_OF_RESOURCES
;
848 Status
= Ip6Cfg
->GetData (
850 Ip6ConfigDataTypeManualAddress
,
854 if (EFI_ERROR (Status
)) {
855 Status
= EFI_DEVICE_ERROR
;
859 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
860 if (CompareMem (Ip6Addr
+ Index
, &CfgAddr
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
864 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
865 Status
= EFI_ABORTED
;
871 if (MappedEvt
!= NULL
) {
872 Ip6Cfg
->UnregisterDataNotify (
874 Ip6ConfigDataTypeManualAddress
,
877 gBS
->CloseEvent (MappedEvt
);
880 if (Ip6Addr
!= NULL
) {
888 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
890 @param[in] Private Pointer to HTTP_BOOT private data.
892 @retval EFI_SUCCESS The S.A.R.R process successfully finished.
893 @retval Others Failed to finish the S.A.R.R process.
898 IN HTTP_BOOT_PRIVATE_DATA
*Private
901 EFI_DHCP6_PROTOCOL
*Dhcp6
;
902 EFI_DHCP6_CONFIG_DATA Config
;
903 EFI_DHCP6_MODE_DATA Mode
;
904 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
905 EFI_DHCP6_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP6_OPTION_MAX_NUM
];
907 UINT8 Buffer
[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE
];
910 Dhcp6
= Private
->Dhcp6
;
911 ASSERT (Dhcp6
!= NULL
);
914 // Build options list for the request packet.
916 OptCount
= HttpBootBuildDhcp6Options (Private
, OptList
, Buffer
);
917 ASSERT (OptCount
>0);
919 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
920 if (Retransmit
== NULL
) {
921 return EFI_OUT_OF_RESOURCES
;
924 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
925 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
927 Config
.OptionCount
= OptCount
;
928 Config
.OptionList
= OptList
;
929 Config
.Dhcp6Callback
= HttpBootDhcp6CallBack
;
930 Config
.CallbackContext
= Private
;
931 Config
.IaInfoEvent
= NULL
;
932 Config
.RapidCommit
= FALSE
;
933 Config
.ReconfigureAccept
= FALSE
;
934 Config
.IaDescriptor
.IaId
= NET_RANDOM (NetRandomInitSeed ());
935 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
936 Config
.SolicitRetransmission
= Retransmit
;
939 Retransmit
->Mrt
= 32;
940 Retransmit
->Mrd
= 60;
943 // Configure the DHCPv6 instance for HTTP boot.
945 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
946 FreePool (Retransmit
);
947 if (EFI_ERROR (Status
)) {
951 // Initialize the record fields for DHCPv6 offer in private data.
953 Private
->OfferNum
= 0;
954 Private
->SelectIndex
= 0;
955 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
956 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
959 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
961 Status
= Dhcp6
->Start (Dhcp6
);
962 if (EFI_ERROR (Status
)) {
967 // Get the acquired IPv6 address and store them.
969 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
970 if (EFI_ERROR (Status
)) {
974 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
975 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
977 AsciiPrint ("\n Station IPv6 address is ");
978 HttpBootShowIp6Addr (&Private
->StationIp
.v6
);
982 if (EFI_ERROR (Status
)) {
984 Dhcp6
->Configure (Dhcp6
, NULL
);
986 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
987 Dhcp6
->Configure (Dhcp6
, &Config
);
988 if (Mode
.ClientId
!= NULL
) {
989 FreePool (Mode
.ClientId
);
991 if (Mode
.Ia
!= NULL
) {