2 Functions implementation related with DHCPv6 for HTTP boot driver.
4 Copyright (c) 2015 - 2018, 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.
332 @retval EFI_SUCCESS Packet is copied.
333 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
337 HttpBootCacheDhcp6Packet (
338 IN EFI_DHCP6_PACKET
*Dst
,
339 IN EFI_DHCP6_PACKET
*Src
342 if (Dst
->Size
< Src
->Length
) {
343 return EFI_BUFFER_TOO_SMALL
;
346 CopyMem (&Dst
->Dhcp6
, &Src
->Dhcp6
, Src
->Length
);
347 Dst
->Length
= Src
->Length
;
353 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
355 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
356 @param[in] RcvdOffer The pointer to the received offer packet.
358 @retval EFI_SUCCESS Cache and parse the packet successfully.
359 @retval Others Operation failed.
363 HttpBootCacheDhcp6Offer (
364 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
365 IN EFI_DHCP6_PACKET
*RcvdOffer
368 HTTP_BOOT_DHCP6_PACKET_CACHE
*Cache6
;
369 EFI_DHCP6_PACKET
*Offer
;
370 HTTP_BOOT_OFFER_TYPE OfferType
;
373 Cache6
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp6
;
374 Offer
= &Cache6
->Packet
.Offer
;
377 // Cache the content of DHCPv6 packet firstly.
379 Status
= HttpBootCacheDhcp6Packet(Offer
, RcvdOffer
);
380 if (EFI_ERROR (Status
)) {
385 // Validate the DHCPv6 packet, and parse the options and offer type.
387 if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6
))) {
392 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
394 OfferType
= Cache6
->OfferType
;
395 ASSERT (OfferType
< HttpOfferTypeMax
);
396 ASSERT (Private
->OfferCount
[OfferType
] < HTTP_BOOT_OFFER_MAX_NUM
);
397 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
398 Private
->OfferCount
[OfferType
]++;
405 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
406 to intercept events that occurred in the configuration process.
408 @param[in] This The pointer to the EFI DHCPv6 Protocol.
409 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
410 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
411 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
413 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
414 @param[out] NewPacket The packet that is used to replace the Packet above.
416 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
417 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
418 driver will continue to wait for more packets.
419 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
420 @retval EFI_OUT_OF_RESOURCES There are not enough resources.
425 HttpBootDhcp6CallBack (
426 IN EFI_DHCP6_PROTOCOL
*This
,
428 IN EFI_DHCP6_STATE CurrentState
,
429 IN EFI_DHCP6_EVENT Dhcp6Event
,
430 IN EFI_DHCP6_PACKET
*Packet
,
431 OUT EFI_DHCP6_PACKET
**NewPacket OPTIONAL
434 HTTP_BOOT_PRIVATE_DATA
*Private
;
435 EFI_DHCP6_PACKET
*SelectAd
;
439 if ((Dhcp6Event
!= Dhcp6SendSolicit
) &&
440 (Dhcp6Event
!= Dhcp6RcvdAdvertise
) &&
441 (Dhcp6Event
!= Dhcp6SendRequest
) &&
442 (Dhcp6Event
!= Dhcp6RcvdReply
) &&
443 (Dhcp6Event
!= Dhcp6SelectAdvertise
)) {
447 ASSERT (Packet
!= NULL
);
449 Private
= (HTTP_BOOT_PRIVATE_DATA
*) Context
;
450 Status
= EFI_SUCCESS
;
451 if (Private
->HttpBootCallback
!= NULL
&& Dhcp6Event
!= Dhcp6SelectAdvertise
) {
452 Received
= (BOOLEAN
) (Dhcp6Event
== Dhcp6RcvdAdvertise
|| Dhcp6Event
== Dhcp6RcvdReply
);
453 Status
= Private
->HttpBootCallback
->Callback (
454 Private
->HttpBootCallback
,
460 if (EFI_ERROR (Status
)) {
464 switch (Dhcp6Event
) {
466 case Dhcp6RcvdAdvertise
:
467 Status
= EFI_NOT_READY
;
468 if (Packet
->Length
> HTTP_BOOT_DHCP6_PACKET_MAX_SIZE
) {
470 // Ignore the incoming packets which exceed the maximum length.
474 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
476 // Cache the dhcp offers to OfferBuffer[] for select later, and record
477 // the OfferIndex and OfferCount.
478 // If error happens, just ignore this packet and continue to wait more offer.
480 HttpBootCacheDhcp6Offer (Private
, Packet
);
484 case Dhcp6SelectAdvertise
:
486 // Select offer by the default policy or by order, and record the SelectIndex
487 // and SelectProxyType.
489 HttpBootSelectDhcpOffer (Private
);
491 if (Private
->SelectIndex
== 0) {
492 Status
= EFI_ABORTED
;
494 ASSERT (NewPacket
!= NULL
);
495 SelectAd
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp6
.Packet
.Offer
;
496 *NewPacket
= AllocateZeroPool (SelectAd
->Size
);
497 if (*NewPacket
== NULL
) {
498 return EFI_OUT_OF_RESOURCES
;
500 CopyMem (*NewPacket
, SelectAd
, SelectAd
->Size
);
512 Check whether IP driver could route the message which will be sent to ServerIp address.
514 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
515 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
517 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
518 @param[in] TimeOutInSecond Timeout value in seconds.
519 @param[out] GatewayAddr Pointer to store the gateway IP address.
521 @retval EFI_SUCCESS Found a valid gateway address successfully.
522 @retval EFI_TIMEOUT The operation is time out.
523 @retval Other Unexpect error happened.
527 HttpBootCheckRouteTable (
528 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
529 IN UINTN TimeOutInSecond
,
530 OUT EFI_IPv6_ADDRESS
*GatewayAddr
534 EFI_IP6_PROTOCOL
*Ip6
;
535 EFI_IP6_MODE_DATA Ip6ModeData
;
537 EFI_EVENT TimeOutEvt
;
539 BOOLEAN GatewayIsFound
;
541 ASSERT (GatewayAddr
!= NULL
);
542 ASSERT (Private
!= NULL
);
545 GatewayIsFound
= FALSE
;
548 Status
= EFI_SUCCESS
;
549 ZeroMem (GatewayAddr
, sizeof (EFI_IPv6_ADDRESS
));
552 Status
= Ip6
->GetModeData (Ip6
, &Ip6ModeData
, NULL
, NULL
);
553 if (EFI_ERROR (Status
)) {
558 // Find out the gateway address which can route the message which send to ServerIp.
560 for (Index
= 0; Index
< Ip6ModeData
.RouteCount
; Index
++) {
561 if (NetIp6IsNetEqual (&Private
->ServerIp
.v6
, &Ip6ModeData
.RouteTable
[Index
].Destination
, Ip6ModeData
.RouteTable
[Index
].PrefixLength
)) {
562 IP6_COPY_ADDRESS (GatewayAddr
, &Ip6ModeData
.RouteTable
[Index
].Gateway
);
563 GatewayIsFound
= TRUE
;
568 if (Ip6ModeData
.AddressList
!= NULL
) {
569 FreePool (Ip6ModeData
.AddressList
);
571 if (Ip6ModeData
.GroupTable
!= NULL
) {
572 FreePool (Ip6ModeData
.GroupTable
);
574 if (Ip6ModeData
.RouteTable
!= NULL
) {
575 FreePool (Ip6ModeData
.RouteTable
);
577 if (Ip6ModeData
.NeighborCache
!= NULL
) {
578 FreePool (Ip6ModeData
.NeighborCache
);
580 if (Ip6ModeData
.PrefixTable
!= NULL
) {
581 FreePool (Ip6ModeData
.PrefixTable
);
583 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
584 FreePool (Ip6ModeData
.IcmpTypeList
);
587 if (GatewayIsFound
|| RetryCount
== TimeOutInSecond
) {
594 // Delay 1 second then recheck it again.
596 if (TimeOutEvt
== NULL
) {
597 Status
= gBS
->CreateEvent (
604 if (EFI_ERROR (Status
)) {
609 Status
= gBS
->SetTimer (TimeOutEvt
, TimerRelative
, TICKS_PER_SECOND
);
610 if (EFI_ERROR (Status
)) {
613 while (EFI_ERROR (gBS
->CheckEvent (TimeOutEvt
))) {
619 if (TimeOutEvt
!= NULL
) {
620 gBS
->CloseEvent (TimeOutEvt
);
623 if (GatewayIsFound
) {
624 Status
= EFI_SUCCESS
;
625 } else if (RetryCount
== TimeOutInSecond
) {
626 Status
= EFI_TIMEOUT
;
633 Set the IP6 policy to Automatic.
635 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
637 @retval EFI_SUCCESS Switch the IP policy succesfully.
638 @retval Others Unexpect error happened.
642 HttpBootSetIp6Policy (
643 IN HTTP_BOOT_PRIVATE_DATA
*Private
646 EFI_IP6_CONFIG_POLICY Policy
;
647 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
651 Ip6Config
= Private
->Ip6Config
;
652 DataSize
= sizeof (EFI_IP6_CONFIG_POLICY
);
655 // Get and store the current policy of IP6 driver.
657 Status
= Ip6Config
->GetData (
659 Ip6ConfigDataTypePolicy
,
663 if (EFI_ERROR (Status
)) {
667 if (Policy
== Ip6ConfigPolicyManual
) {
668 Policy
= Ip6ConfigPolicyAutomatic
;
669 Status
= Ip6Config
->SetData (
671 Ip6ConfigDataTypePolicy
,
672 sizeof(EFI_IP6_CONFIG_POLICY
),
675 if (EFI_ERROR (Status
)) {
683 This function will register the default DNS addresses to the network device.
685 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
686 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
687 @param[in] DnsServerData Point a list of DNS server address in an array
688 of EFI_IPv6_ADDRESS instances.
690 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
691 @retval Others Failed to configure the address.
696 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
698 IN VOID
*DnsServerData
701 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
703 ASSERT (Private
->UsingIpv6
);
705 Ip6Config
= Private
->Ip6Config
;
707 return Ip6Config
->SetData (
709 Ip6ConfigDataTypeDnsServer
,
716 This function will register the IPv6 gateway address to the network device.
718 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
720 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
721 @retval Others Failed to configure the address.
725 HttpBootSetIp6Gateway (
726 IN HTTP_BOOT_PRIVATE_DATA
*Private
729 EFI_IP6_CONFIG_PROTOCOL
*Ip6Config
;
732 ASSERT (Private
->UsingIpv6
);
733 Ip6Config
= Private
->Ip6Config
;
736 // Set the default gateway address.
738 if (!Private
->NoGateway
&& !NetIp6IsUnspecifiedAddr (&Private
->GatewayIp
.v6
)) {
739 Status
= Ip6Config
->SetData (
741 Ip6ConfigDataTypeGateway
,
742 sizeof (EFI_IPv6_ADDRESS
),
743 &Private
->GatewayIp
.v6
745 if (EFI_ERROR(Status
)) {
754 This function will register the station IP address.
756 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
758 @retval EFI_SUCCESS The new IP address has been configured successfully.
759 @retval Others Failed to configure the address.
763 HttpBootSetIp6Address (
764 IN HTTP_BOOT_PRIVATE_DATA
*Private
768 EFI_IP6_PROTOCOL
*Ip6
;
769 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
770 EFI_IP6_CONFIG_POLICY Policy
;
771 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr
;
772 EFI_IPv6_ADDRESS
*Ip6Addr
;
773 EFI_IPv6_ADDRESS GatewayAddr
;
774 EFI_IP6_CONFIG_DATA Ip6CfgData
;
780 ASSERT (Private
->UsingIpv6
);
785 Ip6Cfg
= Private
->Ip6Config
;
788 ZeroMem (&CfgAddr
, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
));
789 CopyMem (&CfgAddr
, &Private
->StationIp
.v6
, sizeof (EFI_IPv6_ADDRESS
));
790 ZeroMem (&Ip6CfgData
, sizeof (EFI_IP6_CONFIG_DATA
));
792 Ip6CfgData
.AcceptIcmpErrors
= TRUE
;
793 Ip6CfgData
.DefaultProtocol
= IP6_ICMP
;
794 Ip6CfgData
.HopLimit
= HTTP_BOOT_DEFAULT_HOPLIMIT
;
795 Ip6CfgData
.ReceiveTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
796 Ip6CfgData
.TransmitTimeout
= HTTP_BOOT_DEFAULT_LIFETIME
;
798 Status
= Ip6
->Configure (Ip6
, &Ip6CfgData
);
799 if (EFI_ERROR (Status
)) {
804 // Retrieve the gateway address from IP6 route table.
806 Status
= HttpBootCheckRouteTable (Private
, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT
, &GatewayAddr
);
807 if (EFI_ERROR (Status
)) {
808 Private
->NoGateway
= TRUE
;
810 IP6_COPY_ADDRESS (&Private
->GatewayIp
.v6
, &GatewayAddr
);
814 // Set the new address by Ip6ConfigProtocol manually.
816 Policy
= Ip6ConfigPolicyManual
;
817 Status
= Ip6Cfg
->SetData (
819 Ip6ConfigDataTypePolicy
,
820 sizeof(EFI_IP6_CONFIG_POLICY
),
823 if (EFI_ERROR (Status
)) {
828 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
830 Status
= gBS
->CreateEvent (
833 HttpBootCommonNotify
,
837 if (EFI_ERROR (Status
)) {
842 // Set static host ip6 address. This is a asynchronous process.
844 Status
= Ip6Cfg
->RegisterDataNotify (
846 Ip6ConfigDataTypeManualAddress
,
849 if (EFI_ERROR(Status
)) {
853 Status
= Ip6Cfg
->SetData (
855 Ip6ConfigDataTypeManualAddress
,
856 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS
),
859 if (EFI_ERROR (Status
) && Status
!= EFI_NOT_READY
) {
861 } else if (Status
== EFI_NOT_READY
) {
863 // Poll the network until the asynchronous process is finished.
865 while (!IsAddressOk
) {
869 // Check whether the Ip6 Address setting is successed.
872 Status
= Ip6Cfg
->GetData (
874 Ip6ConfigDataTypeManualAddress
,
878 if (Status
!= EFI_BUFFER_TOO_SMALL
|| DataSize
== 0) {
879 Status
= EFI_DEVICE_ERROR
;
883 Ip6Addr
= AllocatePool (DataSize
);
884 if (Ip6Addr
== NULL
) {
885 return EFI_OUT_OF_RESOURCES
;
887 Status
= Ip6Cfg
->GetData (
889 Ip6ConfigDataTypeManualAddress
,
893 if (EFI_ERROR (Status
)) {
894 Status
= EFI_DEVICE_ERROR
;
898 for (Index
= 0; Index
< DataSize
/ sizeof (EFI_IPv6_ADDRESS
); Index
++) {
899 if (CompareMem (Ip6Addr
+ Index
, &CfgAddr
, sizeof (EFI_IPv6_ADDRESS
)) == 0) {
903 if (Index
== DataSize
/ sizeof (EFI_IPv6_ADDRESS
)) {
904 Status
= EFI_ABORTED
;
910 if (MappedEvt
!= NULL
) {
911 Ip6Cfg
->UnregisterDataNotify (
913 Ip6ConfigDataTypeManualAddress
,
916 gBS
->CloseEvent (MappedEvt
);
919 if (Ip6Addr
!= NULL
) {
927 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
929 @param[in] Private Pointer to HTTP_BOOT private data.
931 @retval EFI_SUCCESS The S.A.R.R process successfully finished.
932 @retval Others Failed to finish the S.A.R.R process.
937 IN HTTP_BOOT_PRIVATE_DATA
*Private
940 EFI_DHCP6_PROTOCOL
*Dhcp6
;
941 EFI_DHCP6_CONFIG_DATA Config
;
942 EFI_DHCP6_MODE_DATA Mode
;
943 EFI_DHCP6_RETRANSMISSION
*Retransmit
;
944 EFI_DHCP6_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP6_OPTION_MAX_NUM
];
946 UINT8 Buffer
[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE
];
949 Dhcp6
= Private
->Dhcp6
;
950 ASSERT (Dhcp6
!= NULL
);
953 // Build options list for the request packet.
955 OptCount
= HttpBootBuildDhcp6Options (Private
, OptList
, Buffer
);
956 ASSERT (OptCount
>0);
958 Retransmit
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
959 if (Retransmit
== NULL
) {
960 return EFI_OUT_OF_RESOURCES
;
963 ZeroMem (&Mode
, sizeof (EFI_DHCP6_MODE_DATA
));
964 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
966 Config
.OptionCount
= OptCount
;
967 Config
.OptionList
= OptList
;
968 Config
.Dhcp6Callback
= HttpBootDhcp6CallBack
;
969 Config
.CallbackContext
= Private
;
970 Config
.IaInfoEvent
= NULL
;
971 Config
.RapidCommit
= FALSE
;
972 Config
.ReconfigureAccept
= FALSE
;
973 Config
.IaDescriptor
.IaId
= NET_RANDOM (NetRandomInitSeed ());
974 Config
.IaDescriptor
.Type
= EFI_DHCP6_IA_TYPE_NA
;
975 Config
.SolicitRetransmission
= Retransmit
;
978 Retransmit
->Mrt
= 32;
979 Retransmit
->Mrd
= 60;
982 // Configure the DHCPv6 instance for HTTP boot.
984 Status
= Dhcp6
->Configure (Dhcp6
, &Config
);
985 FreePool (Retransmit
);
986 if (EFI_ERROR (Status
)) {
990 // Initialize the record fields for DHCPv6 offer in private data.
992 Private
->OfferNum
= 0;
993 Private
->SelectIndex
= 0;
994 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
995 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
998 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1000 Status
= Dhcp6
->Start (Dhcp6
);
1001 if (EFI_ERROR (Status
)) {
1006 // Get the acquired IPv6 address and store them.
1008 Status
= Dhcp6
->GetModeData (Dhcp6
, &Mode
, NULL
);
1009 if (EFI_ERROR (Status
)) {
1013 ASSERT (Mode
.Ia
->State
== Dhcp6Bound
);
1014 CopyMem (&Private
->StationIp
.v6
, &Mode
.Ia
->IaAddress
[0].IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
1016 AsciiPrint ("\n Station IPv6 address is ");
1017 HttpBootShowIp6Addr (&Private
->StationIp
.v6
);
1021 if (EFI_ERROR (Status
)) {
1022 Dhcp6
->Stop (Dhcp6
);
1023 Dhcp6
->Configure (Dhcp6
, NULL
);
1025 ZeroMem (&Config
, sizeof (EFI_DHCP6_CONFIG_DATA
));
1026 Dhcp6
->Configure (Dhcp6
, &Config
);
1027 if (Mode
.ClientId
!= NULL
) {
1028 FreePool (Mode
.ClientId
);
1030 if (Mode
.Ia
!= NULL
) {