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