]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDhcp6.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootDhcp6.c
CommitLineData
b659408b
ZL
1/** @file\r
2 Functions implementation related with DHCPv6 for HTTP boot driver.\r
3\r
f75a7f56 4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
ecf98fbc 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
b659408b
ZL
6\r
7**/\r
8\r
9#include "HttpBootDxe.h"\r
10\r
11/**\r
12 Build the options buffer for the DHCPv6 request packet.\r
13\r
14 @param[in] Private The pointer to HTTP BOOT driver private data.\r
15 @param[out] OptList The pointer to the option pointer array.\r
16 @param[in] Buffer The pointer to the buffer to contain the option list.\r
17\r
18 @return Index The count of the built-in options.\r
19\r
20**/\r
21UINT32\r
22HttpBootBuildDhcp6Options (\r
d1050b9d
MK
23 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
24 OUT EFI_DHCP6_PACKET_OPTION **OptList,\r
25 IN UINT8 *Buffer\r
b659408b
ZL
26 )\r
27{\r
d1050b9d
MK
28 HTTP_BOOT_DHCP6_OPTION_ENTRY OptEnt;\r
29 UINT16 Value;\r
30 UINT32 Index;\r
b659408b
ZL
31\r
32 Index = 0;\r
d1050b9d 33 OptList[0] = (EFI_DHCP6_PACKET_OPTION *)Buffer;\r
b659408b
ZL
34\r
35 //\r
36 // Append client option request option\r
37 //\r
d1050b9d
MK
38 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO);\r
39 OptList[Index]->OpLen = HTONS (8);\r
40 OptEnt.Oro = (HTTP_BOOT_DHCP6_OPTION_ORO *)OptList[Index]->Data;\r
41 OptEnt.Oro->OpCode[0] = HTONS (DHCP6_OPT_BOOT_FILE_URL);\r
42 OptEnt.Oro->OpCode[1] = HTONS (DHCP6_OPT_BOOT_FILE_PARAM);\r
43 OptEnt.Oro->OpCode[2] = HTONS (DHCP6_OPT_DNS_SERVERS);\r
44 OptEnt.Oro->OpCode[3] = HTONS (DHCP6_OPT_VENDOR_CLASS);\r
b659408b 45 Index++;\r
d1050b9d 46 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
b659408b
ZL
47\r
48 //\r
49 // Append client network device interface option\r
50 //\r
d1050b9d
MK
51 OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI);\r
52 OptList[Index]->OpLen = HTONS ((UINT16)3);\r
53 OptEnt.Undi = (HTTP_BOOT_DHCP6_OPTION_UNDI *)OptList[Index]->Data;\r
b659408b
ZL
54\r
55 if (Private->Nii != NULL) {\r
d1050b9d
MK
56 OptEnt.Undi->Type = Private->Nii->Type;\r
57 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
58 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
b659408b 59 } else {\r
d1050b9d
MK
60 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
61 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
62 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
b659408b
ZL
63 }\r
64\r
65 Index++;\r
d1050b9d 66 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
b659408b
ZL
67\r
68 //\r
69 // Append client system architecture option\r
70 //\r
d1050b9d
MK
71 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH);\r
72 OptList[Index]->OpLen = HTONS ((UINT16)sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH));\r
73 OptEnt.Arch = (HTTP_BOOT_DHCP6_OPTION_ARCH *)OptList[Index]->Data;\r
74 Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);\r
b659408b
ZL
75 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
76 Index++;\r
d1050b9d 77 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
b659408b
ZL
78\r
79 //\r
80 // Append vendor class identify option.\r
81 //\r
142c00c3 82 OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS);\r
d1050b9d
MK
83 OptList[Index]->OpLen = HTONS ((UINT16)sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS));\r
84 OptEnt.VendorClass = (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS *)OptList[Index]->Data;\r
b659408b 85 OptEnt.VendorClass->Vendor = HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM);\r
d1050b9d 86 OptEnt.VendorClass->ClassLen = HTONS ((UINT16)sizeof (HTTP_BOOT_CLASS_ID));\r
b659408b
ZL
87 CopyMem (\r
88 &OptEnt.VendorClass->ClassId,\r
89 DEFAULT_CLASS_ID_DATA,\r
90 sizeof (HTTP_BOOT_CLASS_ID)\r
91 );\r
92 HttpBootUintnToAscDecWithFormat (\r
93 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,\r
94 OptEnt.VendorClass->ClassId.ArchitectureType,\r
95 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)\r
96 );\r
97\r
98 if (Private->Nii != NULL) {\r
99 CopyMem (\r
100 OptEnt.VendorClass->ClassId.InterfaceName,\r
101 Private->Nii->StringId,\r
102 sizeof (OptEnt.VendorClass->ClassId.InterfaceName)\r
103 );\r
104 HttpBootUintnToAscDecWithFormat (\r
105 Private->Nii->MajorVer,\r
106 OptEnt.VendorClass->ClassId.UndiMajor,\r
107 sizeof (OptEnt.VendorClass->ClassId.UndiMajor)\r
108 );\r
109 HttpBootUintnToAscDecWithFormat (\r
110 Private->Nii->MinorVer,\r
111 OptEnt.VendorClass->ClassId.UndiMinor,\r
112 sizeof (OptEnt.VendorClass->ClassId.UndiMinor)\r
113 );\r
114 }\r
115\r
116 Index++;\r
117\r
118 return Index;\r
119}\r
120\r
121/**\r
122 Parse out a DHCPv6 option by OptTag, and find the position in buffer.\r
123\r
124 @param[in] Buffer The pointer to the option buffer.\r
125 @param[in] Length Length of the option buffer.\r
126 @param[in] OptTag The required option tag.\r
127\r
128 @retval NULL Failed to parse the required option.\r
c36b7b51 129 @retval Others The position of the required option in buffer.\r
b659408b
ZL
130\r
131**/\r
132EFI_DHCP6_PACKET_OPTION *\r
133HttpBootParseDhcp6Options (\r
d1050b9d
MK
134 IN UINT8 *Buffer,\r
135 IN UINT32 Length,\r
136 IN UINT16 OptTag\r
b659408b
ZL
137 )\r
138{\r
d1050b9d
MK
139 EFI_DHCP6_PACKET_OPTION *Option;\r
140 UINT32 Offset;\r
b659408b 141\r
d1050b9d
MK
142 Option = (EFI_DHCP6_PACKET_OPTION *)Buffer;\r
143 Offset = 0;\r
b659408b
ZL
144\r
145 //\r
146 // OpLen and OpCode here are both stored in network order.\r
147 //\r
148 while (Offset < Length) {\r
b659408b 149 if (NTOHS (Option->OpCode) == OptTag) {\r
b659408b
ZL
150 return Option;\r
151 }\r
152\r
d1050b9d
MK
153 Offset += (NTOHS (Option->OpLen) + 4);\r
154 Option = (EFI_DHCP6_PACKET_OPTION *)(Buffer + Offset);\r
b659408b
ZL
155 }\r
156\r
157 return NULL;\r
b659408b
ZL
158}\r
159\r
160/**\r
161 Parse the cached DHCPv6 packet, including all the options.\r
162\r
163 @param[in] Cache6 The pointer to a cached DHCPv6 packet.\r
164\r
165 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.\r
166 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.\r
167\r
168**/\r
169EFI_STATUS\r
170HttpBootParseDhcp6Packet (\r
d1050b9d 171 IN HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6\r
b659408b
ZL
172 )\r
173{\r
d1050b9d
MK
174 EFI_DHCP6_PACKET *Offer;\r
175 EFI_DHCP6_PACKET_OPTION **Options;\r
176 EFI_DHCP6_PACKET_OPTION *Option;\r
177 HTTP_BOOT_OFFER_TYPE OfferType;\r
178 EFI_IPv6_ADDRESS IpAddr;\r
179 BOOLEAN IsProxyOffer;\r
180 BOOLEAN IsHttpOffer;\r
181 BOOLEAN IsDnsOffer;\r
182 BOOLEAN IpExpressedUri;\r
183 EFI_STATUS Status;\r
184 UINT32 Offset;\r
185 UINT32 Length;\r
f75a7f56 186\r
b659408b
ZL
187 IsDnsOffer = FALSE;\r
188 IpExpressedUri = FALSE;\r
189 IsProxyOffer = TRUE;\r
190 IsHttpOffer = FALSE;\r
d1050b9d
MK
191 Offer = &Cache6->Packet.Offer;\r
192 Options = Cache6->OptList;\r
f75a7f56 193\r
b659408b
ZL
194 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));\r
195\r
d1050b9d
MK
196 Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option);\r
197 Offset = 0;\r
198 Length = GET_DHCP6_OPTION_SIZE (Offer);\r
b659408b
ZL
199\r
200 //\r
201 // OpLen and OpCode here are both stored in network order, since they are from original packet.\r
202 //\r
203 while (Offset < Length) {\r
142c00c3 204 if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) {\r
b659408b 205 Options[HTTP_BOOT_DHCP6_IDX_IA_NA] = Option;\r
142c00c3 206 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) {\r
b659408b
ZL
207 //\r
208 // The server sends this option to inform the client about an URL to a boot file.\r
209 //\r
210 Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] = Option;\r
142c00c3 211 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) {\r
b659408b 212 Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
142c00c3 213 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {\r
b659408b 214 Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS] = Option;\r
142c00c3 215 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) {\r
b659408b
ZL
216 Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER] = Option;\r
217 }\r
218\r
219 Offset += (NTOHS (Option->OpLen) + 4);\r
d1050b9d 220 Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option + Offset);\r
b659408b 221 }\r
d1050b9d 222\r
b659408b
ZL
223 //\r
224 // The offer with assigned client address is NOT a proxy offer.\r
c36b7b51 225 // An ia_na option, embedded with valid ia_addr option and a status_code of success.\r
b659408b
ZL
226 //\r
227 Option = Options[HTTP_BOOT_DHCP6_IDX_IA_NA];\r
228 if (Option != NULL) {\r
229 Option = HttpBootParseDhcp6Options (\r
230 Option->Data + 12,\r
231 NTOHS (Option->OpLen),\r
142c00c3 232 DHCP6_OPT_STATUS_CODE\r
b659408b 233 );\r
d1050b9d 234 if (((Option != NULL) && (Option->Data[0] == 0)) || (Option == NULL)) {\r
b659408b
ZL
235 IsProxyOffer = FALSE;\r
236 }\r
237 }\r
238\r
239 //\r
240 // The offer with "HTTPClient" is a Http offer.\r
241 //\r
242 Option = Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS];\r
243\r
d1050b9d
MK
244 if ((Option != NULL) &&\r
245 (NTOHS (Option->OpLen) >= 16) &&\r
246 (CompareMem ((Option->Data + 6), DEFAULT_CLASS_ID_DATA, 10) == 0))\r
247 {\r
248 IsHttpOffer = TRUE;\r
b659408b
ZL
249 }\r
250\r
251 //\r
252 // The offer with Domain Server is a DNS offer.\r
253 //\r
254 Option = Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];\r
255 if (Option != NULL) {\r
256 IsDnsOffer = TRUE;\r
257 }\r
258\r
259 //\r
260 // Http offer must have a boot URI.\r
261 //\r
d1050b9d 262 if (IsHttpOffer && (Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] == NULL)) {\r
b659408b
ZL
263 return EFI_DEVICE_ERROR;\r
264 }\r
f75a7f56 265\r
b659408b 266 //\r
f75a7f56 267 // Try to retrieve the IP of HTTP server from URI.\r
b659408b
ZL
268 //\r
269 if (IsHttpOffer) {\r
270 Status = HttpParseUrl (\r
d1050b9d
MK
271 (CHAR8 *)Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
272 (UINT32)AsciiStrLen ((CHAR8 *)Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
b659408b
ZL
273 FALSE,\r
274 &Cache6->UriParser\r
275 );\r
276 if (EFI_ERROR (Status)) {\r
277 return EFI_DEVICE_ERROR;\r
278 }\r
279\r
280 Status = HttpUrlGetIp6 (\r
d1050b9d 281 (CHAR8 *)Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,\r
b659408b
ZL
282 Cache6->UriParser,\r
283 &IpAddr\r
284 );\r
285 IpExpressedUri = !EFI_ERROR (Status);\r
286 }\r
287\r
288 //\r
289 // Determine offer type of the DHCPv6 packet.\r
290 //\r
291 if (IsHttpOffer) {\r
292 if (IpExpressedUri) {\r
fa848a40
FS
293 if (IsProxyOffer) {\r
294 OfferType = HttpOfferTypeProxyIpUri;\r
295 } else {\r
296 OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;\r
297 }\r
b659408b
ZL
298 } else {\r
299 if (!IsProxyOffer) {\r
300 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;\r
301 } else {\r
302 OfferType = HttpOfferTypeProxyNameUri;\r
303 }\r
304 }\r
b659408b
ZL
305 } else {\r
306 if (!IsProxyOffer) {\r
307 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;\r
308 } else {\r
309 return EFI_DEVICE_ERROR;\r
310 }\r
311 }\r
f75a7f56 312\r
b659408b
ZL
313 Cache6->OfferType = OfferType;\r
314 return EFI_SUCCESS;\r
315}\r
316\r
317/**\r
318 Cache the DHCPv6 packet.\r
319\r
320 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.\r
321 @param[in] Src The pointer to the DHCPv6 packet to be cached.\r
322\r
a35dc649
FS
323 @retval EFI_SUCCESS Packet is copied.\r
324 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
325\r
b659408b 326**/\r
a35dc649 327EFI_STATUS\r
b659408b 328HttpBootCacheDhcp6Packet (\r
d1050b9d
MK
329 IN EFI_DHCP6_PACKET *Dst,\r
330 IN EFI_DHCP6_PACKET *Src\r
b659408b
ZL
331 )\r
332{\r
a35dc649
FS
333 if (Dst->Size < Src->Length) {\r
334 return EFI_BUFFER_TOO_SMALL;\r
335 }\r
b659408b
ZL
336\r
337 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);\r
338 Dst->Length = Src->Length;\r
f75a7f56 339\r
a35dc649 340 return EFI_SUCCESS;\r
b659408b
ZL
341}\r
342\r
343/**\r
344 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.\r
345\r
346 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
347 @param[in] RcvdOffer The pointer to the received offer packet.\r
348\r
a35dc649
FS
349 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
350 @retval Others Operation failed.\r
351\r
b659408b 352**/\r
a35dc649 353EFI_STATUS\r
b659408b
ZL
354HttpBootCacheDhcp6Offer (\r
355 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
356 IN EFI_DHCP6_PACKET *RcvdOffer\r
357 )\r
358{\r
d1050b9d
MK
359 HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6;\r
360 EFI_DHCP6_PACKET *Offer;\r
361 HTTP_BOOT_OFFER_TYPE OfferType;\r
362 EFI_STATUS Status;\r
b659408b
ZL
363\r
364 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;\r
365 Offer = &Cache6->Packet.Offer;\r
366\r
367 //\r
368 // Cache the content of DHCPv6 packet firstly.\r
369 //\r
d1050b9d 370 Status = HttpBootCacheDhcp6Packet (Offer, RcvdOffer);\r
a35dc649
FS
371 if (EFI_ERROR (Status)) {\r
372 return Status;\r
373 }\r
b659408b
ZL
374\r
375 //\r
376 // Validate the DHCPv6 packet, and parse the options and offer type.\r
377 //\r
378 if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6))) {\r
a35dc649 379 return EFI_ABORTED;\r
b659408b
ZL
380 }\r
381\r
382 //\r
383 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
384 //\r
385 OfferType = Cache6->OfferType;\r
386 ASSERT (OfferType < HttpOfferTypeMax);\r
387 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);\r
388 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
389 Private->OfferCount[OfferType]++;\r
a35dc649 390 Private->OfferNum++;\r
f75a7f56 391\r
a35dc649 392 return EFI_SUCCESS;\r
b659408b
ZL
393}\r
394\r
395/**\r
396 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver\r
397 to intercept events that occurred in the configuration process.\r
398\r
399 @param[in] This The pointer to the EFI DHCPv6 Protocol.\r
400 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().\r
401 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.\r
402 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a\r
403 state transition.\r
404 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.\r
405 @param[out] NewPacket The packet that is used to replace the Packet above.\r
406\r
407 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.\r
408 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol\r
409 driver will continue to wait for more packets.\r
410 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.\r
7c275b3c 411 @retval EFI_OUT_OF_RESOURCES There are not enough resources.\r
b659408b
ZL
412\r
413**/\r
414EFI_STATUS\r
415EFIAPI\r
416HttpBootDhcp6CallBack (\r
d1050b9d
MK
417 IN EFI_DHCP6_PROTOCOL *This,\r
418 IN VOID *Context,\r
419 IN EFI_DHCP6_STATE CurrentState,\r
420 IN EFI_DHCP6_EVENT Dhcp6Event,\r
421 IN EFI_DHCP6_PACKET *Packet,\r
422 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL\r
b659408b
ZL
423 )\r
424{\r
d1050b9d
MK
425 HTTP_BOOT_PRIVATE_DATA *Private;\r
426 EFI_DHCP6_PACKET *SelectAd;\r
427 EFI_STATUS Status;\r
428 BOOLEAN Received;\r
f75a7f56 429\r
95b5c32f 430 if ((Dhcp6Event != Dhcp6SendSolicit) &&\r
d1050b9d
MK
431 (Dhcp6Event != Dhcp6RcvdAdvertise) &&\r
432 (Dhcp6Event != Dhcp6SendRequest) &&\r
433 (Dhcp6Event != Dhcp6RcvdReply) &&\r
434 (Dhcp6Event != Dhcp6SelectAdvertise))\r
435 {\r
95b5c32f
FS
436 return EFI_SUCCESS;\r
437 }\r
b659408b 438\r
95b5c32f 439 ASSERT (Packet != NULL);\r
f75a7f56 440\r
d1050b9d
MK
441 Private = (HTTP_BOOT_PRIVATE_DATA *)Context;\r
442 Status = EFI_SUCCESS;\r
443 if ((Private->HttpBootCallback != NULL) && (Dhcp6Event != Dhcp6SelectAdvertise)) {\r
444 Received = (BOOLEAN)(Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);\r
445 Status = Private->HttpBootCallback->Callback (\r
446 Private->HttpBootCallback,\r
447 HttpBootDhcp6,\r
448 Received,\r
449 Packet->Length,\r
450 &Packet->Dhcp6\r
451 );\r
95b5c32f
FS
452 if (EFI_ERROR (Status)) {\r
453 return EFI_ABORTED;\r
454 }\r
455 }\r
d1050b9d 456\r
95b5c32f 457 switch (Dhcp6Event) {\r
d1050b9d
MK
458 case Dhcp6RcvdAdvertise:\r
459 Status = EFI_NOT_READY;\r
460 if (Packet->Length > HTTP_BOOT_DHCP6_PACKET_MAX_SIZE) {\r
461 //\r
462 // Ignore the incoming packets which exceed the maximum length.\r
463 //\r
464 break;\r
465 }\r
466\r
467 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
468 //\r
469 // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
470 // the OfferIndex and OfferCount.\r
471 // If error happens, just ignore this packet and continue to wait more offer.\r
472 //\r
473 HttpBootCacheDhcp6Offer (Private, Packet);\r
474 }\r
f75a7f56 475\r
632dcfd6 476 break;\r
d1050b9d
MK
477\r
478 case Dhcp6SelectAdvertise:\r
95b5c32f 479 //\r
d1050b9d
MK
480 // Select offer by the default policy or by order, and record the SelectIndex\r
481 // and SelectProxyType.\r
95b5c32f 482 //\r
d1050b9d 483 HttpBootSelectDhcpOffer (Private);\r
95b5c32f 484\r
d1050b9d
MK
485 if (Private->SelectIndex == 0) {\r
486 Status = EFI_ABORTED;\r
487 } else {\r
488 ASSERT (NewPacket != NULL);\r
489 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
490 *NewPacket = AllocateZeroPool (SelectAd->Size);\r
491 if (*NewPacket == NULL) {\r
492 return EFI_OUT_OF_RESOURCES;\r
493 }\r
494\r
495 CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
95b5c32f 496 }\r
f75a7f56 497\r
d1050b9d
MK
498 break;\r
499\r
500 default:\r
501 break;\r
b659408b
ZL
502 }\r
503\r
f75a7f56 504 return Status;\r
b659408b
ZL
505}\r
506\r
507/**\r
508 Check whether IP driver could route the message which will be sent to ServerIp address.\r
f75a7f56 509\r
b659408b
ZL
510 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid\r
511 route is found in IP6 route table, the address will be filed in GatewayAddr and return.\r
512\r
513 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
514 @param[in] TimeOutInSecond Timeout value in seconds.\r
515 @param[out] GatewayAddr Pointer to store the gateway IP address.\r
516\r
517 @retval EFI_SUCCESS Found a valid gateway address successfully.\r
518 @retval EFI_TIMEOUT The operation is time out.\r
c36b7b51 519 @retval Other Unexpected error happened.\r
f75a7f56 520\r
b659408b
ZL
521**/\r
522EFI_STATUS\r
523HttpBootCheckRouteTable (\r
d1050b9d
MK
524 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
525 IN UINTN TimeOutInSecond,\r
526 OUT EFI_IPv6_ADDRESS *GatewayAddr\r
b659408b
ZL
527 )\r
528{\r
d1050b9d
MK
529 EFI_STATUS Status;\r
530 EFI_IP6_PROTOCOL *Ip6;\r
531 EFI_IP6_MODE_DATA Ip6ModeData;\r
532 UINTN Index;\r
533 EFI_EVENT TimeOutEvt;\r
534 UINTN RetryCount;\r
535 BOOLEAN GatewayIsFound;\r
b659408b
ZL
536\r
537 ASSERT (GatewayAddr != NULL);\r
538 ASSERT (Private != NULL);\r
539\r
540 Ip6 = Private->Ip6;\r
541 GatewayIsFound = FALSE;\r
542 RetryCount = 0;\r
543 TimeOutEvt = NULL;\r
544 Status = EFI_SUCCESS;\r
545 ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));\r
546\r
547 while (TRUE) {\r
548 Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);\r
549 if (EFI_ERROR (Status)) {\r
550 goto ON_EXIT;\r
551 }\r
f75a7f56 552\r
b659408b
ZL
553 //\r
554 // Find out the gateway address which can route the message which send to ServerIp.\r
555 //\r
556 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {\r
557 if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {\r
558 IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);\r
559 GatewayIsFound = TRUE;\r
560 break;\r
561 }\r
562 }\r
563\r
564 if (Ip6ModeData.AddressList != NULL) {\r
565 FreePool (Ip6ModeData.AddressList);\r
566 }\r
d1050b9d 567\r
b659408b
ZL
568 if (Ip6ModeData.GroupTable != NULL) {\r
569 FreePool (Ip6ModeData.GroupTable);\r
570 }\r
d1050b9d 571\r
b659408b
ZL
572 if (Ip6ModeData.RouteTable != NULL) {\r
573 FreePool (Ip6ModeData.RouteTable);\r
574 }\r
d1050b9d 575\r
b659408b
ZL
576 if (Ip6ModeData.NeighborCache != NULL) {\r
577 FreePool (Ip6ModeData.NeighborCache);\r
578 }\r
d1050b9d 579\r
b659408b
ZL
580 if (Ip6ModeData.PrefixTable != NULL) {\r
581 FreePool (Ip6ModeData.PrefixTable);\r
582 }\r
d1050b9d 583\r
b659408b
ZL
584 if (Ip6ModeData.IcmpTypeList != NULL) {\r
585 FreePool (Ip6ModeData.IcmpTypeList);\r
586 }\r
f75a7f56 587\r
d1050b9d 588 if (GatewayIsFound || (RetryCount == TimeOutInSecond)) {\r
b659408b
ZL
589 break;\r
590 }\r
f75a7f56 591\r
b659408b 592 RetryCount++;\r
f75a7f56 593\r
b659408b
ZL
594 //\r
595 // Delay 1 second then recheck it again.\r
596 //\r
597 if (TimeOutEvt == NULL) {\r
598 Status = gBS->CreateEvent (\r
599 EVT_TIMER,\r
600 TPL_CALLBACK,\r
601 NULL,\r
602 NULL,\r
603 &TimeOutEvt\r
604 );\r
605 if (EFI_ERROR (Status)) {\r
606 goto ON_EXIT;\r
607 }\r
608 }\r
609\r
610 Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);\r
611 if (EFI_ERROR (Status)) {\r
612 goto ON_EXIT;\r
613 }\r
d1050b9d 614\r
b659408b
ZL
615 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {\r
616 Ip6->Poll (Ip6);\r
617 }\r
618 }\r
f75a7f56 619\r
b659408b
ZL
620ON_EXIT:\r
621 if (TimeOutEvt != NULL) {\r
622 gBS->CloseEvent (TimeOutEvt);\r
623 }\r
f75a7f56 624\r
b659408b
ZL
625 if (GatewayIsFound) {\r
626 Status = EFI_SUCCESS;\r
627 } else if (RetryCount == TimeOutInSecond) {\r
628 Status = EFI_TIMEOUT;\r
629 }\r
630\r
f75a7f56 631 return Status;\r
b659408b
ZL
632}\r
633\r
634/**\r
635 Set the IP6 policy to Automatic.\r
636\r
637 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
638\r
c36b7b51
AC
639 @retval EFI_SUCCESS Switch the IP policy successfully.\r
640 @retval Others Unexpected error happened.\r
b659408b
ZL
641\r
642**/\r
643EFI_STATUS\r
644HttpBootSetIp6Policy (\r
d1050b9d 645 IN HTTP_BOOT_PRIVATE_DATA *Private\r
b659408b
ZL
646 )\r
647{\r
d1050b9d
MK
648 EFI_IP6_CONFIG_POLICY Policy;\r
649 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
650 EFI_STATUS Status;\r
651 UINTN DataSize;\r
b659408b 652\r
d1050b9d
MK
653 Ip6Config = Private->Ip6Config;\r
654 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);\r
f75a7f56 655\r
b659408b
ZL
656 //\r
657 // Get and store the current policy of IP6 driver.\r
658 //\r
659 Status = Ip6Config->GetData (\r
660 Ip6Config,\r
661 Ip6ConfigDataTypePolicy,\r
662 &DataSize,\r
663 &Policy\r
664 );\r
665 if (EFI_ERROR (Status)) {\r
666 return Status;\r
667 }\r
668\r
669 if (Policy == Ip6ConfigPolicyManual) {\r
670 Policy = Ip6ConfigPolicyAutomatic;\r
671 Status = Ip6Config->SetData (\r
672 Ip6Config,\r
673 Ip6ConfigDataTypePolicy,\r
d1050b9d 674 sizeof (EFI_IP6_CONFIG_POLICY),\r
b659408b
ZL
675 &Policy\r
676 );\r
677 if (EFI_ERROR (Status)) {\r
678 return Status;\r
679 }\r
680 }\r
d1050b9d 681\r
b659408b
ZL
682 return EFI_SUCCESS;\r
683}\r
684\r
685/**\r
686 This function will register the default DNS addresses to the network device.\r
f75a7f56 687\r
b659408b
ZL
688 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
689 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
690 @param[in] DnsServerData Point a list of DNS server address in an array\r
691 of EFI_IPv6_ADDRESS instances.\r
692\r
693 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
694 @retval Others Failed to configure the address.\r
695\r
696**/\r
697EFI_STATUS\r
698HttpBootSetIp6Dns (\r
d1050b9d
MK
699 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
700 IN UINTN DataLength,\r
701 IN VOID *DnsServerData\r
b659408b
ZL
702 )\r
703{\r
d1050b9d 704 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
f75a7f56 705\r
b659408b
ZL
706 ASSERT (Private->UsingIpv6);\r
707\r
708 Ip6Config = Private->Ip6Config;\r
f75a7f56 709\r
b659408b
ZL
710 return Ip6Config->SetData (\r
711 Ip6Config,\r
712 Ip6ConfigDataTypeDnsServer,\r
713 DataLength,\r
714 DnsServerData\r
715 );\r
716}\r
717\r
718/**\r
719 This function will register the IPv6 gateway address to the network device.\r
f75a7f56 720\r
b659408b
ZL
721 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
722\r
723 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
724 @retval Others Failed to configure the address.\r
725\r
726**/\r
727EFI_STATUS\r
728HttpBootSetIp6Gateway (\r
d1050b9d 729 IN HTTP_BOOT_PRIVATE_DATA *Private\r
b659408b
ZL
730 )\r
731{\r
d1050b9d
MK
732 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
733 EFI_STATUS Status;\r
b659408b
ZL
734\r
735 ASSERT (Private->UsingIpv6);\r
736 Ip6Config = Private->Ip6Config;\r
f75a7f56 737\r
b659408b 738 //\r
f75a7f56 739 // Set the default gateway address.\r
b659408b
ZL
740 //\r
741 if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) {\r
742 Status = Ip6Config->SetData (\r
743 Ip6Config,\r
744 Ip6ConfigDataTypeGateway,\r
745 sizeof (EFI_IPv6_ADDRESS),\r
746 &Private->GatewayIp.v6\r
747 );\r
d1050b9d 748 if (EFI_ERROR (Status)) {\r
b659408b
ZL
749 return Status;\r
750 }\r
751 }\r
752\r
753 return EFI_SUCCESS;\r
754}\r
755\r
756/**\r
757 This function will register the station IP address.\r
f75a7f56 758\r
b659408b
ZL
759 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
760\r
761 @retval EFI_SUCCESS The new IP address has been configured successfully.\r
762 @retval Others Failed to configure the address.\r
763\r
764**/\r
765EFI_STATUS\r
766HttpBootSetIp6Address (\r
d1050b9d
MK
767 IN HTTP_BOOT_PRIVATE_DATA *Private\r
768 )\r
b659408b 769{\r
d1050b9d
MK
770 EFI_STATUS Status;\r
771 EFI_IP6_PROTOCOL *Ip6;\r
772 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
773 EFI_IP6_CONFIG_POLICY Policy;\r
774 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;\r
775 EFI_IPv6_ADDRESS *Ip6Addr;\r
776 EFI_IPv6_ADDRESS GatewayAddr;\r
777 EFI_IP6_CONFIG_DATA Ip6CfgData;\r
778 EFI_EVENT MappedEvt;\r
779 UINTN DataSize;\r
780 BOOLEAN IsAddressOk;\r
781 UINTN Index;\r
b659408b
ZL
782\r
783 ASSERT (Private->UsingIpv6);\r
f75a7f56 784\r
b659408b
ZL
785 MappedEvt = NULL;\r
786 IsAddressOk = FALSE;\r
787 Ip6Addr = NULL;\r
788 Ip6Cfg = Private->Ip6Config;\r
789 Ip6 = Private->Ip6;\r
f75a7f56 790\r
b659408b
ZL
791 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
792 CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
793 ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA));\r
f75a7f56 794\r
d1050b9d
MK
795 Ip6CfgData.AcceptIcmpErrors = TRUE;\r
796 Ip6CfgData.DefaultProtocol = IP6_ICMP;\r
797 Ip6CfgData.HopLimit = HTTP_BOOT_DEFAULT_HOPLIMIT;\r
798 Ip6CfgData.ReceiveTimeout = HTTP_BOOT_DEFAULT_LIFETIME;\r
799 Ip6CfgData.TransmitTimeout = HTTP_BOOT_DEFAULT_LIFETIME;\r
f75a7f56 800\r
b659408b
ZL
801 Status = Ip6->Configure (Ip6, &Ip6CfgData);\r
802 if (EFI_ERROR (Status)) {\r
803 goto ON_EXIT;\r
804 }\r
805\r
806 //\r
807 // Retrieve the gateway address from IP6 route table.\r
808 //\r
809 Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);\r
810 if (EFI_ERROR (Status)) {\r
811 Private->NoGateway = TRUE;\r
812 } else {\r
813 IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr);\r
814 }\r
815\r
816 //\r
817 // Set the new address by Ip6ConfigProtocol manually.\r
818 //\r
819 Policy = Ip6ConfigPolicyManual;\r
820 Status = Ip6Cfg->SetData (\r
821 Ip6Cfg,\r
822 Ip6ConfigDataTypePolicy,\r
d1050b9d 823 sizeof (EFI_IP6_CONFIG_POLICY),\r
b659408b
ZL
824 &Policy\r
825 );\r
826 if (EFI_ERROR (Status)) {\r
827 goto ON_EXIT;\r
828 }\r
f75a7f56 829\r
b659408b
ZL
830 //\r
831 // Create a notify event to set address flag when DAD if IP6 driver succeeded.\r
832 //\r
833 Status = gBS->CreateEvent (\r
834 EVT_NOTIFY_SIGNAL,\r
835 TPL_NOTIFY,\r
836 HttpBootCommonNotify,\r
837 &IsAddressOk,\r
838 &MappedEvt\r
839 );\r
840 if (EFI_ERROR (Status)) {\r
841 goto ON_EXIT;\r
842 }\r
f75a7f56 843\r
b659408b
ZL
844 //\r
845 // Set static host ip6 address. This is a asynchronous process.\r
846 //\r
847 Status = Ip6Cfg->RegisterDataNotify (\r
848 Ip6Cfg,\r
849 Ip6ConfigDataTypeManualAddress,\r
850 MappedEvt\r
851 );\r
d1050b9d 852 if (EFI_ERROR (Status)) {\r
b659408b
ZL
853 goto ON_EXIT;\r
854 }\r
855\r
856 Status = Ip6Cfg->SetData (\r
857 Ip6Cfg,\r
858 Ip6ConfigDataTypeManualAddress,\r
859 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS),\r
860 &CfgAddr\r
f75a7f56 861 );\r
d1050b9d 862 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
b659408b
ZL
863 goto ON_EXIT;\r
864 } else if (Status == EFI_NOT_READY) {\r
865 //\r
866 // Poll the network until the asynchronous process is finished.\r
867 //\r
868 while (!IsAddressOk) {\r
869 Ip6->Poll (Ip6);\r
870 }\r
d1050b9d 871\r
b659408b
ZL
872 //\r
873 // Check whether the Ip6 Address setting is successed.\r
874 //\r
875 DataSize = 0;\r
d1050b9d
MK
876 Status = Ip6Cfg->GetData (\r
877 Ip6Cfg,\r
878 Ip6ConfigDataTypeManualAddress,\r
879 &DataSize,\r
880 NULL\r
881 );\r
882 if ((Status != EFI_BUFFER_TOO_SMALL) || (DataSize == 0)) {\r
b659408b
ZL
883 Status = EFI_DEVICE_ERROR;\r
884 goto ON_EXIT;\r
885 }\r
f75a7f56 886\r
b659408b
ZL
887 Ip6Addr = AllocatePool (DataSize);\r
888 if (Ip6Addr == NULL) {\r
889 return EFI_OUT_OF_RESOURCES;\r
890 }\r
d1050b9d 891\r
b659408b
ZL
892 Status = Ip6Cfg->GetData (\r
893 Ip6Cfg,\r
894 Ip6ConfigDataTypeManualAddress,\r
895 &DataSize,\r
d1050b9d 896 (VOID *)Ip6Addr\r
b659408b
ZL
897 );\r
898 if (EFI_ERROR (Status)) {\r
899 Status = EFI_DEVICE_ERROR;\r
900 goto ON_EXIT;\r
901 }\r
902\r
d1050b9d 903 for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) {\r
b659408b
ZL
904 if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) {\r
905 break;\r
906 }\r
907 }\r
d1050b9d 908\r
b659408b
ZL
909 if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {\r
910 Status = EFI_ABORTED;\r
911 goto ON_EXIT;\r
f75a7f56 912 }\r
b659408b 913 }\r
f75a7f56 914\r
b659408b
ZL
915ON_EXIT:\r
916 if (MappedEvt != NULL) {\r
917 Ip6Cfg->UnregisterDataNotify (\r
918 Ip6Cfg,\r
919 Ip6ConfigDataTypeManualAddress,\r
920 MappedEvt\r
921 );\r
922 gBS->CloseEvent (MappedEvt);\r
923 }\r
924\r
925 if (Ip6Addr != NULL) {\r
926 FreePool (Ip6Addr);\r
927 }\r
f75a7f56
LG
928\r
929 return Status;\r
b659408b
ZL
930}\r
931\r
932/**\r
933 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.\r
934\r
935 @param[in] Private Pointer to HTTP_BOOT private data.\r
936\r
937 @retval EFI_SUCCESS The S.A.R.R process successfully finished.\r
938 @retval Others Failed to finish the S.A.R.R process.\r
939\r
940**/\r
941EFI_STATUS\r
942HttpBootDhcp6Sarr (\r
d1050b9d 943 IN HTTP_BOOT_PRIVATE_DATA *Private\r
b659408b
ZL
944 )\r
945{\r
d1050b9d
MK
946 EFI_DHCP6_PROTOCOL *Dhcp6;\r
947 EFI_DHCP6_CONFIG_DATA Config;\r
948 EFI_DHCP6_MODE_DATA Mode;\r
949 EFI_DHCP6_RETRANSMISSION *Retransmit;\r
950 EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM];\r
951 UINT32 OptCount;\r
952 UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE];\r
953 EFI_STATUS Status;\r
b659408b
ZL
954\r
955 Dhcp6 = Private->Dhcp6;\r
956 ASSERT (Dhcp6 != NULL);\r
957\r
958 //\r
959 // Build options list for the request packet.\r
960 //\r
961 OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer);\r
d1050b9d 962 ASSERT (OptCount > 0);\r
f75a7f56 963\r
b659408b
ZL
964 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));\r
965 if (Retransmit == NULL) {\r
966 return EFI_OUT_OF_RESOURCES;\r
967 }\r
f75a7f56 968\r
b659408b
ZL
969 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));\r
970 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
f75a7f56 971\r
b659408b
ZL
972 Config.OptionCount = OptCount;\r
973 Config.OptionList = OptList;\r
974 Config.Dhcp6Callback = HttpBootDhcp6CallBack;\r
975 Config.CallbackContext = Private;\r
976 Config.IaInfoEvent = NULL;\r
977 Config.RapidCommit = FALSE;\r
978 Config.ReconfigureAccept = FALSE;\r
979 Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ());\r
980 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;\r
981 Config.SolicitRetransmission = Retransmit;\r
982 Retransmit->Irt = 4;\r
983 Retransmit->Mrc = 4;\r
984 Retransmit->Mrt = 32;\r
985 Retransmit->Mrd = 60;\r
f75a7f56 986\r
b659408b
ZL
987 //\r
988 // Configure the DHCPv6 instance for HTTP boot.\r
989 //\r
990 Status = Dhcp6->Configure (Dhcp6, &Config);\r
991 FreePool (Retransmit);\r
992 if (EFI_ERROR (Status)) {\r
993 goto ON_EXIT;\r
994 }\r
d1050b9d 995\r
b659408b
ZL
996 //\r
997 // Initialize the record fields for DHCPv6 offer in private data.\r
998 //\r
d1050b9d
MK
999 Private->OfferNum = 0;\r
1000 Private->SelectIndex = 0;\r
b659408b
ZL
1001 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
1002 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
f75a7f56 1003\r
b659408b
ZL
1004 //\r
1005 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.\r
1006 //\r
1007 Status = Dhcp6->Start (Dhcp6);\r
1008 if (EFI_ERROR (Status)) {\r
1009 goto ON_EXIT;\r
1010 }\r
f75a7f56 1011\r
b659408b
ZL
1012 //\r
1013 // Get the acquired IPv6 address and store them.\r
1014 //\r
1015 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);\r
1016 if (EFI_ERROR (Status)) {\r
1017 goto ON_EXIT;\r
1018 }\r
f75a7f56 1019\r
b659408b
ZL
1020 ASSERT (Mode.Ia->State == Dhcp6Bound);\r
1021 CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
f75a7f56 1022\r
b659408b
ZL
1023 AsciiPrint ("\n Station IPv6 address is ");\r
1024 HttpBootShowIp6Addr (&Private->StationIp.v6);\r
1025 AsciiPrint ("\n");\r
f75a7f56 1026\r
b659408b
ZL
1027ON_EXIT:\r
1028 if (EFI_ERROR (Status)) {\r
1029 Dhcp6->Stop (Dhcp6);\r
1030 Dhcp6->Configure (Dhcp6, NULL);\r
1031 } else {\r
1032 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
b659408b 1033 Dhcp6->Configure (Dhcp6, &Config);\r
ce22514e
ZL
1034 if (Mode.ClientId != NULL) {\r
1035 FreePool (Mode.ClientId);\r
1036 }\r
d1050b9d 1037\r
ce22514e
ZL
1038 if (Mode.Ia != NULL) {\r
1039 FreePool (Mode.Ia);\r
1040 }\r
b659408b
ZL
1041 }\r
1042\r
f75a7f56 1043 return Status;\r
b659408b 1044}\r