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