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