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