]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDhcp6.c
NetworkPkg: Check for the max DHCP packet length before use it.
[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
142c00c3 4Copyright (c) 2015 - 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
142c00c3 44 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO);\r
b659408b
ZL
45 OptList[Index]->OpLen = HTONS (8);\r
46 OptEnt.Oro = (HTTP_BOOT_DHCP6_OPTION_ORO *) OptList[Index]->Data;\r
142c00c3
ZL
47 OptEnt.Oro->OpCode[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL);\r
48 OptEnt.Oro->OpCode[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM);\r
49 OptEnt.Oro->OpCode[2] = HTONS(DHCP6_OPT_DNS_SERVERS);\r
50 OptEnt.Oro->OpCode[3] = HTONS(DHCP6_OPT_VENDOR_CLASS);\r
b659408b
ZL
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
142c00c3 57 OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI);\r
b659408b
ZL
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
142c00c3 77 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH);\r
b659408b
ZL
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
142c00c3 88 OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS);\r
b659408b
ZL
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
142c00c3 214 if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) {\r
b659408b 215 Options[HTTP_BOOT_DHCP6_IDX_IA_NA] = Option;\r
142c00c3 216 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) {\r
b659408b
ZL
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
142c00c3 221 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) {\r
b659408b 222 Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
142c00c3 223 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {\r
b659408b 224 Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS] = Option;\r
142c00c3 225 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) {\r
b659408b
ZL
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
142c00c3 241 DHCP6_OPT_STATUS_CODE\r
b659408b
ZL
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
b659408b
ZL
421\r
422 ASSERT (Packet != NULL);\r
423 \r
424 Private = (HTTP_BOOT_PRIVATE_DATA *) Context;\r
425 Status = EFI_SUCCESS;\r
426 switch (Dhcp6Event) {\r
427 \r
428 case Dhcp6RcvdAdvertise:\r
429 Status = EFI_NOT_READY;\r
632dcfd6
FS
430 if (Packet->Length > HTTP_BOOT_DHCP6_PACKET_MAX_SIZE) {\r
431 //\r
432 // Ignore the incoming packets which exceed the maximum length.\r
433 //\r
434 break;\r
435 }\r
b659408b
ZL
436 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
437 //\r
438 // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
439 // the OfferIndex and OfferCount.\r
440 //\r
441 HttpBootCacheDhcp6Offer (Private, Packet);\r
442 }\r
443 break;\r
444\r
445 case Dhcp6SelectAdvertise:\r
446 //\r
447 // Select offer by the default policy or by order, and record the SelectIndex\r
448 // and SelectProxyType.\r
449 //\r
450 HttpBootSelectDhcpOffer (Private);\r
451\r
452 if (Private->SelectIndex == 0) {\r
453 Status = EFI_ABORTED;\r
454 } else {\r
455 ASSERT (NewPacket != NULL);\r
456 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
457 *NewPacket = AllocateZeroPool (SelectAd->Size);\r
7c275b3c
ZL
458 if (*NewPacket == NULL) {\r
459 return EFI_OUT_OF_RESOURCES;\r
460 }\r
b659408b
ZL
461 CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
462 }\r
463 break;\r
464 \r
465 default:\r
466 break;\r
467 }\r
468\r
469 return Status; \r
470}\r
471\r
472/**\r
473 Check whether IP driver could route the message which will be sent to ServerIp address.\r
474 \r
475 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid\r
476 route is found in IP6 route table, the address will be filed in GatewayAddr and return.\r
477\r
478 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
479 @param[in] TimeOutInSecond Timeout value in seconds.\r
480 @param[out] GatewayAddr Pointer to store the gateway IP address.\r
481\r
482 @retval EFI_SUCCESS Found a valid gateway address successfully.\r
483 @retval EFI_TIMEOUT The operation is time out.\r
484 @retval Other Unexpect error happened.\r
485 \r
486**/\r
487EFI_STATUS\r
488HttpBootCheckRouteTable (\r
489 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
490 IN UINTN TimeOutInSecond,\r
491 OUT EFI_IPv6_ADDRESS *GatewayAddr\r
492 )\r
493{\r
494 EFI_STATUS Status;\r
495 EFI_IP6_PROTOCOL *Ip6;\r
496 EFI_IP6_MODE_DATA Ip6ModeData;\r
497 UINTN Index;\r
498 EFI_EVENT TimeOutEvt;\r
499 UINTN RetryCount;\r
500 BOOLEAN GatewayIsFound;\r
501\r
502 ASSERT (GatewayAddr != NULL);\r
503 ASSERT (Private != NULL);\r
504\r
505 Ip6 = Private->Ip6;\r
506 GatewayIsFound = FALSE;\r
507 RetryCount = 0;\r
508 TimeOutEvt = NULL;\r
509 Status = EFI_SUCCESS;\r
510 ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));\r
511\r
512 while (TRUE) {\r
513 Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);\r
514 if (EFI_ERROR (Status)) {\r
515 goto ON_EXIT;\r
516 }\r
517 \r
518 //\r
519 // Find out the gateway address which can route the message which send to ServerIp.\r
520 //\r
521 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {\r
522 if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {\r
523 IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);\r
524 GatewayIsFound = TRUE;\r
525 break;\r
526 }\r
527 }\r
528\r
529 if (Ip6ModeData.AddressList != NULL) {\r
530 FreePool (Ip6ModeData.AddressList);\r
531 }\r
532 if (Ip6ModeData.GroupTable != NULL) {\r
533 FreePool (Ip6ModeData.GroupTable);\r
534 }\r
535 if (Ip6ModeData.RouteTable != NULL) {\r
536 FreePool (Ip6ModeData.RouteTable);\r
537 }\r
538 if (Ip6ModeData.NeighborCache != NULL) {\r
539 FreePool (Ip6ModeData.NeighborCache);\r
540 }\r
541 if (Ip6ModeData.PrefixTable != NULL) {\r
542 FreePool (Ip6ModeData.PrefixTable);\r
543 }\r
544 if (Ip6ModeData.IcmpTypeList != NULL) {\r
545 FreePool (Ip6ModeData.IcmpTypeList);\r
546 }\r
547 \r
548 if (GatewayIsFound || RetryCount == TimeOutInSecond) {\r
549 break;\r
550 }\r
551 \r
552 RetryCount++;\r
553 \r
554 //\r
555 // Delay 1 second then recheck it again.\r
556 //\r
557 if (TimeOutEvt == NULL) {\r
558 Status = gBS->CreateEvent (\r
559 EVT_TIMER,\r
560 TPL_CALLBACK,\r
561 NULL,\r
562 NULL,\r
563 &TimeOutEvt\r
564 );\r
565 if (EFI_ERROR (Status)) {\r
566 goto ON_EXIT;\r
567 }\r
568 }\r
569\r
570 Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);\r
571 if (EFI_ERROR (Status)) {\r
572 goto ON_EXIT;\r
573 }\r
574 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {\r
575 Ip6->Poll (Ip6);\r
576 }\r
577 }\r
578 \r
579ON_EXIT:\r
580 if (TimeOutEvt != NULL) {\r
581 gBS->CloseEvent (TimeOutEvt);\r
582 }\r
583 \r
584 if (GatewayIsFound) {\r
585 Status = EFI_SUCCESS;\r
586 } else if (RetryCount == TimeOutInSecond) {\r
587 Status = EFI_TIMEOUT;\r
588 }\r
589\r
590 return Status; \r
591}\r
592\r
593/**\r
594 Set the IP6 policy to Automatic.\r
595\r
596 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
597\r
598 @retval EFI_SUCCESS Switch the IP policy succesfully.\r
599 @retval Others Unexpect error happened.\r
600\r
601**/\r
602EFI_STATUS\r
603HttpBootSetIp6Policy (\r
604 IN HTTP_BOOT_PRIVATE_DATA *Private\r
605 )\r
606{\r
607 EFI_IP6_CONFIG_POLICY Policy;\r
608 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
609 EFI_STATUS Status;\r
610 UINTN DataSize;\r
611\r
612 Ip6Config = Private->Ip6Config;\r
613 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);\r
614 \r
615 //\r
616 // Get and store the current policy of IP6 driver.\r
617 //\r
618 Status = Ip6Config->GetData (\r
619 Ip6Config,\r
620 Ip6ConfigDataTypePolicy,\r
621 &DataSize,\r
622 &Policy\r
623 );\r
624 if (EFI_ERROR (Status)) {\r
625 return Status;\r
626 }\r
627\r
628 if (Policy == Ip6ConfigPolicyManual) {\r
629 Policy = Ip6ConfigPolicyAutomatic;\r
630 Status = Ip6Config->SetData (\r
631 Ip6Config,\r
632 Ip6ConfigDataTypePolicy,\r
633 sizeof(EFI_IP6_CONFIG_POLICY),\r
634 &Policy\r
635 );\r
636 if (EFI_ERROR (Status)) {\r
637 return Status;\r
638 }\r
639 }\r
640 return EFI_SUCCESS;\r
641}\r
642\r
643/**\r
644 This function will register the default DNS addresses to the network device.\r
645 \r
646 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
647 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
648 @param[in] DnsServerData Point a list of DNS server address in an array\r
649 of EFI_IPv6_ADDRESS instances.\r
650\r
651 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
652 @retval Others Failed to configure the address.\r
653\r
654**/\r
655EFI_STATUS\r
656HttpBootSetIp6Dns (\r
657 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
658 IN UINTN DataLength,\r
659 IN VOID *DnsServerData\r
660 )\r
661{\r
662 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
663 \r
664 ASSERT (Private->UsingIpv6);\r
665\r
666 Ip6Config = Private->Ip6Config;\r
667 \r
668 return Ip6Config->SetData (\r
669 Ip6Config,\r
670 Ip6ConfigDataTypeDnsServer,\r
671 DataLength,\r
672 DnsServerData\r
673 );\r
674}\r
675\r
676/**\r
677 This function will register the IPv6 gateway address to the network device.\r
678 \r
679 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
680\r
681 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
682 @retval Others Failed to configure the address.\r
683\r
684**/\r
685EFI_STATUS\r
686HttpBootSetIp6Gateway (\r
687 IN HTTP_BOOT_PRIVATE_DATA *Private\r
688 )\r
689{\r
690 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
691 EFI_STATUS Status;\r
692\r
693 ASSERT (Private->UsingIpv6);\r
694 Ip6Config = Private->Ip6Config;\r
695 \r
696 //\r
697 // Set the default gateway address. \r
698 //\r
699 if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) {\r
700 Status = Ip6Config->SetData (\r
701 Ip6Config,\r
702 Ip6ConfigDataTypeGateway,\r
703 sizeof (EFI_IPv6_ADDRESS),\r
704 &Private->GatewayIp.v6\r
705 );\r
706 if (EFI_ERROR(Status)) {\r
707 return Status;\r
708 }\r
709 }\r
710\r
711 return EFI_SUCCESS;\r
712}\r
713\r
714/**\r
715 This function will register the station IP address.\r
716 \r
717 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
718\r
719 @retval EFI_SUCCESS The new IP address has been configured successfully.\r
720 @retval Others Failed to configure the address.\r
721\r
722**/\r
723EFI_STATUS\r
724HttpBootSetIp6Address (\r
725 IN HTTP_BOOT_PRIVATE_DATA *Private\r
726)\r
727{\r
728 EFI_STATUS Status;\r
729 EFI_IP6_PROTOCOL *Ip6;\r
730 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
731 EFI_IP6_CONFIG_POLICY Policy;\r
732 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;\r
733 EFI_IPv6_ADDRESS *Ip6Addr;\r
734 EFI_IPv6_ADDRESS GatewayAddr;\r
735 EFI_IP6_CONFIG_DATA Ip6CfgData;\r
736 EFI_EVENT MappedEvt; \r
737 UINTN DataSize;\r
738 BOOLEAN IsAddressOk;\r
739 UINTN Index;\r
740\r
741 ASSERT (Private->UsingIpv6);\r
742 \r
743 MappedEvt = NULL;\r
744 IsAddressOk = FALSE;\r
745 Ip6Addr = NULL;\r
746 Ip6Cfg = Private->Ip6Config;\r
747 Ip6 = Private->Ip6;\r
748 \r
749 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
750 CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
751 ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA));\r
752 \r
753 Ip6CfgData.AcceptIcmpErrors = TRUE;\r
754 Ip6CfgData.DefaultProtocol = IP6_ICMP;\r
755 Ip6CfgData.HopLimit = HTTP_BOOT_DEFAULT_HOPLIMIT;\r
756 Ip6CfgData.ReceiveTimeout = HTTP_BOOT_DEFAULT_LIFETIME;\r
757 Ip6CfgData.TransmitTimeout = HTTP_BOOT_DEFAULT_LIFETIME;\r
758 \r
759 Status = Ip6->Configure (Ip6, &Ip6CfgData);\r
760 if (EFI_ERROR (Status)) {\r
761 goto ON_EXIT;\r
762 }\r
763\r
764 //\r
765 // Retrieve the gateway address from IP6 route table.\r
766 //\r
767 Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);\r
768 if (EFI_ERROR (Status)) {\r
769 Private->NoGateway = TRUE;\r
770 } else {\r
771 IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr);\r
772 }\r
773\r
774 //\r
775 // Set the new address by Ip6ConfigProtocol manually.\r
776 //\r
777 Policy = Ip6ConfigPolicyManual;\r
778 Status = Ip6Cfg->SetData (\r
779 Ip6Cfg,\r
780 Ip6ConfigDataTypePolicy,\r
781 sizeof(EFI_IP6_CONFIG_POLICY),\r
782 &Policy\r
783 );\r
784 if (EFI_ERROR (Status)) {\r
785 goto ON_EXIT;\r
786 }\r
787 \r
788 //\r
789 // Create a notify event to set address flag when DAD if IP6 driver succeeded.\r
790 //\r
791 Status = gBS->CreateEvent (\r
792 EVT_NOTIFY_SIGNAL,\r
793 TPL_NOTIFY,\r
794 HttpBootCommonNotify,\r
795 &IsAddressOk,\r
796 &MappedEvt\r
797 );\r
798 if (EFI_ERROR (Status)) {\r
799 goto ON_EXIT;\r
800 }\r
801 \r
802 //\r
803 // Set static host ip6 address. This is a asynchronous process.\r
804 //\r
805 Status = Ip6Cfg->RegisterDataNotify (\r
806 Ip6Cfg,\r
807 Ip6ConfigDataTypeManualAddress,\r
808 MappedEvt\r
809 );\r
810 if (EFI_ERROR(Status)) {\r
811 goto ON_EXIT;\r
812 }\r
813\r
814 Status = Ip6Cfg->SetData (\r
815 Ip6Cfg,\r
816 Ip6ConfigDataTypeManualAddress,\r
817 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS),\r
818 &CfgAddr\r
819 ); \r
820 if (EFI_ERROR (Status) && Status != EFI_NOT_READY) {\r
821 goto ON_EXIT;\r
822 } else if (Status == EFI_NOT_READY) {\r
823 //\r
824 // Poll the network until the asynchronous process is finished.\r
825 //\r
826 while (!IsAddressOk) {\r
827 Ip6->Poll (Ip6);\r
828 }\r
829 //\r
830 // Check whether the Ip6 Address setting is successed.\r
831 //\r
832 DataSize = 0;\r
833 Status = Ip6Cfg->GetData (\r
834 Ip6Cfg,\r
835 Ip6ConfigDataTypeManualAddress,\r
836 &DataSize,\r
837 NULL\r
838 );\r
839 if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) {\r
840 Status = EFI_DEVICE_ERROR;\r
841 goto ON_EXIT;\r
842 }\r
843 \r
844 Ip6Addr = AllocatePool (DataSize);\r
845 if (Ip6Addr == NULL) {\r
846 return EFI_OUT_OF_RESOURCES;\r
847 }\r
848 Status = Ip6Cfg->GetData (\r
849 Ip6Cfg,\r
850 Ip6ConfigDataTypeManualAddress,\r
851 &DataSize,\r
852 (VOID *) Ip6Addr\r
853 );\r
854 if (EFI_ERROR (Status)) {\r
855 Status = EFI_DEVICE_ERROR;\r
856 goto ON_EXIT;\r
857 }\r
858\r
859 for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index ++) {\r
860 if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) {\r
861 break;\r
862 }\r
863 }\r
864 if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {\r
865 Status = EFI_ABORTED;\r
866 goto ON_EXIT;\r
867 } \r
868 }\r
869 \r
870ON_EXIT:\r
871 if (MappedEvt != NULL) {\r
872 Ip6Cfg->UnregisterDataNotify (\r
873 Ip6Cfg,\r
874 Ip6ConfigDataTypeManualAddress,\r
875 MappedEvt\r
876 );\r
877 gBS->CloseEvent (MappedEvt);\r
878 }\r
879\r
880 if (Ip6Addr != NULL) {\r
881 FreePool (Ip6Addr);\r
882 }\r
883 \r
884 return Status; \r
885}\r
886\r
887/**\r
888 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.\r
889\r
890 @param[in] Private Pointer to HTTP_BOOT private data.\r
891\r
892 @retval EFI_SUCCESS The S.A.R.R process successfully finished.\r
893 @retval Others Failed to finish the S.A.R.R process.\r
894\r
895**/\r
896EFI_STATUS\r
897HttpBootDhcp6Sarr (\r
898 IN HTTP_BOOT_PRIVATE_DATA *Private\r
899 )\r
900{\r
901 EFI_DHCP6_PROTOCOL *Dhcp6;\r
902 EFI_DHCP6_CONFIG_DATA Config;\r
903 EFI_DHCP6_MODE_DATA Mode;\r
904 EFI_DHCP6_RETRANSMISSION *Retransmit;\r
905 EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM];\r
906 UINT32 OptCount;\r
907 UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE];\r
908 EFI_STATUS Status;\r
909\r
910 Dhcp6 = Private->Dhcp6;\r
911 ASSERT (Dhcp6 != NULL);\r
912\r
913 //\r
914 // Build options list for the request packet.\r
915 //\r
916 OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer);\r
917 ASSERT (OptCount >0);\r
918 \r
919 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));\r
920 if (Retransmit == NULL) {\r
921 return EFI_OUT_OF_RESOURCES;\r
922 }\r
923 \r
924 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));\r
925 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
926 \r
927 Config.OptionCount = OptCount;\r
928 Config.OptionList = OptList;\r
929 Config.Dhcp6Callback = HttpBootDhcp6CallBack;\r
930 Config.CallbackContext = Private;\r
931 Config.IaInfoEvent = NULL;\r
932 Config.RapidCommit = FALSE;\r
933 Config.ReconfigureAccept = FALSE;\r
934 Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ());\r
935 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;\r
936 Config.SolicitRetransmission = Retransmit;\r
937 Retransmit->Irt = 4;\r
938 Retransmit->Mrc = 4;\r
939 Retransmit->Mrt = 32;\r
940 Retransmit->Mrd = 60;\r
941 \r
942 //\r
943 // Configure the DHCPv6 instance for HTTP boot.\r
944 //\r
945 Status = Dhcp6->Configure (Dhcp6, &Config);\r
946 FreePool (Retransmit);\r
947 if (EFI_ERROR (Status)) {\r
948 goto ON_EXIT;\r
949 }\r
950 //\r
951 // Initialize the record fields for DHCPv6 offer in private data.\r
952 //\r
953 Private->OfferNum = 0;\r
954 Private->SelectIndex = 0;\r
955 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
956 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
957 \r
958 //\r
959 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.\r
960 //\r
961 Status = Dhcp6->Start (Dhcp6);\r
962 if (EFI_ERROR (Status)) {\r
963 goto ON_EXIT;\r
964 }\r
965 \r
966 //\r
967 // Get the acquired IPv6 address and store them.\r
968 //\r
969 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);\r
970 if (EFI_ERROR (Status)) {\r
971 goto ON_EXIT;\r
972 }\r
973 \r
974 ASSERT (Mode.Ia->State == Dhcp6Bound);\r
975 CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
976 \r
977 AsciiPrint ("\n Station IPv6 address is ");\r
978 HttpBootShowIp6Addr (&Private->StationIp.v6);\r
979 AsciiPrint ("\n");\r
980 \r
981ON_EXIT:\r
982 if (EFI_ERROR (Status)) {\r
983 Dhcp6->Stop (Dhcp6);\r
984 Dhcp6->Configure (Dhcp6, NULL);\r
985 } else {\r
986 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
b659408b 987 Dhcp6->Configure (Dhcp6, &Config);\r
ce22514e
ZL
988 if (Mode.ClientId != NULL) {\r
989 FreePool (Mode.ClientId);\r
990 }\r
991 if (Mode.Ia != NULL) {\r
992 FreePool (Mode.Ia);\r
993 }\r
b659408b
ZL
994 }\r
995\r
996 return Status; \r
997 \r
998}\r
999\r