]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootImpl.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootImpl.c
CommitLineData
d933e70a
JW
1/** @file\r
2 The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot.\r
3\r
f33d3994 4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
44a7d08b 5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
ecf98fbc 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
d933e70a
JW
7\r
8**/\r
9\r
10#include "HttpBootDxe.h"\r
11\r
95b5c32f
FS
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
c36b7b51 17 @retval EFI_SUCCESS HTTP Boot Callback Protocol installed successfully.\r
95b5c32f
FS
18 @retval Others Failed to install HTTP Boot Callback Protocol.\r
19\r
20**/\r
21EFI_STATUS\r
22HttpBootInstallCallback (\r
d1050b9d 23 IN HTTP_BOOT_PRIVATE_DATA *Private\r
95b5c32f
FS
24 )\r
25{\r
d1050b9d
MK
26 EFI_STATUS Status;\r
27 EFI_HANDLE ControllerHandle;\r
95b5c32f
FS
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
d1050b9d 41 (VOID **)&Private->HttpBootCallback\r
95b5c32f
FS
42 );\r
43 if (Status == EFI_UNSUPPORTED) {\r
95b5c32f
FS
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
d1050b9d 62\r
95b5c32f
FS
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
d1050b9d 77 IN HTTP_BOOT_PRIVATE_DATA *Private\r
95b5c32f
FS
78 )\r
79{\r
80 if (Private->HttpBootCallback == &Private->LoadFileCallback) {\r
81 gBS->UninstallProtocolInterface (\r
d1050b9d
MK
82 Private->Controller,\r
83 &gEfiHttpBootCallbackProtocolGuid,\r
84 &Private->HttpBootCallback\r
85 );\r
95b5c32f
FS
86 Private->HttpBootCallback = NULL;\r
87 }\r
88}\r
89\r
d933e70a
JW
90/**\r
91 Enable the use of UEFI HTTP boot function.\r
92\r
f75a7f56 93 If the driver has already been started but not satisfy the requirement (IP stack and\r
587d204c
FS
94 specified boot file path), this function will stop the driver and start it again.\r
95\r
d933e70a 96 @param[in] Private The pointer to the driver's private data.\r
b659408b
ZL
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
fa848a40 100 @param[in] FilePath The device specific path of the file to load.\r
d933e70a
JW
101\r
102 @retval EFI_SUCCESS HTTP boot was successfully enabled.\r
587d204c
FS
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
d933e70a 105 @retval EFI_ALREADY_STARTED The driver is already in started state.\r
fa848a40 106 @retval EFI_OUT_OF_RESOURCES There are not enough resources.\r
f75a7f56 107\r
d933e70a
JW
108**/\r
109EFI_STATUS\r
110HttpBootStart (\r
d1050b9d
MK
111 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
112 IN BOOLEAN UsingIpv6,\r
113 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
d933e70a
JW
114 )\r
115{\r
d1050b9d
MK
116 UINTN Index;\r
117 EFI_STATUS Status;\r
118 CHAR8 *Uri;\r
d933e70a 119\r
0dc59296 120 Uri = NULL;\r
f75a7f56 121\r
d1050b9d 122 if ((Private == NULL) || (FilePath == NULL)) {\r
d933e70a
JW
123 return EFI_INVALID_PARAMETER;\r
124 }\r
f75a7f56 125\r
587d204c
FS
126 //\r
127 // Check the URI in the input FilePath, in order to see whether it is\r
f75a7f56 128 // required to boot from a new specified boot file.\r
587d204c
FS
129 //\r
130 Status = HttpBootParseFilePath (FilePath, &Uri);\r
131 if (EFI_ERROR (Status)) {\r
132 return EFI_INVALID_PARAMETER;\r
133 }\r
f75a7f56 134\r
587d204c
FS
135 //\r
136 // Check whether we need to stop and restart the HTTP boot driver.\r
137 //\r
d933e70a 138 if (Private->Started) {\r
587d204c
FS
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
f75a7f56 145 if ((UsingIpv6 != Private->UsingIpv6) ||\r
d1050b9d
MK
146 ((Uri != NULL) && (AsciiStrCmp (Private->BootFileUri, Uri) != 0)))\r
147 {\r
587d204c
FS
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
0dc59296
JW
153 if (Uri != NULL) {\r
154 FreePool (Uri);\r
155 }\r
d1050b9d 156\r
587d204c
FS
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
d1050b9d 166\r
587d204c
FS
167 return EFI_ALREADY_STARTED;\r
168 }\r
d933e70a
JW
169 }\r
170\r
b659408b
ZL
171 //\r
172 // Detect whether using ipv6 or not, and set it to the private data.\r
173 //\r
d1050b9d 174 if (UsingIpv6 && (Private->Ip6Nic != NULL)) {\r
b659408b 175 Private->UsingIpv6 = TRUE;\r
d1050b9d 176 } else if (!UsingIpv6 && (Private->Ip4Nic != NULL)) {\r
b659408b
ZL
177 Private->UsingIpv6 = FALSE;\r
178 } else {\r
587d204c
FS
179 if (Uri != NULL) {\r
180 FreePool (Uri);\r
181 }\r
d1050b9d 182\r
b659408b
ZL
183 return EFI_UNSUPPORTED;\r
184 }\r
fa848a40
FS
185\r
186 //\r
587d204c 187 // Record the specified URI and prepare the URI parser if needed.\r
fa848a40 188 //\r
587d204c 189 Private->FilePathUri = Uri;\r
fa848a40
FS
190 if (Private->FilePathUri != NULL) {\r
191 Status = HttpParseUrl (\r
192 Private->FilePathUri,\r
d1050b9d 193 (UINT32)AsciiStrLen (Private->FilePathUri),\r
fa848a40
FS
194 FALSE,\r
195 &Private->FilePathUriParser\r
196 );\r
197 if (EFI_ERROR (Status)) {\r
587d204c 198 FreePool (Private->FilePathUri);\r
fa848a40
FS
199 return Status;\r
200 }\r
201 }\r
f75a7f56 202\r
b659408b
ZL
203 //\r
204 // Init the content of cached DHCP offer list.\r
205 //\r
206 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
d933e70a 207 if (!Private->UsingIpv6) {\r
d933e70a 208 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
632dcfd6 209 Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_CACHED_DHCP4_PACKET_MAX_SIZE;\r
d933e70a
JW
210 }\r
211 } else {\r
b659408b 212 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
632dcfd6 213 Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = HTTP_CACHED_DHCP6_PACKET_MAX_SIZE;\r
b659408b 214 }\r
d933e70a
JW
215 }\r
216\r
b659408b
ZL
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
d1050b9d
MK
226\r
227 Private->Started = TRUE;\r
95b5c32f 228 Print (L"\n>>Start HTTP Boot over IPv%d", Private->UsingIpv6 ? 6 : 4);\r
d933e70a
JW
229\r
230 return EFI_SUCCESS;\r
231}\r
232\r
233/**\r
b659408b 234 Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information.\r
d933e70a
JW
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
f75a7f56 243\r
d933e70a
JW
244**/\r
245EFI_STATUS\r
246HttpBootDhcp (\r
d1050b9d 247 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
248 )\r
249{\r
d1050b9d 250 EFI_STATUS Status;\r
d933e70a
JW
251\r
252 if (Private == NULL) {\r
253 return EFI_INVALID_PARAMETER;\r
254 }\r
f75a7f56 255\r
d933e70a
JW
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
b659408b
ZL
263 //\r
264 // Start D.O.R.A process to get a IPv4 address and other boot information.\r
265 //\r
d933e70a
JW
266 Status = HttpBootDhcp4Dora (Private);\r
267 } else {\r
d1050b9d 268 //\r
b659408b
ZL
269 // Start S.A.R.R process to get a IPv6 address and other boot information.\r
270 //\r
271 Status = HttpBootDhcp6Sarr (Private);\r
d933e70a
JW
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
587d204c 288 @param[out] ImageType The image type of the downloaded file.\r
d933e70a
JW
289\r
290 @retval EFI_SUCCESS Boot file was loaded successfully.\r
587d204c
FS
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
d933e70a 293 @retval EFI_NOT_STARTED The driver is in stopped state.\r
f75a7f56 294 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the boot file. BufferSize has\r
d933e70a
JW
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
f75a7f56 298\r
d933e70a
JW
299**/\r
300EFI_STATUS\r
301HttpBootLoadFile (\r
d1050b9d
MK
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
d933e70a
JW
306 )\r
307{\r
d1050b9d 308 EFI_STATUS Status;\r
d933e70a 309\r
d1050b9d 310 if ((Private == NULL) || (ImageType == NULL) || (BufferSize == NULL)) {\r
587d204c
FS
311 return EFI_INVALID_PARAMETER;\r
312 }\r
313\r
d1050b9d 314 if ((*BufferSize != 0) && (Buffer == NULL)) {\r
d933e70a
JW
315 return EFI_INVALID_PARAMETER;\r
316 }\r
f75a7f56 317\r
d933e70a
JW
318 if (!Private->Started) {\r
319 return EFI_NOT_STARTED;\r
320 }\r
321\r
95b5c32f 322 Status = HttpBootInstallCallback (Private);\r
d1050b9d 323 if (EFI_ERROR (Status)) {\r
95b5c32f
FS
324 goto ON_EXIT;\r
325 }\r
d933e70a
JW
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
f33d3994 333 AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n");\r
95b5c32f 334 goto ON_EXIT;\r
d933e70a
JW
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
95b5c32f 344 goto ON_EXIT;\r
d933e70a
JW
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
587d204c 360 NULL,\r
44a7d08b 361 &Private->ImageType\r
d933e70a 362 );\r
d1050b9d 363 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
d933e70a
JW
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
587d204c 372 NULL,\r
44a7d08b 373 &Private->ImageType\r
d933e70a 374 );\r
d1050b9d 375 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
fca04738 376 AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n");\r
95b5c32f 377 goto ON_EXIT;\r
d933e70a
JW
378 }\r
379 }\r
380 }\r
381\r
382 if (*BufferSize < Private->BootFileSize) {\r
383 *BufferSize = Private->BootFileSize;\r
d1050b9d
MK
384 *ImageType = Private->ImageType;\r
385 Status = EFI_BUFFER_TOO_SMALL;\r
95b5c32f 386 goto ON_EXIT;\r
d933e70a
JW
387 }\r
388\r
389 //\r
390 // Load the boot file into Buffer\r
391 //\r
95b5c32f
FS
392 Status = HttpBootGetBootFile (\r
393 Private,\r
394 FALSE,\r
395 BufferSize,\r
396 Buffer,\r
397 ImageType\r
398 );\r
f75a7f56 399\r
95b5c32f
FS
400ON_EXIT:\r
401 HttpBootUninstallCallback (Private);\r
f75a7f56 402\r
f33d3994
JW
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
d1050b9d 406 } else if ((Status == EFI_BUFFER_TOO_SMALL) && (Buffer != NULL)) {\r
f33d3994
JW
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
fca04738 419 }\r
f75a7f56 420\r
95b5c32f 421 return Status;\r
d933e70a
JW
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
f75a7f56 433\r
d933e70a
JW
434**/\r
435EFI_STATUS\r
436HttpBootStop (\r
d1050b9d 437 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
438 )\r
439{\r
d1050b9d 440 UINTN Index;\r
d933e70a
JW
441\r
442 if (Private == NULL) {\r
443 return EFI_INVALID_PARAMETER;\r
444 }\r
f75a7f56 445\r
d933e70a
JW
446 if (!Private->Started) {\r
447 return EFI_NOT_STARTED;\r
448 }\r
f75a7f56 449\r
d933e70a
JW
450 if (Private->HttpCreated) {\r
451 HttpIoDestroyIo (&Private->HttpIo);\r
452 Private->HttpCreated = FALSE;\r
453 }\r
f75a7f56 454\r
d933e70a
JW
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
d1050b9d
MK
459 Private->Port = 0;\r
460 Private->BootFileUri = NULL;\r
d933e70a 461 Private->BootFileUriParser = NULL;\r
d1050b9d
MK
462 Private->BootFileSize = 0;\r
463 Private->SelectIndex = 0;\r
464 Private->SelectProxyType = HttpOfferTypeMax;\r
d933e70a
JW
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
b659408b
ZL
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
f75a7f56 484\r
b659408b
ZL
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
d933e70a 490 }\r
fa848a40 491\r
7b1dbd15
JW
492 if (Private->DnsServerIp != NULL) {\r
493 FreePool (Private->DnsServerIp);\r
494 Private->DnsServerIp = NULL;\r
495 }\r
496\r
d1050b9d 497 if (Private->FilePathUri != NULL) {\r
fa848a40
FS
498 FreePool (Private->FilePathUri);\r
499 HttpUrlFreeParser (Private->FilePathUriParser);\r
d1050b9d 500 Private->FilePathUri = NULL;\r
fa848a40
FS
501 Private->FilePathUriParser = NULL;\r
502 }\r
f75a7f56 503\r
d933e70a
JW
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
f75a7f56 508\r
fa848a40 509 HttpBootFreeCacheList (Private);\r
f75a7f56 510\r
d933e70a
JW
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
d1050b9d
MK
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
d933e70a
JW
553 )\r
554{\r
d1050b9d
MK
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
d933e70a
JW
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
b659408b 573 VirtualNic = HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE (This);\r
d1050b9d 574 Private = VirtualNic->Private;\r
f75a7f56 575\r
d933e70a
JW
576 //\r
577 // Check media status before HTTP boot start\r
578 //\r
152f2d5e 579 MediaStatus = EFI_SUCCESS;\r
580 NetLibDetectMediaWaitTimeout (Private->Controller, HTTP_BOOT_CHECK_MEDIA_WAITING_TIME, &MediaStatus);\r
581 if (MediaStatus != EFI_SUCCESS) {\r
fca04738 582 AsciiPrint ("\n Error: Could not detect network connection.\n");\r
d933e70a
JW
583 return EFI_NO_MEDIA;\r
584 }\r
f75a7f56 585\r
b659408b
ZL
586 //\r
587 // Check whether the virtual nic is using IPv6 or not.\r
588 //\r
fa848a40 589 UsingIpv6 = FALSE;\r
b659408b
ZL
590 if (VirtualNic == Private->Ip6Nic) {\r
591 UsingIpv6 = TRUE;\r
592 }\r
fa848a40 593\r
d933e70a 594 //\r
fa848a40 595 // Initialize HTTP boot.\r
d933e70a 596 //\r
fa848a40 597 Status = HttpBootStart (Private, UsingIpv6, FilePath);\r
d1050b9d 598 if ((Status != EFI_SUCCESS) && (Status != EFI_ALREADY_STARTED)) {\r
587d204c 599 return Status;\r
b659408b 600 }\r
f75a7f56 601\r
fa848a40
FS
602 //\r
603 // Load the boot file.\r
604 //\r
587d204c 605 ImageType = ImageTypeMax;\r
d1050b9d 606 Status = HttpBootLoadFile (Private, BufferSize, Buffer, &ImageType);\r
587d204c 607 if (EFI_ERROR (Status)) {\r
d1050b9d 608 if ((Status == EFI_BUFFER_TOO_SMALL) && ((ImageType == ImageTypeVirtualCd) || (ImageType == ImageTypeVirtualDisk))) {\r
587d204c
FS
609 Status = EFI_WARN_FILE_SYSTEM;\r
610 } else if (Status != EFI_BUFFER_TOO_SMALL) {\r
611 HttpBootStop (Private);\r
612 }\r
d1050b9d 613\r
587d204c 614 return Status;\r
d933e70a
JW
615 }\r
616\r
587d204c
FS
617 //\r
618 // Register the RAM Disk to the system if needed.\r
619 //\r
d1050b9d 620 if ((ImageType == ImageTypeVirtualCd) || (ImageType == ImageTypeVirtualDisk)) {\r
587d204c
FS
621 Status = HttpBootRegisterRamDisk (Private, *BufferSize, Buffer, ImageType);\r
622 if (!EFI_ERROR (Status)) {\r
623 Status = EFI_WARN_FILE_SYSTEM;\r
fca04738
FS
624 } else {\r
625 AsciiPrint ("\n Error: Could not register RAM disk to the system.\n");\r
b659408b 626 }\r
d933e70a 627 }\r
287f05cd
FS
628\r
629 //\r
630 // Stop the HTTP Boot service after the boot image is downloaded.\r
631 //\r
632 HttpBootStop (Private);\r
d933e70a
JW
633 return Status;\r
634}\r
635\r
636///\r
637/// Load File Protocol instance\r
638///\r
f75a7f56 639GLOBAL_REMOVE_IF_UNREFERENCED\r
d933e70a
JW
640EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = {\r
641 HttpBootDxeLoadFile\r
642};\r
95b5c32f
FS
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
f75a7f56 661\r
95b5c32f
FS
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
3858c58a 666EFIAPI\r
95b5c32f 667HttpBootCallback (\r
d1050b9d
MK
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
95b5c32f
FS
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
d1050b9d 680 Private = HTTP_BOOT_PRIVATE_DATA_FROM_CALLBACK_PROTOCOL (This);\r
95b5c32f
FS
681\r
682 switch (DataType) {\r
d1050b9d
MK
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
95b5c32f 734 }\r
95b5c32f 735\r
d1050b9d 736 break;\r
f75a7f56 737\r
d1050b9d
MK
738 case HttpBootHttpEntityBody:\r
739 if (DataLength != 0) {\r
740 if (Private->FileSize != 0) {\r
bb4831c0 741 //\r
d1050b9d 742 // We already know the file size, print in percentage format.\r
bb4831c0 743 //\r
d1050b9d
MK
744 if (Private->ReceivedSize == 0) {\r
745 Print (L" File Size: %lu Bytes\n", Private->FileSize);\r
bb4831c0 746 }\r
f75a7f56 747\r
d1050b9d
MK
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
95b5c32f 761 }\r
95b5c32f 762 }\r
95b5c32f 763\r
d1050b9d
MK
764 break;\r
765\r
766 default:\r
767 break;\r
768 }\r
95b5c32f
FS
769\r
770 return EFI_SUCCESS;\r
771}\r
772\r
773///\r
774/// HTTP Boot Callback Protocol instance\r
775///\r
f75a7f56 776GLOBAL_REMOVE_IF_UNREFERENCED\r
95b5c32f
FS
777EFI_HTTP_BOOT_CALLBACK_PROTOCOL gHttpBootDxeHttpBootCallback = {\r
778 HttpBootCallback\r
779};\r