]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootSupport.c
CommitLineData
d933e70a
JW
1/** @file\r
2 Support functions implementation for UEFI HTTP boot driver.\r
3\r
f75a7f56 4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
97e2b622 5(C) Copyright 2016 - 2020 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
d933e70a
JW
12/**\r
13 Get the Nic handle using any child handle in the IPv4 stack.\r
14\r
15 @param[in] ControllerHandle Pointer to child handle over IPv4.\r
16\r
17 @return NicHandle The pointer to the Nic handle.\r
18 @return NULL Can't find the Nic handle.\r
19\r
20**/\r
21EFI_HANDLE\r
22HttpBootGetNicByIp4Children (\r
d1050b9d 23 IN EFI_HANDLE ControllerHandle\r
d933e70a
JW
24 )\r
25{\r
d1050b9d 26 EFI_HANDLE NicHandle;\r
d933e70a
JW
27\r
28 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
29 if (NicHandle == NULL) {\r
30 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
31 if (NicHandle == NULL) {\r
32 return NULL;\r
33 }\r
34 }\r
35\r
36 return NicHandle;\r
37}\r
38\r
b659408b
ZL
39/**\r
40 Get the Nic handle using any child handle in the IPv6 stack.\r
41\r
42 @param[in] ControllerHandle Pointer to child handle over IPv6.\r
43\r
44 @return NicHandle The pointer to the Nic handle.\r
45 @return NULL Can't find the Nic handle.\r
46\r
47**/\r
48EFI_HANDLE\r
49HttpBootGetNicByIp6Children (\r
d1050b9d 50 IN EFI_HANDLE ControllerHandle\r
b659408b
ZL
51 )\r
52{\r
d1050b9d
MK
53 EFI_HANDLE NicHandle;\r
54\r
b659408b
ZL
55 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
56 if (NicHandle == NULL) {\r
57 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
58 if (NicHandle == NULL) {\r
59 return NULL;\r
60 }\r
61 }\r
62\r
63 return NicHandle;\r
64}\r
d933e70a
JW
65\r
66/**\r
67 This function is to convert UINTN to ASCII string with the required formatting.\r
68\r
69 @param[in] Number Numeric value to be converted.\r
70 @param[in] Buffer The pointer to the buffer for ASCII string.\r
71 @param[in] Length The length of the required format.\r
72\r
73**/\r
74VOID\r
75HttpBootUintnToAscDecWithFormat (\r
d1050b9d
MK
76 IN UINTN Number,\r
77 IN UINT8 *Buffer,\r
78 IN INTN Length\r
d933e70a
JW
79 )\r
80{\r
d1050b9d 81 UINTN Remainder;\r
d933e70a 82\r
d1050b9d
MK
83 for ( ; Length > 0; Length--) {\r
84 Remainder = Number % 10;\r
85 Number /= 10;\r
86 Buffer[Length - 1] = (UINT8)('0' + Remainder);\r
d933e70a
JW
87 }\r
88}\r
89\r
90/**\r
91 This function is to display the IPv4 address.\r
92\r
93 @param[in] Ip The pointer to the IPv4 address.\r
94\r
95**/\r
96VOID\r
97HttpBootShowIp4Addr (\r
d1050b9d 98 IN EFI_IPv4_ADDRESS *Ip\r
d933e70a
JW
99 )\r
100{\r
d1050b9d 101 UINTN Index;\r
d933e70a
JW
102\r
103 for (Index = 0; Index < 4; Index++) {\r
104 AsciiPrint ("%d", Ip->Addr[Index]);\r
105 if (Index < 3) {\r
106 AsciiPrint (".");\r
107 }\r
108 }\r
109}\r
110\r
b659408b
ZL
111/**\r
112 This function is to display the IPv6 address.\r
113\r
114 @param[in] Ip The pointer to the IPv6 address.\r
115\r
116**/\r
117VOID\r
118HttpBootShowIp6Addr (\r
d1050b9d 119 IN EFI_IPv6_ADDRESS *Ip\r
b659408b
ZL
120 )\r
121{\r
d1050b9d 122 UINTN Index;\r
b659408b
ZL
123\r
124 for (Index = 0; Index < 16; Index++) {\r
b659408b
ZL
125 if (Ip->Addr[Index] != 0) {\r
126 AsciiPrint ("%x", Ip->Addr[Index]);\r
127 }\r
d1050b9d 128\r
b659408b
ZL
129 Index++;\r
130 if (Index > 15) {\r
131 return;\r
132 }\r
d1050b9d 133\r
b659408b
ZL
134 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
135 AsciiPrint ("0");\r
136 }\r
d1050b9d 137\r
b659408b
ZL
138 AsciiPrint ("%x", Ip->Addr[Index]);\r
139 if (Index < 15) {\r
140 AsciiPrint (":");\r
141 }\r
142 }\r
143}\r
144\r
62cae351
ZL
145/**\r
146 This function is to display the HTTP error status.\r
147\r
148 @param[in] StatusCode The status code value in HTTP message.\r
149\r
150**/\r
151VOID\r
152HttpBootPrintErrorMessage (\r
d1050b9d 153 EFI_HTTP_STATUS_CODE StatusCode\r
62cae351
ZL
154 )\r
155{\r
156 AsciiPrint ("\n");\r
157\r
158 switch (StatusCode) {\r
d1050b9d
MK
159 case HTTP_STATUS_300_MULTIPLE_CHOICES:\r
160 AsciiPrint ("\n Redirection: 300 Multiple Choices");\r
161 break;\r
f75a7f56 162\r
d1050b9d
MK
163 case HTTP_STATUS_301_MOVED_PERMANENTLY:\r
164 AsciiPrint ("\n Redirection: 301 Moved Permanently");\r
165 break;\r
f75a7f56 166\r
d1050b9d
MK
167 case HTTP_STATUS_302_FOUND:\r
168 AsciiPrint ("\n Redirection: 302 Found");\r
169 break;\r
62cae351 170\r
d1050b9d
MK
171 case HTTP_STATUS_303_SEE_OTHER:\r
172 AsciiPrint ("\n Redirection: 303 See Other");\r
173 break;\r
62cae351 174\r
d1050b9d
MK
175 case HTTP_STATUS_304_NOT_MODIFIED:\r
176 AsciiPrint ("\n Redirection: 304 Not Modified");\r
177 break;\r
62cae351 178\r
d1050b9d
MK
179 case HTTP_STATUS_305_USE_PROXY:\r
180 AsciiPrint ("\n Redirection: 305 Use Proxy");\r
181 break;\r
406d1d92 182\r
d1050b9d
MK
183 case HTTP_STATUS_307_TEMPORARY_REDIRECT:\r
184 AsciiPrint ("\n Redirection: 307 Temporary Redirect");\r
185 break;\r
62cae351 186\r
d1050b9d
MK
187 case HTTP_STATUS_308_PERMANENT_REDIRECT:\r
188 AsciiPrint ("\n Redirection: 308 Permanent Redirect");\r
189 break;\r
f75a7f56 190\r
d1050b9d
MK
191 case HTTP_STATUS_400_BAD_REQUEST:\r
192 AsciiPrint ("\n Client Error: 400 Bad Request");\r
193 break;\r
f75a7f56 194\r
d1050b9d
MK
195 case HTTP_STATUS_401_UNAUTHORIZED:\r
196 AsciiPrint ("\n Client Error: 401 Unauthorized");\r
197 break;\r
62cae351 198\r
d1050b9d
MK
199 case HTTP_STATUS_402_PAYMENT_REQUIRED:\r
200 AsciiPrint ("\n Client Error: 402 Payment Required");\r
201 break;\r
62cae351 202\r
d1050b9d
MK
203 case HTTP_STATUS_403_FORBIDDEN:\r
204 AsciiPrint ("\n Client Error: 403 Forbidden");\r
205 break;\r
62cae351 206\r
d1050b9d
MK
207 case HTTP_STATUS_404_NOT_FOUND:\r
208 AsciiPrint ("\n Client Error: 404 Not Found");\r
209 break;\r
62cae351 210\r
d1050b9d
MK
211 case HTTP_STATUS_405_METHOD_NOT_ALLOWED:\r
212 AsciiPrint ("\n Client Error: 405 Method Not Allowed");\r
213 break;\r
62cae351 214\r
d1050b9d
MK
215 case HTTP_STATUS_406_NOT_ACCEPTABLE:\r
216 AsciiPrint ("\n Client Error: 406 Not Acceptable");\r
217 break;\r
62cae351 218\r
d1050b9d
MK
219 case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:\r
220 AsciiPrint ("\n Client Error: 407 Proxy Authentication Required");\r
221 break;\r
62cae351 222\r
d1050b9d
MK
223 case HTTP_STATUS_408_REQUEST_TIME_OUT:\r
224 AsciiPrint ("\n Client Error: 408 Request Timeout");\r
225 break;\r
62cae351 226\r
d1050b9d
MK
227 case HTTP_STATUS_409_CONFLICT:\r
228 AsciiPrint ("\n Client Error: 409 Conflict");\r
229 break;\r
62cae351 230\r
d1050b9d
MK
231 case HTTP_STATUS_410_GONE:\r
232 AsciiPrint ("\n Client Error: 410 Gone");\r
233 break;\r
62cae351 234\r
d1050b9d
MK
235 case HTTP_STATUS_411_LENGTH_REQUIRED:\r
236 AsciiPrint ("\n Client Error: 411 Length Required");\r
237 break;\r
62cae351 238\r
d1050b9d
MK
239 case HTTP_STATUS_412_PRECONDITION_FAILED:\r
240 AsciiPrint ("\n Client Error: 412 Precondition Failed");\r
241 break;\r
62cae351 242\r
d1050b9d
MK
243 case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:\r
244 AsciiPrint ("\n Client Error: 413 Request Entity Too Large");\r
245 break;\r
62cae351 246\r
d1050b9d
MK
247 case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:\r
248 AsciiPrint ("\n Client Error: 414 Request URI Too Long");\r
249 break;\r
62cae351 250\r
d1050b9d
MK
251 case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:\r
252 AsciiPrint ("\n Client Error: 415 Unsupported Media Type");\r
253 break;\r
62cae351 254\r
d1050b9d
MK
255 case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:\r
256 AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable");\r
257 break;\r
62cae351 258\r
d1050b9d
MK
259 case HTTP_STATUS_417_EXPECTATION_FAILED:\r
260 AsciiPrint ("\n Client Error: 417 Expectation Failed");\r
261 break;\r
62cae351 262\r
d1050b9d
MK
263 case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:\r
264 AsciiPrint ("\n Server Error: 500 Internal Server Error");\r
265 break;\r
62cae351 266\r
d1050b9d
MK
267 case HTTP_STATUS_501_NOT_IMPLEMENTED:\r
268 AsciiPrint ("\n Server Error: 501 Not Implemented");\r
269 break;\r
62cae351 270\r
d1050b9d
MK
271 case HTTP_STATUS_502_BAD_GATEWAY:\r
272 AsciiPrint ("\n Server Error: 502 Bad Gateway");\r
273 break;\r
62cae351 274\r
d1050b9d
MK
275 case HTTP_STATUS_503_SERVICE_UNAVAILABLE:\r
276 AsciiPrint ("\n Server Error: 503 Service Unavailable");\r
277 break;\r
62cae351 278\r
d1050b9d
MK
279 case HTTP_STATUS_504_GATEWAY_TIME_OUT:\r
280 AsciiPrint ("\n Server Error: 504 Gateway Timeout");\r
281 break;\r
62cae351 282\r
d1050b9d
MK
283 case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:\r
284 AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported");\r
285 break;\r
f75a7f56 286\r
d1050b9d 287 default:;\r
62cae351
ZL
288 }\r
289}\r
290\r
b659408b
ZL
291/**\r
292 Notify the callback function when an event is triggered.\r
293\r
294 @param[in] Event The triggered event.\r
295 @param[in] Context The opaque parameter to the function.\r
296\r
297**/\r
298VOID\r
299EFIAPI\r
300HttpBootCommonNotify (\r
d1050b9d
MK
301 IN EFI_EVENT Event,\r
302 IN VOID *Context\r
b659408b
ZL
303 )\r
304{\r
d1050b9d 305 *((BOOLEAN *)Context) = TRUE;\r
b659408b
ZL
306}\r
307\r
308/**\r
309 Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
310\r
311 @param[in] Private The pointer to the driver's private data.\r
312 @param[in] HostName Pointer to buffer containing hostname.\r
313 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
314\r
315 @retval EFI_SUCCESS Operation succeeded.\r
316 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
f75a7f56 317 @retval Others Other errors as indicated.\r
b659408b
ZL
318**/\r
319EFI_STATUS\r
320HttpBootDns (\r
d1050b9d
MK
321 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
322 IN CHAR16 *HostName,\r
323 OUT EFI_IPv6_ADDRESS *IpAddress\r
b659408b
ZL
324 )\r
325{\r
d1050b9d
MK
326 EFI_STATUS Status;\r
327 EFI_DNS6_PROTOCOL *Dns6;\r
328 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
329 EFI_DNS6_COMPLETION_TOKEN Token;\r
330 EFI_HANDLE Dns6Handle;\r
331 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
332 EFI_IPv6_ADDRESS *DnsServerList;\r
333 UINTN DnsServerListCount;\r
334 UINTN DataSize;\r
335 BOOLEAN IsDone;\r
336\r
337 DnsServerList = NULL;\r
338 DnsServerListCount = 0;\r
339 Dns6 = NULL;\r
340 Dns6Handle = NULL;\r
b659408b 341 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
f75a7f56 342\r
b659408b
ZL
343 //\r
344 // Get DNS server list from EFI IPv6 Configuration protocol.\r
345 //\r
d1050b9d 346 Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **)&Ip6Config);\r
b659408b
ZL
347 if (!EFI_ERROR (Status)) {\r
348 //\r
349 // Get the required size.\r
350 //\r
351 DataSize = 0;\r
d1050b9d 352 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
b659408b
ZL
353 if (Status == EFI_BUFFER_TOO_SMALL) {\r
354 DnsServerList = AllocatePool (DataSize);\r
355 if (DnsServerList == NULL) {\r
356 return EFI_OUT_OF_RESOURCES;\r
f75a7f56 357 }\r
b659408b
ZL
358\r
359 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
360 if (EFI_ERROR (Status)) {\r
361 FreePool (DnsServerList);\r
362 DnsServerList = NULL;\r
363 } else {\r
364 DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
365 }\r
366 }\r
367 }\r
d1050b9d 368\r
b659408b
ZL
369 //\r
370 // Create a DNSv6 child instance and get the protocol.\r
371 //\r
372 Status = NetLibCreateServiceChild (\r
373 Private->Controller,\r
75372581 374 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
375 &gEfiDns6ServiceBindingProtocolGuid,\r
376 &Dns6Handle\r
377 );\r
378 if (EFI_ERROR (Status)) {\r
379 goto Exit;\r
f75a7f56
LG
380 }\r
381\r
b659408b
ZL
382 Status = gBS->OpenProtocol (\r
383 Dns6Handle,\r
384 &gEfiDns6ProtocolGuid,\r
d1050b9d 385 (VOID **)&Dns6,\r
75372581 386 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
387 Private->Controller,\r
388 EFI_OPEN_PROTOCOL_BY_DRIVER\r
389 );\r
390 if (EFI_ERROR (Status)) {\r
391 goto Exit;\r
392 }\r
393\r
394 //\r
395 // Configure DNS6 instance for the DNS server address and protocol.\r
396 //\r
397 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
398 Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
399 Dns6ConfigData.DnsServerList = DnsServerList;\r
400 Dns6ConfigData.EnableDnsCache = TRUE;\r
401 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;\r
d1050b9d 402 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->StationIp.v6);\r
b659408b 403 Status = Dns6->Configure (\r
d1050b9d
MK
404 Dns6,\r
405 &Dns6ConfigData\r
406 );\r
b659408b
ZL
407 if (EFI_ERROR (Status)) {\r
408 goto Exit;\r
409 }\r
f75a7f56 410\r
b659408b
ZL
411 Token.Status = EFI_NOT_READY;\r
412 IsDone = FALSE;\r
413 //\r
414 // Create event to set the IsDone flag when name resolution is finished.\r
415 //\r
416 Status = gBS->CreateEvent (\r
417 EVT_NOTIFY_SIGNAL,\r
418 TPL_NOTIFY,\r
419 HttpBootCommonNotify,\r
420 &IsDone,\r
421 &Token.Event\r
422 );\r
423 if (EFI_ERROR (Status)) {\r
424 goto Exit;\r
425 }\r
426\r
427 //\r
428 // Start asynchronous name resolution.\r
429 //\r
430 Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
431 if (EFI_ERROR (Status)) {\r
432 goto Exit;\r
433 }\r
434\r
435 while (!IsDone) {\r
436 Dns6->Poll (Dns6);\r
437 }\r
f75a7f56 438\r
b659408b
ZL
439 //\r
440 // Name resolution is done, check result.\r
441 //\r
f75a7f56 442 Status = Token.Status;\r
b659408b
ZL
443 if (!EFI_ERROR (Status)) {\r
444 if (Token.RspData.H2AData == NULL) {\r
445 Status = EFI_DEVICE_ERROR;\r
446 goto Exit;\r
447 }\r
d1050b9d
MK
448\r
449 if ((Token.RspData.H2AData->IpCount == 0) || (Token.RspData.H2AData->IpList == NULL)) {\r
b659408b
ZL
450 Status = EFI_DEVICE_ERROR;\r
451 goto Exit;\r
452 }\r
d1050b9d 453\r
b659408b
ZL
454 //\r
455 // We just return the first IPv6 address from DNS protocol.\r
456 //\r
457 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
458 Status = EFI_SUCCESS;\r
459 }\r
d1050b9d 460\r
b659408b
ZL
461Exit:\r
462\r
463 if (Token.Event != NULL) {\r
464 gBS->CloseEvent (Token.Event);\r
465 }\r
d1050b9d 466\r
b659408b
ZL
467 if (Token.RspData.H2AData != NULL) {\r
468 if (Token.RspData.H2AData->IpList != NULL) {\r
469 FreePool (Token.RspData.H2AData->IpList);\r
470 }\r
d1050b9d 471\r
b659408b
ZL
472 FreePool (Token.RspData.H2AData);\r
473 }\r
474\r
475 if (Dns6 != NULL) {\r
476 Dns6->Configure (Dns6, NULL);\r
f75a7f56 477\r
b659408b
ZL
478 gBS->CloseProtocol (\r
479 Dns6Handle,\r
480 &gEfiDns6ProtocolGuid,\r
75372581 481 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
482 Private->Controller\r
483 );\r
484 }\r
485\r
486 if (Dns6Handle != NULL) {\r
487 NetLibDestroyServiceChild (\r
488 Private->Controller,\r
75372581 489 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
490 &gEfiDns6ServiceBindingProtocolGuid,\r
491 Dns6Handle\r
492 );\r
493 }\r
494\r
495 if (DnsServerList != NULL) {\r
496 FreePool (DnsServerList);\r
497 }\r
f75a7f56
LG
498\r
499 return Status;\r
b659408b 500}\r
d933e70a 501\r
221463c2
JW
502/**\r
503 This function checks the HTTP(S) URI scheme.\r
504\r
505 @param[in] Uri The pointer to the URI string.\r
f75a7f56 506\r
221463c2
JW
507 @retval EFI_SUCCESS The URI scheme is valid.\r
508 @retval EFI_INVALID_PARAMETER The URI scheme is not HTTP or HTTPS.\r
509 @retval EFI_ACCESS_DENIED HTTP is disabled and the URI is HTTP.\r
510\r
511**/\r
512EFI_STATUS\r
513HttpBootCheckUriScheme (\r
d1050b9d 514 IN CHAR8 *Uri\r
221463c2
JW
515 )\r
516{\r
d1050b9d
MK
517 UINTN Index;\r
518 EFI_STATUS Status;\r
221463c2
JW
519\r
520 Status = EFI_SUCCESS;\r
521\r
522 //\r
523 // Convert the scheme to all lower case.\r
524 //\r
525 for (Index = 0; Index < AsciiStrLen (Uri); Index++) {\r
526 if (Uri[Index] == ':') {\r
527 break;\r
528 }\r
d1050b9d
MK
529\r
530 if ((Uri[Index] >= 'A') && (Uri[Index] <= 'Z')) {\r
221463c2
JW
531 Uri[Index] -= (CHAR8)('A' - 'a');\r
532 }\r
533 }\r
534\r
535 //\r
536 // Return EFI_INVALID_PARAMETER if the URI is not HTTP or HTTPS.\r
537 //\r
538 if ((AsciiStrnCmp (Uri, "http://", 7) != 0) && (AsciiStrnCmp (Uri, "https://", 8) != 0)) {\r
c49ca4a2 539 DEBUG ((DEBUG_ERROR, "HttpBootCheckUriScheme: Invalid Uri.\n"));\r
221463c2
JW
540 return EFI_INVALID_PARAMETER;\r
541 }\r
f75a7f56 542\r
221463c2
JW
543 //\r
544 // HTTP is disabled, return EFI_ACCESS_DENIED if the URI is HTTP.\r
545 //\r
546 if (!PcdGetBool (PcdAllowHttpConnections) && (AsciiStrnCmp (Uri, "http://", 7) == 0)) {\r
c49ca4a2 547 DEBUG ((DEBUG_ERROR, "HttpBootCheckUriScheme: HTTP is disabled.\n"));\r
221463c2
JW
548 return EFI_ACCESS_DENIED;\r
549 }\r
550\r
551 return Status;\r
552}\r
553\r
fa848a40
FS
554/**\r
555 Get the URI address string from the input device path.\r
556\r
557 Caller need to free the buffer in the UriAddress pointer.\r
f75a7f56 558\r
fa848a40 559 @param[in] FilePath Pointer to the device path which contains a URI device path node.\r
73617fa6 560 @param[out] UriAddress The URI address string extract from the device path.\r
f75a7f56 561\r
fa848a40
FS
562 @retval EFI_SUCCESS The URI string is returned.\r
563 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
564\r
565**/\r
566EFI_STATUS\r
567HttpBootParseFilePath (\r
d1050b9d
MK
568 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
569 OUT CHAR8 **UriAddress\r
fa848a40
FS
570 )\r
571{\r
572 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
573 URI_DEVICE_PATH *UriDevicePath;\r
574 CHAR8 *Uri;\r
575 UINTN UriStrLength;\r
576\r
577 if (FilePath == NULL) {\r
578 return EFI_INVALID_PARAMETER;\r
579 }\r
580\r
581 *UriAddress = NULL;\r
582\r
583 //\r
584 // Extract the URI address from the FilePath\r
585 //\r
586 TempDevicePath = FilePath;\r
587 while (!IsDevicePathEnd (TempDevicePath)) {\r
588 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
d1050b9d
MK
589 (DevicePathSubType (TempDevicePath) == MSG_URI_DP))\r
590 {\r
591 UriDevicePath = (URI_DEVICE_PATH *)TempDevicePath;\r
fa848a40
FS
592 //\r
593 // UEFI Spec doesn't require the URI to be a NULL-terminated string\r
594 // So we allocate a new buffer and always append a '\0' to it.\r
595 //\r
d1050b9d 596 UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
fa848a40
FS
597 if (UriStrLength == 0) {\r
598 //\r
599 // return a NULL UriAddress if it's a empty URI device path node.\r
600 //\r
601 break;\r
602 }\r
d1050b9d 603\r
fa848a40
FS
604 Uri = AllocatePool (UriStrLength + 1);\r
605 if (Uri == NULL) {\r
606 return EFI_OUT_OF_RESOURCES;\r
607 }\r
d1050b9d
MK
608\r
609 CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
610 Uri[DevicePathNodeLength (UriDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL)] = '\0';\r
fa848a40
FS
611\r
612 *UriAddress = Uri;\r
613 }\r
d1050b9d 614\r
fa848a40
FS
615 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
616 }\r
617\r
618 return EFI_SUCCESS;\r
619}\r
587d204c
FS
620\r
621/**\r
622 This function returns the image type according to server replied HTTP message\r
623 and also the image's URI info.\r
624\r
625 @param[in] Uri The pointer to the image's URI string.\r
f75a7f56
LG
626 @param[in] UriParser URI Parse result returned by NetHttpParseUrl().\r
627 @param[in] HeaderCount Number of HTTP header structures in Headers list.\r
587d204c
FS
628 @param[in] Headers Array containing list of HTTP headers.\r
629 @param[out] ImageType The image type of the downloaded file.\r
f75a7f56 630\r
587d204c
FS
631 @retval EFI_SUCCESS The image type is returned in ImageType.\r
632 @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL.\r
633 @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL.\r
634 @retval EFI_NOT_FOUND Failed to identify the image type.\r
c36b7b51 635 @retval Others Unexpected error happened.\r
587d204c
FS
636\r
637**/\r
638EFI_STATUS\r
639HttpBootCheckImageType (\r
d1050b9d
MK
640 IN CHAR8 *Uri,\r
641 IN VOID *UriParser,\r
642 IN UINTN HeaderCount,\r
643 IN EFI_HTTP_HEADER *Headers,\r
644 OUT HTTP_BOOT_IMAGE_TYPE *ImageType\r
587d204c
FS
645 )\r
646{\r
d1050b9d
MK
647 EFI_STATUS Status;\r
648 EFI_HTTP_HEADER *Header;\r
649 CHAR8 *FilePath;\r
650 CHAR8 *FilePost;\r
587d204c 651\r
d1050b9d 652 if ((Uri == NULL) || (UriParser == NULL) || (ImageType == NULL)) {\r
587d204c
FS
653 return EFI_INVALID_PARAMETER;\r
654 }\r
655\r
d1050b9d 656 if ((HeaderCount != 0) && (Headers == NULL)) {\r
587d204c
FS
657 return EFI_INVALID_PARAMETER;\r
658 }\r
659\r
660 //\r
661 // Determine the image type by the HTTP Content-Type header field first.\r
b173ad78
JW
662 // "application/efi" -> EFI Image\r
663 // "application/vnd.efi-iso" -> CD/DVD Image\r
664 // "application/vnd.efi-img" -> Virtual Disk Image\r
587d204c
FS
665 //\r
666 Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE);\r
667 if (Header != NULL) {\r
668 if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) {\r
669 *ImageType = ImageTypeEfi;\r
670 return EFI_SUCCESS;\r
b173ad78
JW
671 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) {\r
672 *ImageType = ImageTypeVirtualCd;\r
673 return EFI_SUCCESS;\r
674 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) {\r
675 *ImageType = ImageTypeVirtualDisk;\r
676 return EFI_SUCCESS;\r
587d204c
FS
677 }\r
678 }\r
679\r
680 //\r
681 // Determine the image type by file extension:\r
682 // *.efi -> EFI Image\r
683 // *.iso -> CD/DVD Image\r
684 // *.img -> Virtual Disk Image\r
685 //\r
686 Status = HttpUrlGetPath (\r
687 Uri,\r
688 UriParser,\r
689 &FilePath\r
690 );\r
691 if (EFI_ERROR (Status)) {\r
692 return Status;\r
693 }\r
694\r
695 FilePost = FilePath + AsciiStrLen (FilePath) - 4;\r
bd5ec03d 696 if (AsciiStriCmp (FilePost, ".efi") == 0) {\r
587d204c 697 *ImageType = ImageTypeEfi;\r
bd5ec03d 698 } else if (AsciiStriCmp (FilePost, ".iso") == 0) {\r
587d204c 699 *ImageType = ImageTypeVirtualCd;\r
bd5ec03d 700 } else if (AsciiStriCmp (FilePost, ".img") == 0) {\r
587d204c
FS
701 *ImageType = ImageTypeVirtualDisk;\r
702 } else {\r
703 *ImageType = ImageTypeMax;\r
704 }\r
705\r
706 FreePool (FilePath);\r
707\r
708 return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
709}\r
710\r
711/**\r
712 This function register the RAM disk info to the system.\r
f75a7f56 713\r
587d204c
FS
714 @param[in] Private The pointer to the driver's private data.\r
715 @param[in] BufferSize The size of Buffer in bytes.\r
716 @param[in] Buffer The base address of the RAM disk.\r
717 @param[in] ImageType The image type of the file in Buffer.\r
718\r
719 @retval EFI_SUCCESS The RAM disk has been registered.\r
720 @retval EFI_NOT_FOUND No RAM disk protocol instances were found.\r
721 @retval EFI_UNSUPPORTED The ImageType is not supported.\r
722 @retval Others Unexpected error happened.\r
723\r
724**/\r
725EFI_STATUS\r
726HttpBootRegisterRamDisk (\r
d1050b9d
MK
727 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
728 IN UINTN BufferSize,\r
729 IN VOID *Buffer,\r
730 IN HTTP_BOOT_IMAGE_TYPE ImageType\r
587d204c
FS
731 )\r
732{\r
d1050b9d
MK
733 EFI_RAM_DISK_PROTOCOL *RamDisk;\r
734 EFI_STATUS Status;\r
735 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
736 EFI_GUID *RamDiskType;\r
f75a7f56 737\r
587d204c
FS
738 ASSERT (Private != NULL);\r
739 ASSERT (Buffer != NULL);\r
740 ASSERT (BufferSize != 0);\r
741\r
d1050b9d 742 Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID **)&RamDisk);\r
587d204c 743 if (EFI_ERROR (Status)) {\r
c49ca4a2 744 DEBUG ((DEBUG_ERROR, "HTTP Boot: Couldn't find the RAM Disk protocol - %r\n", Status));\r
587d204c
FS
745 return Status;\r
746 }\r
747\r
748 if (ImageType == ImageTypeVirtualCd) {\r
749 RamDiskType = &gEfiVirtualCdGuid;\r
750 } else if (ImageType == ImageTypeVirtualDisk) {\r
751 RamDiskType = &gEfiVirtualDiskGuid;\r
752 } else {\r
753 return EFI_UNSUPPORTED;\r
754 }\r
f75a7f56 755\r
587d204c 756 Status = RamDisk->Register (\r
d1050b9d
MK
757 (UINTN)Buffer,\r
758 (UINT64)BufferSize,\r
759 RamDiskType,\r
760 Private->UsingIpv6 ? Private->Ip6Nic->DevicePath : Private->Ip4Nic->DevicePath,\r
761 &DevicePath\r
762 );\r
587d204c 763 if (EFI_ERROR (Status)) {\r
c49ca4a2 764 DEBUG ((DEBUG_ERROR, "HTTP Boot: Failed to register RAM Disk - %r\n", Status));\r
587d204c
FS
765 }\r
766\r
767 return Status;\r
768}\r
769\r
bb4831c0
FS
770/**\r
771 Indicate if the HTTP status code indicates a redirection.\r
f75a7f56 772\r
bb4831c0
FS
773 @param[in] StatusCode HTTP status code from server.\r
774\r
775 @return TRUE if it's redirection.\r
776\r
777**/\r
778BOOLEAN\r
779HttpBootIsHttpRedirectStatusCode (\r
d1050b9d 780 IN EFI_HTTP_STATUS_CODE StatusCode\r
2913ebb2 781 )\r
bb4831c0 782{\r
d1050b9d
MK
783 if ((StatusCode == HTTP_STATUS_301_MOVED_PERMANENTLY) ||\r
784 (StatusCode == HTTP_STATUS_302_FOUND) ||\r
785 (StatusCode == HTTP_STATUS_307_TEMPORARY_REDIRECT) ||\r
786 (StatusCode == HTTP_STATUS_308_PERMANENT_REDIRECT))\r
787 {\r
bb4831c0
FS
788 return TRUE;\r
789 }\r
790\r
791 return FALSE;\r
792}\r