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