]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/HttpBootDxe/HttpBootImpl.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootImpl.c
... / ...
CommitLineData
1/** @file\r
2 The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot.\r
3\r
4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "HttpBootDxe.h"\r
11\r
12/**\r
13 Install HTTP Boot Callback Protocol if not installed before.\r
14\r
15 @param[in] Private Pointer to HTTP Boot private data.\r
16\r
17 @retval EFI_SUCCESS HTTP Boot Callback Protocol installed successfully.\r
18 @retval Others Failed to install HTTP Boot Callback Protocol.\r
19\r
20**/\r
21EFI_STATUS\r
22HttpBootInstallCallback (\r
23 IN HTTP_BOOT_PRIVATE_DATA *Private\r
24 )\r
25{\r
26 EFI_STATUS Status;\r
27 EFI_HANDLE ControllerHandle;\r
28\r
29 if (!Private->UsingIpv6) {\r
30 ControllerHandle = Private->Ip4Nic->Controller;\r
31 } else {\r
32 ControllerHandle = Private->Ip6Nic->Controller;\r
33 }\r
34\r
35 //\r
36 // Check whether gEfiHttpBootCallbackProtocolGuid already installed.\r
37 //\r
38 Status = gBS->HandleProtocol (\r
39 ControllerHandle,\r
40 &gEfiHttpBootCallbackProtocolGuid,\r
41 (VOID **)&Private->HttpBootCallback\r
42 );\r
43 if (Status == EFI_UNSUPPORTED) {\r
44 CopyMem (\r
45 &Private->LoadFileCallback,\r
46 &gHttpBootDxeHttpBootCallback,\r
47 sizeof (EFI_HTTP_BOOT_CALLBACK_PROTOCOL)\r
48 );\r
49\r
50 //\r
51 // Install a default callback if user didn't offer one.\r
52 //\r
53 Status = gBS->InstallProtocolInterface (\r
54 &ControllerHandle,\r
55 &gEfiHttpBootCallbackProtocolGuid,\r
56 EFI_NATIVE_INTERFACE,\r
57 &Private->LoadFileCallback\r
58 );\r
59 if (EFI_ERROR (Status)) {\r
60 return Status;\r
61 }\r
62\r
63 Private->HttpBootCallback = &Private->LoadFileCallback;\r
64 }\r
65\r
66 return EFI_SUCCESS;\r
67}\r
68\r
69/**\r
70 Uninstall HTTP Boot Callback Protocol if it's installed by this driver.\r
71\r
72 @param[in] Private Pointer to HTTP Boot private data.\r
73\r
74**/\r
75VOID\r
76HttpBootUninstallCallback (\r
77 IN HTTP_BOOT_PRIVATE_DATA *Private\r
78 )\r
79{\r
80 if (Private->HttpBootCallback == &Private->LoadFileCallback) {\r
81 gBS->UninstallProtocolInterface (\r
82 Private->Controller,\r
83 &gEfiHttpBootCallbackProtocolGuid,\r
84 &Private->HttpBootCallback\r
85 );\r
86 Private->HttpBootCallback = NULL;\r
87 }\r
88}\r
89\r
90/**\r
91 Enable the use of UEFI HTTP boot function.\r
92\r
93 If the driver has already been started but not satisfy the requirement (IP stack and\r
94 specified boot file path), this function will stop the driver and start it again.\r
95\r
96 @param[in] Private The pointer to the driver's private data.\r
97 @param[in] UsingIpv6 Specifies the type of IP addresses that are to be\r
98 used during the session that is being started.\r
99 Set to TRUE for IPv6, and FALSE for IPv4.\r
100 @param[in] FilePath The device specific path of the file to load.\r
101\r
102 @retval EFI_SUCCESS HTTP boot was successfully enabled.\r
103 @retval EFI_INVALID_PARAMETER Private is NULL or FilePath is NULL.\r
104 @retval EFI_INVALID_PARAMETER The FilePath doesn't contain a valid URI device path node.\r
105 @retval EFI_ALREADY_STARTED The driver is already in started state.\r
106 @retval EFI_OUT_OF_RESOURCES There are not enough resources.\r
107\r
108**/\r
109EFI_STATUS\r
110HttpBootStart (\r
111 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
112 IN BOOLEAN UsingIpv6,\r
113 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
114 )\r
115{\r
116 UINTN Index;\r
117 EFI_STATUS Status;\r
118 CHAR8 *Uri;\r
119\r
120 Uri = NULL;\r
121\r
122 if ((Private == NULL) || (FilePath == NULL)) {\r
123 return EFI_INVALID_PARAMETER;\r
124 }\r
125\r
126 //\r
127 // Check the URI in the input FilePath, in order to see whether it is\r
128 // required to boot from a new specified boot file.\r
129 //\r
130 Status = HttpBootParseFilePath (FilePath, &Uri);\r
131 if (EFI_ERROR (Status)) {\r
132 return EFI_INVALID_PARAMETER;\r
133 }\r
134\r
135 //\r
136 // Check whether we need to stop and restart the HTTP boot driver.\r
137 //\r
138 if (Private->Started) {\r
139 //\r
140 // Restart is needed in 2 cases:\r
141 // 1. Http boot driver has already been started but not on the required IP stack.\r
142 // 2. The specified boot file URI in FilePath is different with the one we have\r
143 // recorded before.\r
144 //\r
145 if ((UsingIpv6 != Private->UsingIpv6) ||\r
146 ((Uri != NULL) && (AsciiStrCmp (Private->BootFileUri, Uri) != 0)))\r
147 {\r
148 //\r
149 // Restart is required, first stop then continue this start function.\r
150 //\r
151 Status = HttpBootStop (Private);\r
152 if (EFI_ERROR (Status)) {\r
153 if (Uri != NULL) {\r
154 FreePool (Uri);\r
155 }\r
156\r
157 return Status;\r
158 }\r
159 } else {\r
160 //\r
161 // Restart is not required.\r
162 //\r
163 if (Uri != NULL) {\r
164 FreePool (Uri);\r
165 }\r
166\r
167 return EFI_ALREADY_STARTED;\r
168 }\r
169 }\r
170\r
171 //\r
172 // Detect whether using ipv6 or not, and set it to the private data.\r
173 //\r
174 if (UsingIpv6 && (Private->Ip6Nic != NULL)) {\r
175 Private->UsingIpv6 = TRUE;\r
176 } else if (!UsingIpv6 && (Private->Ip4Nic != NULL)) {\r
177 Private->UsingIpv6 = FALSE;\r
178 } else {\r
179 if (Uri != NULL) {\r
180 FreePool (Uri);\r
181 }\r
182\r
183 return EFI_UNSUPPORTED;\r
184 }\r
185\r
186 //\r
187 // Record the specified URI and prepare the URI parser if needed.\r
188 //\r
189 Private->FilePathUri = Uri;\r
190 if (Private->FilePathUri != NULL) {\r
191 Status = HttpParseUrl (\r
192 Private->FilePathUri,\r
193 (UINT32)AsciiStrLen (Private->FilePathUri),\r
194 FALSE,\r
195 &Private->FilePathUriParser\r
196 );\r
197 if (EFI_ERROR (Status)) {\r
198 FreePool (Private->FilePathUri);\r
199 return Status;\r
200 }\r
201 }\r
202\r
203 //\r
204 // Init the content of cached DHCP offer list.\r
205 //\r
206 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
207 if (!Private->UsingIpv6) {\r
208 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
209 Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_CACHED_DHCP4_PACKET_MAX_SIZE;\r
210 }\r
211 } else {\r
212 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
213 Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = HTTP_CACHED_DHCP6_PACKET_MAX_SIZE;\r
214 }\r
215 }\r
216\r
217 if (Private->UsingIpv6) {\r
218 //\r
219 // Set Ip6 policy to Automatic to start the Ip6 router discovery.\r
220 //\r
221 Status = HttpBootSetIp6Policy (Private);\r
222 if (EFI_ERROR (Status)) {\r
223 return Status;\r
224 }\r
225 }\r
226\r
227 Private->Started = TRUE;\r
228 Print (L"\n>>Start HTTP Boot over IPv%d", Private->UsingIpv6 ? 6 : 4);\r
229\r
230 return EFI_SUCCESS;\r
231}\r
232\r
233/**\r
234 Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information.\r
235\r
236 @param[in] Private The pointer to the driver's private data.\r
237\r
238 @retval EFI_SUCCESS Boot info was successfully retrieved.\r
239 @retval EFI_INVALID_PARAMETER Private is NULL.\r
240 @retval EFI_NOT_STARTED The driver is in stopped state.\r
241 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
242 @retval Others Other errors as indicated.\r
243\r
244**/\r
245EFI_STATUS\r
246HttpBootDhcp (\r
247 IN HTTP_BOOT_PRIVATE_DATA *Private\r
248 )\r
249{\r
250 EFI_STATUS Status;\r
251\r
252 if (Private == NULL) {\r
253 return EFI_INVALID_PARAMETER;\r
254 }\r
255\r
256 if (!Private->Started) {\r
257 return EFI_NOT_STARTED;\r
258 }\r
259\r
260 Status = EFI_DEVICE_ERROR;\r
261\r
262 if (!Private->UsingIpv6) {\r
263 //\r
264 // Start D.O.R.A process to get a IPv4 address and other boot information.\r
265 //\r
266 Status = HttpBootDhcp4Dora (Private);\r
267 } else {\r
268 //\r
269 // Start S.A.R.R process to get a IPv6 address and other boot information.\r
270 //\r
271 Status = HttpBootDhcp6Sarr (Private);\r
272 }\r
273\r
274 return Status;\r
275}\r
276\r
277/**\r
278 Attempt to download the boot file through HTTP message exchange.\r
279\r
280 @param[in] Private The pointer to the driver's private data.\r
281 @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return\r
282 code of EFI_SUCCESS, the amount of data transferred to\r
283 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
284 the size of Buffer required to retrieve the requested file.\r
285 @param[in] Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
286 then the size of the requested file is returned in\r
287 BufferSize.\r
288 @param[out] ImageType The image type of the downloaded file.\r
289\r
290 @retval EFI_SUCCESS Boot file was loaded successfully.\r
291 @retval EFI_INVALID_PARAMETER Private is NULL, or ImageType is NULL, or BufferSize is NULL.\r
292 @retval EFI_INVALID_PARAMETER *BufferSize is not zero, and Buffer is NULL.\r
293 @retval EFI_NOT_STARTED The driver is in stopped state.\r
294 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the boot file. BufferSize has\r
295 been updated with the size needed to complete the request.\r
296 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
297 @retval Others Other errors as indicated.\r
298\r
299**/\r
300EFI_STATUS\r
301HttpBootLoadFile (\r
302 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
303 IN OUT UINTN *BufferSize,\r
304 IN VOID *Buffer OPTIONAL,\r
305 OUT HTTP_BOOT_IMAGE_TYPE *ImageType\r
306 )\r
307{\r
308 EFI_STATUS Status;\r
309\r
310 if ((Private == NULL) || (ImageType == NULL) || (BufferSize == NULL)) {\r
311 return EFI_INVALID_PARAMETER;\r
312 }\r
313\r
314 if ((*BufferSize != 0) && (Buffer == NULL)) {\r
315 return EFI_INVALID_PARAMETER;\r
316 }\r
317\r
318 if (!Private->Started) {\r
319 return EFI_NOT_STARTED;\r
320 }\r
321\r
322 Status = HttpBootInstallCallback (Private);\r
323 if (EFI_ERROR (Status)) {\r
324 goto ON_EXIT;\r
325 }\r
326\r
327 if (Private->BootFileUri == NULL) {\r
328 //\r
329 // Parse the cached offer to get the boot file URL first.\r
330 //\r
331 Status = HttpBootDiscoverBootInfo (Private);\r
332 if (EFI_ERROR (Status)) {\r
333 AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n");\r
334 goto ON_EXIT;\r
335 }\r
336 }\r
337\r
338 if (!Private->HttpCreated) {\r
339 //\r
340 // Create HTTP child.\r
341 //\r
342 Status = HttpBootCreateHttpIo (Private);\r
343 if (EFI_ERROR (Status)) {\r
344 goto ON_EXIT;\r
345 }\r
346 }\r
347\r
348 if (Private->BootFileSize == 0) {\r
349 //\r
350 // Discover the information about the bootfile if we haven't.\r
351 //\r
352\r
353 //\r
354 // Try to use HTTP HEAD method.\r
355 //\r
356 Status = HttpBootGetBootFile (\r
357 Private,\r
358 TRUE,\r
359 &Private->BootFileSize,\r
360 NULL,\r
361 &Private->ImageType\r
362 );\r
363 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
364 //\r
365 // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.\r
366 //\r
367 ASSERT (Private->BootFileSize == 0);\r
368 Status = HttpBootGetBootFile (\r
369 Private,\r
370 FALSE,\r
371 &Private->BootFileSize,\r
372 NULL,\r
373 &Private->ImageType\r
374 );\r
375 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
376 AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n");\r
377 goto ON_EXIT;\r
378 }\r
379 }\r
380 }\r
381\r
382 if (*BufferSize < Private->BootFileSize) {\r
383 *BufferSize = Private->BootFileSize;\r
384 *ImageType = Private->ImageType;\r
385 Status = EFI_BUFFER_TOO_SMALL;\r
386 goto ON_EXIT;\r
387 }\r
388\r
389 //\r
390 // Load the boot file into Buffer\r
391 //\r
392 Status = HttpBootGetBootFile (\r
393 Private,\r
394 FALSE,\r
395 BufferSize,\r
396 Buffer,\r
397 ImageType\r
398 );\r
399\r
400ON_EXIT:\r
401 HttpBootUninstallCallback (Private);\r
402\r
403 if (EFI_ERROR (Status)) {\r
404 if (Status == EFI_ACCESS_DENIED) {\r
405 AsciiPrint ("\n Error: Could not establish connection with HTTP server.\n");\r
406 } else if ((Status == EFI_BUFFER_TOO_SMALL) && (Buffer != NULL)) {\r
407 AsciiPrint ("\n Error: Buffer size is smaller than the requested file.\n");\r
408 } else if (Status == EFI_OUT_OF_RESOURCES) {\r
409 AsciiPrint ("\n Error: Could not allocate I/O buffers.\n");\r
410 } else if (Status == EFI_DEVICE_ERROR) {\r
411 AsciiPrint ("\n Error: Network device error.\n");\r
412 } else if (Status == EFI_TIMEOUT) {\r
413 AsciiPrint ("\n Error: Server response timeout.\n");\r
414 } else if (Status == EFI_ABORTED) {\r
415 AsciiPrint ("\n Error: Remote boot cancelled.\n");\r
416 } else if (Status != EFI_BUFFER_TOO_SMALL) {\r
417 AsciiPrint ("\n Error: Unexpected network error.\n");\r
418 }\r
419 }\r
420\r
421 return Status;\r
422}\r
423\r
424/**\r
425 Disable the use of UEFI HTTP boot function.\r
426\r
427 @param[in] Private The pointer to the driver's private data.\r
428\r
429 @retval EFI_SUCCESS HTTP boot was successfully disabled.\r
430 @retval EFI_NOT_STARTED The driver is already in stopped state.\r
431 @retval EFI_INVALID_PARAMETER Private is NULL.\r
432 @retval Others Unexpected error when stop the function.\r
433\r
434**/\r
435EFI_STATUS\r
436HttpBootStop (\r
437 IN HTTP_BOOT_PRIVATE_DATA *Private\r
438 )\r
439{\r
440 UINTN Index;\r
441\r
442 if (Private == NULL) {\r
443 return EFI_INVALID_PARAMETER;\r
444 }\r
445\r
446 if (!Private->Started) {\r
447 return EFI_NOT_STARTED;\r
448 }\r
449\r
450 if (Private->HttpCreated) {\r
451 HttpIoDestroyIo (&Private->HttpIo);\r
452 Private->HttpCreated = FALSE;\r
453 }\r
454\r
455 Private->Started = FALSE;\r
456 ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));\r
457 ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));\r
458 ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));\r
459 Private->Port = 0;\r
460 Private->BootFileUri = NULL;\r
461 Private->BootFileUriParser = NULL;\r
462 Private->BootFileSize = 0;\r
463 Private->SelectIndex = 0;\r
464 Private->SelectProxyType = HttpOfferTypeMax;\r
465\r
466 if (!Private->UsingIpv6) {\r
467 //\r
468 // Stop and release the DHCP4 child.\r
469 //\r
470 Private->Dhcp4->Stop (Private->Dhcp4);\r
471 Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
472\r
473 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
474 if (Private->OfferBuffer[Index].Dhcp4.UriParser) {\r
475 HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp4.UriParser);\r
476 }\r
477 }\r
478 } else {\r
479 //\r
480 // Stop and release the DHCP6 child.\r
481 //\r
482 Private->Dhcp6->Stop (Private->Dhcp6);\r
483 Private->Dhcp6->Configure (Private->Dhcp6, NULL);\r
484\r
485 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
486 if (Private->OfferBuffer[Index].Dhcp6.UriParser) {\r
487 HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp6.UriParser);\r
488 }\r
489 }\r
490 }\r
491\r
492 if (Private->DnsServerIp != NULL) {\r
493 FreePool (Private->DnsServerIp);\r
494 Private->DnsServerIp = NULL;\r
495 }\r
496\r
497 if (Private->FilePathUri != NULL) {\r
498 FreePool (Private->FilePathUri);\r
499 HttpUrlFreeParser (Private->FilePathUriParser);\r
500 Private->FilePathUri = NULL;\r
501 Private->FilePathUriParser = NULL;\r
502 }\r
503\r
504 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
505 Private->OfferNum = 0;\r
506 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
507 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
508\r
509 HttpBootFreeCacheList (Private);\r
510\r
511 return EFI_SUCCESS;\r
512}\r
513\r
514/**\r
515 Causes the driver to load a specified file.\r
516\r
517 @param This Protocol instance pointer.\r
518 @param FilePath The device specific path of the file to load.\r
519 @param BootPolicy If TRUE, indicates that the request originates from the\r
520 boot manager is attempting to load FilePath as a boot\r
521 selection. If FALSE, then FilePath must match as exact file\r
522 to be loaded.\r
523 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
524 code of EFI_SUCCESS, the amount of data transferred to\r
525 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
526 the size of Buffer required to retrieve the requested file.\r
527 @param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,\r
528 then the size of the requested file is returned in\r
529 BufferSize.\r
530\r
531 @retval EFI_SUCCESS The file was loaded.\r
532 @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy\r
533 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
534 BufferSize is NULL.\r
535 @retval EFI_NO_MEDIA No medium was present to load the file.\r
536 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.\r
537 @retval EFI_NO_RESPONSE The remote system did not respond.\r
538 @retval EFI_NOT_FOUND The file was not found.\r
539 @retval EFI_ABORTED The file load process was manually cancelled.\r
540 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
541 BufferSize has been updated with the size needed to complete\r
542 the request.\r
543\r
544**/\r
545EFI_STATUS\r
546EFIAPI\r
547HttpBootDxeLoadFile (\r
548 IN EFI_LOAD_FILE_PROTOCOL *This,\r
549 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
550 IN BOOLEAN BootPolicy,\r
551 IN OUT UINTN *BufferSize,\r
552 IN VOID *Buffer OPTIONAL\r
553 )\r
554{\r
555 HTTP_BOOT_PRIVATE_DATA *Private;\r
556 HTTP_BOOT_VIRTUAL_NIC *VirtualNic;\r
557 EFI_STATUS MediaStatus;\r
558 BOOLEAN UsingIpv6;\r
559 EFI_STATUS Status;\r
560 HTTP_BOOT_IMAGE_TYPE ImageType;\r
561\r
562 if ((This == NULL) || (BufferSize == NULL) || (FilePath == NULL)) {\r
563 return EFI_INVALID_PARAMETER;\r
564 }\r
565\r
566 //\r
567 // Only support BootPolicy\r
568 //\r
569 if (!BootPolicy) {\r
570 return EFI_UNSUPPORTED;\r
571 }\r
572\r
573 VirtualNic = HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE (This);\r
574 Private = VirtualNic->Private;\r
575\r
576 //\r
577 // Check media status before HTTP boot start\r
578 //\r
579 MediaStatus = EFI_SUCCESS;\r
580 NetLibDetectMediaWaitTimeout (Private->Controller, HTTP_BOOT_CHECK_MEDIA_WAITING_TIME, &MediaStatus);\r
581 if (MediaStatus != EFI_SUCCESS) {\r
582 AsciiPrint ("\n Error: Could not detect network connection.\n");\r
583 return EFI_NO_MEDIA;\r
584 }\r
585\r
586 //\r
587 // Check whether the virtual nic is using IPv6 or not.\r
588 //\r
589 UsingIpv6 = FALSE;\r
590 if (VirtualNic == Private->Ip6Nic) {\r
591 UsingIpv6 = TRUE;\r
592 }\r
593\r
594 //\r
595 // Initialize HTTP boot.\r
596 //\r
597 Status = HttpBootStart (Private, UsingIpv6, FilePath);\r
598 if ((Status != EFI_SUCCESS) && (Status != EFI_ALREADY_STARTED)) {\r
599 return Status;\r
600 }\r
601\r
602 //\r
603 // Load the boot file.\r
604 //\r
605 ImageType = ImageTypeMax;\r
606 Status = HttpBootLoadFile (Private, BufferSize, Buffer, &ImageType);\r
607 if (EFI_ERROR (Status)) {\r
608 if ((Status == EFI_BUFFER_TOO_SMALL) && ((ImageType == ImageTypeVirtualCd) || (ImageType == ImageTypeVirtualDisk))) {\r
609 Status = EFI_WARN_FILE_SYSTEM;\r
610 } else if (Status != EFI_BUFFER_TOO_SMALL) {\r
611 HttpBootStop (Private);\r
612 }\r
613\r
614 return Status;\r
615 }\r
616\r
617 //\r
618 // Register the RAM Disk to the system if needed.\r
619 //\r
620 if ((ImageType == ImageTypeVirtualCd) || (ImageType == ImageTypeVirtualDisk)) {\r
621 Status = HttpBootRegisterRamDisk (Private, *BufferSize, Buffer, ImageType);\r
622 if (!EFI_ERROR (Status)) {\r
623 Status = EFI_WARN_FILE_SYSTEM;\r
624 } else {\r
625 AsciiPrint ("\n Error: Could not register RAM disk to the system.\n");\r
626 }\r
627 }\r
628\r
629 //\r
630 // Stop the HTTP Boot service after the boot image is downloaded.\r
631 //\r
632 HttpBootStop (Private);\r
633 return Status;\r
634}\r
635\r
636///\r
637/// Load File Protocol instance\r
638///\r
639GLOBAL_REMOVE_IF_UNREFERENCED\r
640EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = {\r
641 HttpBootDxeLoadFile\r
642};\r
643\r
644/**\r
645 Callback function that is invoked when the HTTP Boot driver is about to transmit or has received a\r
646 packet.\r
647\r
648 This function is invoked when the HTTP Boot driver is about to transmit or has received packet.\r
649 Parameters DataType and Received specify the type of event and the format of the buffer pointed\r
650 to by Data. Due to the polling nature of UEFI device drivers, this callback function should not\r
651 execute for more than 5 ms.\r
652 The returned status code determines the behavior of the HTTP Boot driver.\r
653\r
654 @param[in] This Pointer to the EFI_HTTP_BOOT_CALLBACK_PROTOCOL instance.\r
655 @param[in] DataType The event that occurs in the current state.\r
656 @param[in] Received TRUE if the callback is being invoked due to a receive event.\r
657 FALSE if the callback is being invoked due to a transmit event.\r
658 @param[in] DataLength The length in bytes of the buffer pointed to by Data.\r
659 @param[in] Data A pointer to the buffer of data, the data type is specified by\r
660 DataType.\r
661\r
662 @retval EFI_SUCCESS Tells the HTTP Boot driver to continue the HTTP Boot process.\r
663 @retval EFI_ABORTED Tells the HTTP Boot driver to abort the current HTTP Boot process.\r
664**/\r
665EFI_STATUS\r
666EFIAPI\r
667HttpBootCallback (\r
668 IN EFI_HTTP_BOOT_CALLBACK_PROTOCOL *This,\r
669 IN EFI_HTTP_BOOT_CALLBACK_DATA_TYPE DataType,\r
670 IN BOOLEAN Received,\r
671 IN UINT32 DataLength,\r
672 IN VOID *Data OPTIONAL\r
673 )\r
674{\r
675 EFI_HTTP_MESSAGE *HttpMessage;\r
676 EFI_HTTP_HEADER *HttpHeader;\r
677 HTTP_BOOT_PRIVATE_DATA *Private;\r
678 UINT32 Percentage;\r
679\r
680 Private = HTTP_BOOT_PRIVATE_DATA_FROM_CALLBACK_PROTOCOL (This);\r
681\r
682 switch (DataType) {\r
683 case HttpBootDhcp4:\r
684 case HttpBootDhcp6:\r
685 Print (L".");\r
686 break;\r
687\r
688 case HttpBootHttpRequest:\r
689 if (Data != NULL) {\r
690 HttpMessage = (EFI_HTTP_MESSAGE *)Data;\r
691 if ((HttpMessage->Data.Request->Method == HttpMethodGet) &&\r
692 (HttpMessage->Data.Request->Url != NULL))\r
693 {\r
694 Print (L"\n URI: %s\n", HttpMessage->Data.Request->Url);\r
695 }\r
696 }\r
697\r
698 break;\r
699\r
700 case HttpBootHttpResponse:\r
701 if (Data != NULL) {\r
702 HttpMessage = (EFI_HTTP_MESSAGE *)Data;\r
703\r
704 if (HttpMessage->Data.Response != NULL) {\r
705 if (HttpBootIsHttpRedirectStatusCode (HttpMessage->Data.Response->StatusCode)) {\r
706 //\r
707 // Server indicates the resource has been redirected to a different URL\r
708 // according to the section 6.4 of RFC7231 and the RFC 7538.\r
709 // Display the redirect information on the screen.\r
710 //\r
711 HttpHeader = HttpFindHeader (\r
712 HttpMessage->HeaderCount,\r
713 HttpMessage->Headers,\r
714 HTTP_HEADER_LOCATION\r
715 );\r
716 if (HttpHeader != NULL) {\r
717 Print (L"\n HTTP ERROR: Resource Redirected.\n New Location: %a\n", HttpHeader->FieldValue);\r
718 }\r
719\r
720 break;\r
721 }\r
722 }\r
723\r
724 HttpHeader = HttpFindHeader (\r
725 HttpMessage->HeaderCount,\r
726 HttpMessage->Headers,\r
727 HTTP_HEADER_CONTENT_LENGTH\r
728 );\r
729 if (HttpHeader != NULL) {\r
730 Private->FileSize = AsciiStrDecimalToUintn (HttpHeader->FieldValue);\r
731 Private->ReceivedSize = 0;\r
732 Private->Percentage = 0;\r
733 }\r
734 }\r
735\r
736 break;\r
737\r
738 case HttpBootHttpEntityBody:\r
739 if (DataLength != 0) {\r
740 if (Private->FileSize != 0) {\r
741 //\r
742 // We already know the file size, print in percentage format.\r
743 //\r
744 if (Private->ReceivedSize == 0) {\r
745 Print (L" File Size: %lu Bytes\n", Private->FileSize);\r
746 }\r
747\r
748 Private->ReceivedSize += DataLength;\r
749 Percentage = (UINT32)DivU64x64Remainder (MultU64x32 (Private->ReceivedSize, 100), Private->FileSize, NULL);\r
750 if (Private->Percentage != Percentage) {\r
751 Private->Percentage = Percentage;\r
752 Print (L"\r Downloading...%d%%", Percentage);\r
753 }\r
754 } else {\r
755 //\r
756 // In some case we couldn't get the file size from the HTTP header, so we\r
757 // just print the downloaded file size.\r
758 //\r
759 Private->ReceivedSize += DataLength;\r
760 Print (L"\r Downloading...%lu Bytes", Private->ReceivedSize);\r
761 }\r
762 }\r
763\r
764 break;\r
765\r
766 default:\r
767 break;\r
768 }\r
769\r
770 return EFI_SUCCESS;\r
771}\r
772\r
773///\r
774/// HTTP Boot Callback Protocol instance\r
775///\r
776GLOBAL_REMOVE_IF_UNREFERENCED\r
777EFI_HTTP_BOOT_CALLBACK_PROTOCOL gHttpBootDxeHttpBootCallback = {\r
778 HttpBootCallback\r
779};\r