]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
MdeModulePkg/DxeHttpLib: Handle new #define in HttpMappingToStatusCode
[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
221463c2 4Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
f58554fc
GB
5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
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
JW
8The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php. \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
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
18\r
19/**\r
20 Get the Nic handle using any child handle in the IPv4 stack.\r
21\r
22 @param[in] ControllerHandle Pointer to child handle over IPv4.\r
23\r
24 @return NicHandle The pointer to the Nic handle.\r
25 @return NULL Can't find the Nic handle.\r
26\r
27**/\r
28EFI_HANDLE\r
29HttpBootGetNicByIp4Children (\r
30 IN EFI_HANDLE ControllerHandle\r
31 )\r
32{\r
33 EFI_HANDLE NicHandle;\r
34\r
35 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
36 if (NicHandle == NULL) {\r
37 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
38 if (NicHandle == NULL) {\r
39 return NULL;\r
40 }\r
41 }\r
42\r
43 return NicHandle;\r
44}\r
45\r
b659408b
ZL
46/**\r
47 Get the Nic handle using any child handle in the IPv6 stack.\r
48\r
49 @param[in] ControllerHandle Pointer to child handle over IPv6.\r
50\r
51 @return NicHandle The pointer to the Nic handle.\r
52 @return NULL Can't find the Nic handle.\r
53\r
54**/\r
55EFI_HANDLE\r
56HttpBootGetNicByIp6Children (\r
57 IN EFI_HANDLE ControllerHandle\r
58 )\r
59{\r
60 EFI_HANDLE NicHandle;\r
61 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
62 if (NicHandle == NULL) {\r
63 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
64 if (NicHandle == NULL) {\r
65 return NULL;\r
66 }\r
67 }\r
68\r
69 return NicHandle;\r
70}\r
d933e70a
JW
71\r
72/**\r
73 This function is to convert UINTN to ASCII string with the required formatting.\r
74\r
75 @param[in] Number Numeric value to be converted.\r
76 @param[in] Buffer The pointer to the buffer for ASCII string.\r
77 @param[in] Length The length of the required format.\r
78\r
79**/\r
80VOID\r
81HttpBootUintnToAscDecWithFormat (\r
82 IN UINTN Number,\r
83 IN UINT8 *Buffer,\r
84 IN INTN Length\r
85 )\r
86{\r
87 UINTN Remainder;\r
88\r
413535bb 89 for (; Length > 0; Length--) {\r
d933e70a
JW
90 Remainder = Number % 10;\r
91 Number /= 10;\r
413535bb 92 Buffer[Length - 1] = (UINT8) ('0' + Remainder);\r
d933e70a
JW
93 }\r
94}\r
95\r
96/**\r
97 This function is to display the IPv4 address.\r
98\r
99 @param[in] Ip The pointer to the IPv4 address.\r
100\r
101**/\r
102VOID\r
103HttpBootShowIp4Addr (\r
104 IN EFI_IPv4_ADDRESS *Ip\r
105 )\r
106{\r
107 UINTN Index;\r
108\r
109 for (Index = 0; Index < 4; Index++) {\r
110 AsciiPrint ("%d", Ip->Addr[Index]);\r
111 if (Index < 3) {\r
112 AsciiPrint (".");\r
113 }\r
114 }\r
115}\r
116\r
b659408b
ZL
117/**\r
118 This function is to display the IPv6 address.\r
119\r
120 @param[in] Ip The pointer to the IPv6 address.\r
121\r
122**/\r
123VOID\r
124HttpBootShowIp6Addr (\r
125 IN EFI_IPv6_ADDRESS *Ip\r
126 )\r
127{\r
128 UINTN Index;\r
129\r
130 for (Index = 0; Index < 16; Index++) {\r
131\r
132 if (Ip->Addr[Index] != 0) {\r
133 AsciiPrint ("%x", Ip->Addr[Index]);\r
134 }\r
135 Index++;\r
136 if (Index > 15) {\r
137 return;\r
138 }\r
139 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
140 AsciiPrint ("0");\r
141 }\r
142 AsciiPrint ("%x", Ip->Addr[Index]);\r
143 if (Index < 15) {\r
144 AsciiPrint (":");\r
145 }\r
146 }\r
147}\r
148\r
62cae351
ZL
149/**\r
150 This function is to display the HTTP error status.\r
151\r
152 @param[in] StatusCode The status code value in HTTP message.\r
153\r
154**/\r
155VOID\r
156HttpBootPrintErrorMessage (\r
157 EFI_HTTP_STATUS_CODE StatusCode\r
158 )\r
159{\r
160 AsciiPrint ("\n");\r
161\r
162 switch (StatusCode) {\r
163 case HTTP_STATUS_300_MULTIPLE_CHIOCES:\r
164 AsciiPrint ("\n Redirection: 300 Multiple Choices");\r
165 break; \r
166 \r
167 case HTTP_STATUS_301_MOVED_PERMANENTLY:\r
168 AsciiPrint ("\n Redirection: 301 Moved Permanently");\r
169 break; \r
170 \r
171 case HTTP_STATUS_302_FOUND:\r
172 AsciiPrint ("\n Redirection: 302 Found");\r
173 break; \r
174 \r
175 case HTTP_STATUS_303_SEE_OTHER:\r
176 AsciiPrint ("\n Redirection: 303 See Other");\r
177 break; \r
178\r
179 case HTTP_STATUS_304_NOT_MODIFIED:\r
180 AsciiPrint ("\n Redirection: 304 Not Modified");\r
181 break; \r
182\r
183 case HTTP_STATUS_305_USE_PROXY:\r
184 AsciiPrint ("\n Redirection: 305 Use Proxy");\r
185 break; \r
186\r
187 case HTTP_STATUS_307_TEMPORARY_REDIRECT:\r
188 AsciiPrint ("\n Redirection: 307 Temporary Redirect");\r
189 break; \r
190\r
191 case HTTP_STATUS_400_BAD_REQUEST:\r
192 AsciiPrint ("\n Client Error: 400 Bad Request");\r
193 break;\r
194 \r
195 case HTTP_STATUS_401_UNAUTHORIZED:\r
196 AsciiPrint ("\n Client Error: 401 Unauthorized");\r
197 break;\r
198 \r
199 case HTTP_STATUS_402_PAYMENT_REQUIRED:\r
200 AsciiPrint ("\n Client Error: 402 Payment Required");\r
201 break;\r
202\r
203 case HTTP_STATUS_403_FORBIDDEN:\r
204 AsciiPrint ("\n Client Error: 403 Forbidden");\r
205 break;\r
206\r
207 case HTTP_STATUS_404_NOT_FOUND:\r
208 AsciiPrint ("\n Client Error: 404 Not Found");\r
209 break;\r
210\r
211 case HTTP_STATUS_405_METHOD_NOT_ALLOWED:\r
212 AsciiPrint ("\n Client Error: 405 Method Not Allowed");\r
213 break;\r
214\r
215 case HTTP_STATUS_406_NOT_ACCEPTABLE:\r
216 AsciiPrint ("\n Client Error: 406 Not Acceptable");\r
217 break;\r
218\r
219 case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:\r
220 AsciiPrint ("\n Client Error: 407 Proxy Authentication Required");\r
221 break;\r
222\r
223 case HTTP_STATUS_408_REQUEST_TIME_OUT:\r
224 AsciiPrint ("\n Client Error: 408 Request Timeout");\r
225 break;\r
226\r
227 case HTTP_STATUS_409_CONFLICT:\r
228 AsciiPrint ("\n Client Error: 409 Conflict");\r
229 break;\r
230\r
231 case HTTP_STATUS_410_GONE:\r
232 AsciiPrint ("\n Client Error: 410 Gone");\r
233 break;\r
234\r
235 case HTTP_STATUS_411_LENGTH_REQUIRED:\r
236 AsciiPrint ("\n Client Error: 411 Length Required");\r
237 break;\r
238\r
239 case HTTP_STATUS_412_PRECONDITION_FAILED:\r
240 AsciiPrint ("\n Client Error: 412 Precondition Failed");\r
241 break;\r
242\r
243 case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:\r
244 AsciiPrint ("\n Client Error: 413 Request Entity Too Large");\r
245 break;\r
246\r
247 case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:\r
248 AsciiPrint ("\n Client Error: 414 Request URI Too Long");\r
249 break;\r
250\r
251 case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:\r
252 AsciiPrint ("\n Client Error: 415 Unsupported Media Type");\r
253 break;\r
254\r
255 case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:\r
256 AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable");\r
257 break;\r
258\r
259 case HTTP_STATUS_417_EXPECTATION_FAILED:\r
260 AsciiPrint ("\n Client Error: 417 Expectation Failed");\r
261 break;\r
262\r
263 case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:\r
264 AsciiPrint ("\n Server Error: 500 Internal Server Error");\r
265 break;\r
266\r
267 case HTTP_STATUS_501_NOT_IMPLEMENTED:\r
268 AsciiPrint ("\n Server Error: 501 Not Implemented");\r
269 break;\r
270\r
271 case HTTP_STATUS_502_BAD_GATEWAY:\r
272 AsciiPrint ("\n Server Error: 502 Bad Gateway");\r
273 break;\r
274\r
275 case HTTP_STATUS_503_SERVICE_UNAVAILABLE:\r
276 AsciiPrint ("\n Server Error: 503 Service Unavailable");\r
277 break;\r
278\r
279 case HTTP_STATUS_504_GATEWAY_TIME_OUT:\r
280 AsciiPrint ("\n Server Error: 504 Gateway Timeout");\r
281 break;\r
282\r
283 case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:\r
284 AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported");\r
285 break;\r
286\r
287 default: ;\r
288 \r
289 }\r
290}\r
291\r
b659408b
ZL
292/**\r
293 Notify the callback function when an event is triggered.\r
294\r
295 @param[in] Event The triggered event.\r
296 @param[in] Context The opaque parameter to the function.\r
297\r
298**/\r
299VOID\r
300EFIAPI\r
301HttpBootCommonNotify (\r
302 IN EFI_EVENT Event,\r
303 IN VOID *Context\r
304 )\r
305{\r
306 *((BOOLEAN *) Context) = TRUE;\r
307}\r
308\r
309/**\r
310 Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
311\r
312 @param[in] Private The pointer to the driver's private data.\r
313 @param[in] HostName Pointer to buffer containing hostname.\r
314 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
315\r
316 @retval EFI_SUCCESS Operation succeeded.\r
317 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
318 @retval Others Other errors as indicated. \r
319**/\r
320EFI_STATUS\r
321HttpBootDns (\r
322 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
323 IN CHAR16 *HostName,\r
324 OUT EFI_IPv6_ADDRESS *IpAddress \r
325 )\r
326{\r
327 EFI_STATUS Status;\r
328 EFI_DNS6_PROTOCOL *Dns6;\r
329 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
330 EFI_DNS6_COMPLETION_TOKEN Token;\r
331 EFI_HANDLE Dns6Handle;\r
332 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
333 EFI_IPv6_ADDRESS *DnsServerList;\r
334 UINTN DnsServerListCount;\r
335 UINTN DataSize;\r
336 BOOLEAN IsDone; \r
337 \r
338 DnsServerList = NULL;\r
339 DnsServerListCount = 0;\r
340 Dns6 = NULL;\r
341 Dns6Handle = NULL;\r
342 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
343 \r
344 //\r
345 // Get DNS server list from EFI IPv6 Configuration protocol.\r
346 //\r
347 Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
348 if (!EFI_ERROR (Status)) {\r
349 //\r
350 // Get the required size.\r
351 //\r
352 DataSize = 0;\r
353 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
354 if (Status == EFI_BUFFER_TOO_SMALL) {\r
355 DnsServerList = AllocatePool (DataSize);\r
356 if (DnsServerList == NULL) {\r
357 return EFI_OUT_OF_RESOURCES;\r
358 } \r
359\r
360 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
361 if (EFI_ERROR (Status)) {\r
362 FreePool (DnsServerList);\r
363 DnsServerList = NULL;\r
364 } else {\r
365 DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
366 }\r
367 }\r
368 }\r
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
380 } \r
381 \r
382 Status = gBS->OpenProtocol (\r
383 Dns6Handle,\r
384 &gEfiDns6ProtocolGuid,\r
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
402 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6);\r
403 Status = Dns6->Configure (\r
404 Dns6,\r
405 &Dns6ConfigData\r
406 );\r
407 if (EFI_ERROR (Status)) {\r
408 goto Exit;\r
409 }\r
410 \r
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
438 \r
439 //\r
440 // Name resolution is done, check result.\r
441 //\r
442 Status = Token.Status; \r
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
448 if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
449 Status = EFI_DEVICE_ERROR;\r
450 goto Exit;\r
451 }\r
452 //\r
453 // We just return the first IPv6 address from DNS protocol.\r
454 //\r
455 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
456 Status = EFI_SUCCESS;\r
457 }\r
458Exit:\r
459\r
460 if (Token.Event != NULL) {\r
461 gBS->CloseEvent (Token.Event);\r
462 }\r
463 if (Token.RspData.H2AData != NULL) {\r
464 if (Token.RspData.H2AData->IpList != NULL) {\r
465 FreePool (Token.RspData.H2AData->IpList);\r
466 }\r
467 FreePool (Token.RspData.H2AData);\r
468 }\r
469\r
470 if (Dns6 != NULL) {\r
471 Dns6->Configure (Dns6, NULL);\r
472 \r
473 gBS->CloseProtocol (\r
474 Dns6Handle,\r
475 &gEfiDns6ProtocolGuid,\r
75372581 476 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
477 Private->Controller\r
478 );\r
479 }\r
480\r
481 if (Dns6Handle != NULL) {\r
482 NetLibDestroyServiceChild (\r
483 Private->Controller,\r
75372581 484 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
485 &gEfiDns6ServiceBindingProtocolGuid,\r
486 Dns6Handle\r
487 );\r
488 }\r
489\r
490 if (DnsServerList != NULL) {\r
491 FreePool (DnsServerList);\r
492 }\r
493 \r
494 return Status; \r
495}\r
d933e70a
JW
496/**\r
497 Create a HTTP_IO_HEADER to hold the HTTP header items.\r
498\r
499 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.\r
500\r
501 @return A pointer of the HTTP header holder or NULL if failed.\r
502 \r
503**/\r
504HTTP_IO_HEADER *\r
505HttpBootCreateHeader (\r
506 UINTN MaxHeaderCount\r
b659408b 507 )\r
d933e70a
JW
508{\r
509 HTTP_IO_HEADER *HttpIoHeader;\r
510\r
511 if (MaxHeaderCount == 0) {\r
512 return NULL;\r
513 }\r
514\r
515 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));\r
516 if (HttpIoHeader == NULL) {\r
517 return NULL;\r
518 }\r
519\r
520 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;\r
521 HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);\r
522\r
523 return HttpIoHeader;\r
524}\r
525\r
526/**\r
527 Destroy the HTTP_IO_HEADER and release the resouces. \r
528\r
529 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.\r
530\r
531**/\r
532VOID\r
533HttpBootFreeHeader (\r
534 IN HTTP_IO_HEADER *HttpIoHeader\r
535 )\r
536{\r
537 UINTN Index;\r
538 \r
539 if (HttpIoHeader != NULL) {\r
540 if (HttpIoHeader->HeaderCount != 0) {\r
541 for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {\r
542 FreePool (HttpIoHeader->Headers[Index].FieldName);\r
543 FreePool (HttpIoHeader->Headers[Index].FieldValue);\r
544 }\r
545 }\r
546 FreePool (HttpIoHeader);\r
547 }\r
548}\r
549\r
d933e70a
JW
550/**\r
551 Set or update a HTTP header with the field name and corresponding value.\r
552\r
553 @param[in] HttpIoHeader Point to the HTTP header holder.\r
f58554fc 554 @param[in] FieldName Null terminated string which describes a field name.\r
d933e70a
JW
555 @param[in] FieldValue Null terminated string which describes the corresponding field value.\r
556\r
557 @retval EFI_SUCCESS The HTTP header has been set or updated.\r
558 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
559 @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.\r
560 @retval Other Unexpected error happened.\r
561 \r
562**/\r
563EFI_STATUS\r
564HttpBootSetHeader (\r
565 IN HTTP_IO_HEADER *HttpIoHeader,\r
566 IN CHAR8 *FieldName,\r
567 IN CHAR8 *FieldValue\r
568 )\r
569{\r
570 EFI_HTTP_HEADER *Header;\r
571 UINTN StrSize;\r
572 CHAR8 *NewFieldValue;\r
573 \r
574 if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {\r
575 return EFI_INVALID_PARAMETER;\r
576 }\r
577\r
f58554fc 578 Header = HttpFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);\r
d933e70a
JW
579 if (Header == NULL) {\r
580 //\r
581 // Add a new header.\r
582 //\r
583 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {\r
584 return EFI_OUT_OF_RESOURCES;\r
585 }\r
586 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];\r
587\r
588 StrSize = AsciiStrSize (FieldName);\r
589 Header->FieldName = AllocatePool (StrSize);\r
590 if (Header->FieldName == NULL) {\r
591 return EFI_OUT_OF_RESOURCES;\r
592 }\r
593 CopyMem (Header->FieldName, FieldName, StrSize);\r
594 Header->FieldName[StrSize -1] = '\0';\r
595\r
596 StrSize = AsciiStrSize (FieldValue);\r
597 Header->FieldValue = AllocatePool (StrSize);\r
598 if (Header->FieldValue == NULL) {\r
599 FreePool (Header->FieldName);\r
600 return EFI_OUT_OF_RESOURCES;\r
601 }\r
602 CopyMem (Header->FieldValue, FieldValue, StrSize);\r
603 Header->FieldValue[StrSize -1] = '\0';\r
604\r
605 HttpIoHeader->HeaderCount++;\r
606 } else {\r
607 //\r
608 // Update an existing one.\r
609 //\r
610 StrSize = AsciiStrSize (FieldValue);\r
611 NewFieldValue = AllocatePool (StrSize);\r
612 if (NewFieldValue == NULL) {\r
613 return EFI_OUT_OF_RESOURCES;\r
614 }\r
615 CopyMem (NewFieldValue, FieldValue, StrSize);\r
616 NewFieldValue[StrSize -1] = '\0';\r
617 \r
618 if (Header->FieldValue != NULL) {\r
619 FreePool (Header->FieldValue);\r
620 }\r
621 Header->FieldValue = NewFieldValue;\r
622 }\r
623\r
624 return EFI_SUCCESS;\r
625}\r
626\r
5e9e151c
JW
627/**\r
628 Notify the callback function when an event is triggered.\r
629\r
630 @param[in] Context The opaque parameter to the function.\r
631\r
632**/\r
633VOID\r
6c6452c6 634EFIAPI\r
5e9e151c
JW
635HttpIoNotifyDpc (\r
636 IN VOID *Context\r
637 )\r
638{\r
639 *((BOOLEAN *) Context) = TRUE;\r
640}\r
641\r
642/**\r
643 Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.\r
644\r
645 @param[in] Event The event signaled.\r
646 @param[in] Context The opaque parameter to the function.\r
647\r
648**/\r
649VOID\r
6c6452c6 650EFIAPI\r
5e9e151c
JW
651HttpIoNotify (\r
652 IN EFI_EVENT Event,\r
653 IN VOID *Context\r
654 )\r
655{\r
656 //\r
657 // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK\r
658 //\r
659 QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context);\r
660}\r
661\r
d933e70a
JW
662/**\r
663 Create a HTTP_IO to access the HTTP service. It will create and configure\r
664 a HTTP child handle.\r
665\r
666 @param[in] Image The handle of the driver image.\r
667 @param[in] Controller The handle of the controller.\r
668 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
669 @param[in] ConfigData The HTTP_IO configuration data.\r
670 @param[out] HttpIo The HTTP_IO.\r
671 \r
672 @retval EFI_SUCCESS The HTTP_IO is created and configured.\r
673 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
674 @retval EFI_UNSUPPORTED One or more of the control options are not\r
675 supported in the implementation.\r
676 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
677 @retval Others Failed to create the HTTP_IO or configure it.\r
678\r
679**/\r
680EFI_STATUS\r
681HttpIoCreateIo (\r
682 IN EFI_HANDLE Image,\r
683 IN EFI_HANDLE Controller,\r
684 IN UINT8 IpVersion,\r
685 IN HTTP_IO_CONFIG_DATA *ConfigData,\r
686 OUT HTTP_IO *HttpIo\r
687 )\r
688{\r
689 EFI_STATUS Status;\r
690 EFI_HTTP_CONFIG_DATA HttpConfigData;\r
691 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;\r
b659408b 692 EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;\r
d933e70a
JW
693 EFI_HTTP_PROTOCOL *Http;\r
694 EFI_EVENT Event;\r
695 \r
696 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
699\r
700 if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {\r
701 return EFI_UNSUPPORTED;\r
702 }\r
703\r
704 ZeroMem (HttpIo, sizeof (HTTP_IO));\r
705 \r
706 //\r
707 // Create the HTTP child instance and get the HTTP protocol.\r
708 // \r
709 Status = NetLibCreateServiceChild (\r
710 Controller,\r
711 Image,\r
712 &gEfiHttpServiceBindingProtocolGuid,\r
713 &HttpIo->Handle\r
714 );\r
715 if (EFI_ERROR (Status)) {\r
716 return Status;\r
717 }\r
718\r
719 Status = gBS->OpenProtocol (\r
720 HttpIo->Handle,\r
721 &gEfiHttpProtocolGuid,\r
722 (VOID **) &Http,\r
723 Image,\r
724 Controller,\r
725 EFI_OPEN_PROTOCOL_BY_DRIVER\r
726 );\r
727 if (EFI_ERROR (Status) || (Http == NULL)) {\r
728 goto ON_ERROR;\r
729 }\r
730\r
731 //\r
732 // Init the configuration data and configure the HTTP child.\r
733 //\r
734 HttpIo->Image = Image;\r
735 HttpIo->Controller = Controller;\r
736 HttpIo->IpVersion = IpVersion;\r
737 HttpIo->Http = Http;\r
738\r
739 ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));\r
740 HttpConfigData.HttpVersion = HttpVersion11;\r
741 HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;\r
742 if (HttpIo->IpVersion == IP_VERSION_4) {\r
743 HttpConfigData.LocalAddressIsIPv6 = FALSE;\r
744 \r
745 Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;\r
746 Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;\r
747 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);\r
748 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);\r
749 HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; \r
750 } else {\r
b659408b
ZL
751 HttpConfigData.LocalAddressIsIPv6 = TRUE;\r
752 Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort;\r
753 IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);\r
754 HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;\r
d933e70a
JW
755 }\r
756 \r
757 Status = Http->Configure (Http, &HttpConfigData);\r
758 if (EFI_ERROR (Status)) {\r
759 goto ON_ERROR;\r
760 }\r
761\r
762 //\r
763 // Create events for variuos asynchronous operations.\r
764 //\r
765 Status = gBS->CreateEvent (\r
766 EVT_NOTIFY_SIGNAL,\r
767 TPL_NOTIFY,\r
5e9e151c 768 HttpIoNotify,\r
d933e70a
JW
769 &HttpIo->IsTxDone,\r
770 &Event\r
771 );\r
772 if (EFI_ERROR (Status)) {\r
773 goto ON_ERROR;\r
774 }\r
775 HttpIo->ReqToken.Event = Event;\r
776 HttpIo->ReqToken.Message = &HttpIo->ReqMessage;\r
777\r
778 Status = gBS->CreateEvent (\r
779 EVT_NOTIFY_SIGNAL,\r
780 TPL_NOTIFY,\r
5e9e151c 781 HttpIoNotify,\r
d933e70a
JW
782 &HttpIo->IsRxDone,\r
783 &Event\r
784 );\r
785 if (EFI_ERROR (Status)) {\r
786 goto ON_ERROR;\r
787 }\r
788 HttpIo->RspToken.Event = Event;\r
789 HttpIo->RspToken.Message = &HttpIo->RspMessage;\r
790\r
7570696c
JW
791 //\r
792 // Create TimeoutEvent for response\r
793 //\r
794 Status = gBS->CreateEvent (\r
795 EVT_TIMER,\r
796 TPL_CALLBACK,\r
797 NULL,\r
798 NULL,\r
799 &Event\r
800 );\r
801 if (EFI_ERROR (Status)) {\r
802 goto ON_ERROR;\r
803 }\r
804 HttpIo->TimeoutEvent = Event;\r
805\r
d933e70a
JW
806 return EFI_SUCCESS;\r
807 \r
808ON_ERROR:\r
809 HttpIoDestroyIo (HttpIo);\r
810\r
811 return Status;\r
812}\r
813\r
814/**\r
815 Destroy the HTTP_IO and release the resouces. \r
816\r
817 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.\r
818\r
819**/\r
820VOID\r
821HttpIoDestroyIo (\r
822 IN HTTP_IO *HttpIo\r
823 )\r
824{\r
825 EFI_HTTP_PROTOCOL *Http;\r
826 EFI_EVENT Event;\r
827\r
828 if (HttpIo == NULL) {\r
829 return;\r
830 }\r
831\r
832 Event = HttpIo->ReqToken.Event;\r
833 if (Event != NULL) {\r
834 gBS->CloseEvent (Event);\r
835 }\r
836\r
837 Event = HttpIo->RspToken.Event;\r
838 if (Event != NULL) {\r
839 gBS->CloseEvent (Event);\r
840 }\r
7570696c
JW
841\r
842 Event = HttpIo->TimeoutEvent;\r
843 if (Event != NULL) {\r
844 gBS->CloseEvent (Event);\r
845 }\r
d933e70a
JW
846 \r
847 Http = HttpIo->Http;\r
848 if (Http != NULL) {\r
849 Http->Configure (Http, NULL);\r
850 gBS->CloseProtocol (\r
851 HttpIo->Handle,\r
852 &gEfiHttpProtocolGuid,\r
853 HttpIo->Image,\r
854 HttpIo->Controller\r
855 );\r
856 }\r
857\r
858 NetLibDestroyServiceChild (\r
859 HttpIo->Controller,\r
860 HttpIo->Image,\r
861 &gEfiHttpServiceBindingProtocolGuid,\r
862 HttpIo->Handle\r
863 );\r
864}\r
865\r
866/**\r
867 Synchronously send a HTTP REQUEST message to the server.\r
868 \r
869 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
870 @param[in] Request A pointer to storage such data as URL and HTTP method.\r
871 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
872 @param[in] Headers Array containing list of HTTP headers.\r
873 @param[in] BodyLength Length in bytes of the HTTP body.\r
874 @param[in] Body Body associated with the HTTP request. \r
875 \r
876 @retval EFI_SUCCESS The HTTP request is trasmitted.\r
877 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
878 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
879 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
880 @retval Others Other errors as indicated.\r
881\r
882**/\r
883EFI_STATUS\r
884HttpIoSendRequest (\r
885 IN HTTP_IO *HttpIo,\r
886 IN EFI_HTTP_REQUEST_DATA *Request,\r
887 IN UINTN HeaderCount,\r
888 IN EFI_HTTP_HEADER *Headers,\r
889 IN UINTN BodyLength,\r
890 IN VOID *Body\r
891 )\r
892{\r
893 EFI_STATUS Status;\r
894 EFI_HTTP_PROTOCOL *Http;\r
895\r
896 if (HttpIo == NULL || HttpIo->Http == NULL) {\r
897 return EFI_INVALID_PARAMETER;\r
898 }\r
899\r
900 HttpIo->ReqToken.Status = EFI_NOT_READY;\r
901 HttpIo->ReqToken.Message->Data.Request = Request;\r
902 HttpIo->ReqToken.Message->HeaderCount = HeaderCount;\r
903 HttpIo->ReqToken.Message->Headers = Headers;\r
904 HttpIo->ReqToken.Message->BodyLength = BodyLength;\r
905 HttpIo->ReqToken.Message->Body = Body;\r
906\r
907 //\r
908 // Queue the request token to HTTP instances.\r
909 //\r
910 Http = HttpIo->Http;\r
911 HttpIo->IsTxDone = FALSE;\r
912 Status = Http->Request (\r
913 Http,\r
914 &HttpIo->ReqToken\r
915 );\r
916 if (EFI_ERROR (Status)) {\r
917 return Status;\r
918 }\r
919\r
920 //\r
921 // Poll the network until transmit finish.\r
922 //\r
923 while (!HttpIo->IsTxDone) {\r
924 Http->Poll (Http);\r
925 }\r
926\r
927 return HttpIo->ReqToken.Status;\r
928}\r
929\r
930/**\r
931 Synchronously receive a HTTP RESPONSE message from the server.\r
932 \r
933 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
934 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).\r
935 FALSE to continue receive the previous response message.\r
936 @param[out] ResponseData Point to a wrapper of the received response data.\r
937 \r
ef422fc5 938 @retval EFI_SUCCESS The HTTP response is received.\r
d933e70a
JW
939 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
940 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
941 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
942 @retval Others Other errors as indicated.\r
943\r
944**/\r
945EFI_STATUS\r
946HttpIoRecvResponse (\r
947 IN HTTP_IO *HttpIo,\r
948 IN BOOLEAN RecvMsgHeader,\r
ef422fc5 949 OUT HTTP_IO_RESPONSE_DATA *ResponseData\r
d933e70a
JW
950 )\r
951{\r
952 EFI_STATUS Status;\r
953 EFI_HTTP_PROTOCOL *Http;\r
954\r
955 if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {\r
956 return EFI_INVALID_PARAMETER;\r
957 }\r
958\r
7570696c
JW
959 //\r
960 // Start the timer, and wait Timeout seconds to receive the header packet.\r
961 //\r
962 Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative, HTTP_BOOT_RESPONSE_TIMEOUT * TICKS_PER_MS);\r
963 if (EFI_ERROR (Status)) {\r
964 return Status;\r
965 }\r
966\r
d933e70a
JW
967 //\r
968 // Queue the response token to HTTP instances.\r
969 //\r
970 HttpIo->RspToken.Status = EFI_NOT_READY;\r
971 if (RecvMsgHeader) {\r
972 HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;\r
973 } else {\r
974 HttpIo->RspToken.Message->Data.Response = NULL;\r
975 }\r
976 HttpIo->RspToken.Message->HeaderCount = 0;\r
977 HttpIo->RspToken.Message->Headers = NULL;\r
978 HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;\r
979 HttpIo->RspToken.Message->Body = ResponseData->Body;\r
980\r
981 Http = HttpIo->Http;\r
982 HttpIo->IsRxDone = FALSE;\r
983 Status = Http->Response (\r
984 Http,\r
985 &HttpIo->RspToken\r
986 );\r
987 \r
988 if (EFI_ERROR (Status)) {\r
7570696c 989 gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);\r
d933e70a
JW
990 return Status;\r
991 }\r
992\r
993 //\r
62cae351 994 // Poll the network until receive finish.\r
d933e70a 995 //\r
7570696c 996 while (!HttpIo->IsRxDone && ((HttpIo->TimeoutEvent == NULL) || EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent)))) {\r
d933e70a
JW
997 Http->Poll (Http);\r
998 }\r
999\r
7570696c
JW
1000 gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);\r
1001\r
1002 if (!HttpIo->IsRxDone) {\r
1003 //\r
1004 // Timeout occurs, cancel the response token.\r
1005 //\r
1006 Http->Cancel (Http, &HttpIo->RspToken);\r
1007 \r
1008 Status = EFI_TIMEOUT;\r
1009 \r
1010 return Status;\r
1011 } else {\r
1012 HttpIo->IsRxDone = FALSE;\r
1013 }\r
1014\r
d933e70a
JW
1015 //\r
1016 // Store the received data into the wrapper.\r
1017 //\r
072289f4
ZL
1018 ResponseData->Status = HttpIo->RspToken.Status;\r
1019 ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;\r
1020 ResponseData->Headers = HttpIo->RspToken.Message->Headers;\r
1021 ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;\r
d933e70a
JW
1022\r
1023 return Status;\r
1024}\r
fa848a40 1025\r
221463c2
JW
1026/**\r
1027 This function checks the HTTP(S) URI scheme.\r
1028\r
1029 @param[in] Uri The pointer to the URI string.\r
1030 \r
1031 @retval EFI_SUCCESS The URI scheme is valid.\r
1032 @retval EFI_INVALID_PARAMETER The URI scheme is not HTTP or HTTPS.\r
1033 @retval EFI_ACCESS_DENIED HTTP is disabled and the URI is HTTP.\r
1034\r
1035**/\r
1036EFI_STATUS\r
1037HttpBootCheckUriScheme (\r
1038 IN CHAR8 *Uri\r
1039 )\r
1040{\r
1041 UINTN Index;\r
1042 EFI_STATUS Status;\r
1043\r
1044 Status = EFI_SUCCESS;\r
1045\r
1046 //\r
1047 // Convert the scheme to all lower case.\r
1048 //\r
1049 for (Index = 0; Index < AsciiStrLen (Uri); Index++) {\r
1050 if (Uri[Index] == ':') {\r
1051 break;\r
1052 }\r
1053 if (Uri[Index] >= 'A' && Uri[Index] <= 'Z') {\r
1054 Uri[Index] -= (CHAR8)('A' - 'a');\r
1055 }\r
1056 }\r
1057\r
1058 //\r
1059 // Return EFI_INVALID_PARAMETER if the URI is not HTTP or HTTPS.\r
1060 //\r
1061 if ((AsciiStrnCmp (Uri, "http://", 7) != 0) && (AsciiStrnCmp (Uri, "https://", 8) != 0)) {\r
1062 DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: Invalid Uri.\n"));\r
1063 return EFI_INVALID_PARAMETER;\r
1064 }\r
1065 \r
1066 //\r
1067 // HTTP is disabled, return EFI_ACCESS_DENIED if the URI is HTTP.\r
1068 //\r
1069 if (!PcdGetBool (PcdAllowHttpConnections) && (AsciiStrnCmp (Uri, "http://", 7) == 0)) {\r
1070 DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: HTTP is disabled.\n"));\r
1071 return EFI_ACCESS_DENIED;\r
1072 }\r
1073\r
1074 return Status;\r
1075}\r
1076\r
fa848a40
FS
1077/**\r
1078 Get the URI address string from the input device path.\r
1079\r
1080 Caller need to free the buffer in the UriAddress pointer.\r
1081 \r
1082 @param[in] FilePath Pointer to the device path which contains a URI device path node.\r
73617fa6 1083 @param[out] UriAddress The URI address string extract from the device path.\r
fa848a40
FS
1084 \r
1085 @retval EFI_SUCCESS The URI string is returned.\r
1086 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
1087\r
1088**/\r
1089EFI_STATUS\r
1090HttpBootParseFilePath (\r
1091 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1092 OUT CHAR8 **UriAddress\r
1093 )\r
1094{\r
1095 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1096 URI_DEVICE_PATH *UriDevicePath;\r
1097 CHAR8 *Uri;\r
1098 UINTN UriStrLength;\r
1099\r
1100 if (FilePath == NULL) {\r
1101 return EFI_INVALID_PARAMETER;\r
1102 }\r
1103\r
1104 *UriAddress = NULL;\r
1105\r
1106 //\r
1107 // Extract the URI address from the FilePath\r
1108 //\r
1109 TempDevicePath = FilePath;\r
1110 while (!IsDevicePathEnd (TempDevicePath)) {\r
1111 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1112 (DevicePathSubType (TempDevicePath) == MSG_URI_DP)) {\r
1113 UriDevicePath = (URI_DEVICE_PATH*) TempDevicePath;\r
1114 //\r
1115 // UEFI Spec doesn't require the URI to be a NULL-terminated string\r
1116 // So we allocate a new buffer and always append a '\0' to it.\r
1117 //\r
1118 UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
1119 if (UriStrLength == 0) {\r
1120 //\r
1121 // return a NULL UriAddress if it's a empty URI device path node.\r
1122 //\r
1123 break;\r
1124 }\r
1125 Uri = AllocatePool (UriStrLength + 1);\r
1126 if (Uri == NULL) {\r
1127 return EFI_OUT_OF_RESOURCES;\r
1128 }\r
1129 CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL));\r
1130 Uri[DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL)] = '\0';\r
1131\r
1132 *UriAddress = Uri;\r
1133 }\r
1134 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1135 }\r
1136\r
1137 return EFI_SUCCESS;\r
1138}\r
587d204c
FS
1139\r
1140/**\r
1141 This function returns the image type according to server replied HTTP message\r
1142 and also the image's URI info.\r
1143\r
1144 @param[in] Uri The pointer to the image's URI string.\r
1145 @param[in] UriParser URI Parse result returned by NetHttpParseUrl(). \r
1146 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
1147 @param[in] Headers Array containing list of HTTP headers.\r
1148 @param[out] ImageType The image type of the downloaded file.\r
1149 \r
1150 @retval EFI_SUCCESS The image type is returned in ImageType.\r
1151 @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL.\r
1152 @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL.\r
1153 @retval EFI_NOT_FOUND Failed to identify the image type.\r
1154 @retval Others Unexpect error happened.\r
1155\r
1156**/\r
1157EFI_STATUS\r
1158HttpBootCheckImageType (\r
1159 IN CHAR8 *Uri,\r
1160 IN VOID *UriParser,\r
1161 IN UINTN HeaderCount,\r
1162 IN EFI_HTTP_HEADER *Headers,\r
1163 OUT HTTP_BOOT_IMAGE_TYPE *ImageType\r
1164 )\r
1165{\r
1166 EFI_STATUS Status;\r
1167 EFI_HTTP_HEADER *Header;\r
1168 CHAR8 *FilePath;\r
1169 CHAR8 *FilePost;\r
1170\r
1171 if (Uri == NULL || UriParser == NULL || ImageType == NULL) {\r
1172 return EFI_INVALID_PARAMETER;\r
1173 }\r
1174\r
1175 if (HeaderCount != 0 && Headers == NULL) {\r
1176 return EFI_INVALID_PARAMETER;\r
1177 }\r
1178\r
1179 //\r
1180 // Determine the image type by the HTTP Content-Type header field first.\r
b173ad78
JW
1181 // "application/efi" -> EFI Image\r
1182 // "application/vnd.efi-iso" -> CD/DVD Image\r
1183 // "application/vnd.efi-img" -> Virtual Disk Image\r
587d204c
FS
1184 //\r
1185 Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE);\r
1186 if (Header != NULL) {\r
1187 if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) {\r
1188 *ImageType = ImageTypeEfi;\r
1189 return EFI_SUCCESS;\r
b173ad78
JW
1190 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) {\r
1191 *ImageType = ImageTypeVirtualCd;\r
1192 return EFI_SUCCESS;\r
1193 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) {\r
1194 *ImageType = ImageTypeVirtualDisk;\r
1195 return EFI_SUCCESS;\r
587d204c
FS
1196 }\r
1197 }\r
1198\r
1199 //\r
1200 // Determine the image type by file extension:\r
1201 // *.efi -> EFI Image\r
1202 // *.iso -> CD/DVD Image\r
1203 // *.img -> Virtual Disk Image\r
1204 //\r
1205 Status = HttpUrlGetPath (\r
1206 Uri,\r
1207 UriParser,\r
1208 &FilePath\r
1209 );\r
1210 if (EFI_ERROR (Status)) {\r
1211 return Status;\r
1212 }\r
1213\r
1214 FilePost = FilePath + AsciiStrLen (FilePath) - 4;\r
1215 if (AsciiStrCmp (FilePost, ".efi") == 0) {\r
1216 *ImageType = ImageTypeEfi;\r
1217 } else if (AsciiStrCmp (FilePost, ".iso") == 0) {\r
1218 *ImageType = ImageTypeVirtualCd;\r
1219 } else if (AsciiStrCmp (FilePost, ".img") == 0) {\r
1220 *ImageType = ImageTypeVirtualDisk;\r
1221 } else {\r
1222 *ImageType = ImageTypeMax;\r
1223 }\r
1224\r
1225 FreePool (FilePath);\r
1226\r
1227 return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
1228}\r
1229\r
1230/**\r
1231 This function register the RAM disk info to the system.\r
1232 \r
1233 @param[in] Private The pointer to the driver's private data.\r
1234 @param[in] BufferSize The size of Buffer in bytes.\r
1235 @param[in] Buffer The base address of the RAM disk.\r
1236 @param[in] ImageType The image type of the file in Buffer.\r
1237\r
1238 @retval EFI_SUCCESS The RAM disk has been registered.\r
1239 @retval EFI_NOT_FOUND No RAM disk protocol instances were found.\r
1240 @retval EFI_UNSUPPORTED The ImageType is not supported.\r
1241 @retval Others Unexpected error happened.\r
1242\r
1243**/\r
1244EFI_STATUS\r
1245HttpBootRegisterRamDisk (\r
1246 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
1247 IN UINTN BufferSize,\r
1248 IN VOID *Buffer,\r
1249 IN HTTP_BOOT_IMAGE_TYPE ImageType\r
1250 )\r
1251{\r
1252 EFI_RAM_DISK_PROTOCOL *RamDisk;\r
1253 EFI_STATUS Status;\r
1254 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1255 EFI_GUID *RamDiskType;\r
1256 \r
1257 ASSERT (Private != NULL);\r
1258 ASSERT (Buffer != NULL);\r
1259 ASSERT (BufferSize != 0);\r
1260\r
1261 Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID**) &RamDisk);\r
1262 if (EFI_ERROR (Status)) {\r
1263 DEBUG ((EFI_D_ERROR, "HTTP Boot: Couldn't find the RAM Disk protocol - %r\n", Status));\r
1264 return Status;\r
1265 }\r
1266\r
1267 if (ImageType == ImageTypeVirtualCd) {\r
1268 RamDiskType = &gEfiVirtualCdGuid;\r
1269 } else if (ImageType == ImageTypeVirtualDisk) {\r
1270 RamDiskType = &gEfiVirtualDiskGuid;\r
1271 } else {\r
1272 return EFI_UNSUPPORTED;\r
1273 }\r
1274 \r
1275 Status = RamDisk->Register (\r
1276 (UINTN)Buffer,\r
1277 (UINT64)BufferSize,\r
1278 RamDiskType,\r
1279 Private->UsingIpv6 ? Private->Ip6Nic->DevicePath : Private->Ip4Nic->DevicePath,\r
1280 &DevicePath\r
1281 );\r
1282 if (EFI_ERROR (Status)) {\r
1283 DEBUG ((EFI_D_ERROR, "HTTP Boot: Failed to register RAM Disk - %r\n", Status));\r
1284 }\r
1285\r
1286 return Status;\r
1287}\r
1288\r