1 /** @file
2   Miscellaneous routines for HttpDxe driver.
3 
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "HttpDriver.h"
17 
18 /**
19   The common notify function used in HTTP driver.
20 
21   @param[in]  Event   The event signaled.
22   @param[in]  Context The context.
23 
24 **/
25 VOID
26 EFIAPI
HttpCommonNotify(IN EFI_EVENT Event,IN VOID * Context)27 HttpCommonNotify (
28   IN EFI_EVENT  Event,
29   IN VOID       *Context
30   )
31 {
32   if ((Event == NULL) || (Context == NULL)) {
33     return ;
34   }
35 
36   *((BOOLEAN *) Context) = TRUE;
37 }
38 
39 /**
40   The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().
41 
42   @param[in]  Context The context.
43 
44 **/
45 VOID
46 EFIAPI
HttpTcpTransmitNotifyDpc(IN VOID * Context)47 HttpTcpTransmitNotifyDpc (
48   IN VOID       *Context
49   )
50 {
51   HTTP_TOKEN_WRAP          *Wrap;
52   HTTP_PROTOCOL            *HttpInstance;
53 
54   if (Context == NULL) {
55     return ;
56   }
57 
58   Wrap         = (HTTP_TOKEN_WRAP *) Context;
59   HttpInstance = Wrap->HttpInstance;
60 
61   if (!HttpInstance->LocalAddressIsIPv6) {
62       Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status;
63       gBS->SignalEvent (Wrap->HttpToken->Event);
64 
65       //
66       // Free resources.
67       //
68       if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
69         FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
70       }
71 
72       if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {
73         gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
74       }
75 
76   } else {
77     Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status;
78     gBS->SignalEvent (Wrap->HttpToken->Event);
79 
80     //
81     // Free resources.
82     //
83     if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
84       FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
85     }
86 
87     if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {
88       gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);
89     }
90   }
91 
92 
93   Wrap->TcpWrap.IsTxDone = TRUE;
94 
95   //
96   // Check pending TxTokens and sent out.
97   //
98   NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
99 
100 }
101 
102 /**
103   Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
104 
105   @param  Event                 The receive event delivered to TCP for transmit.
106   @param  Context               Context for the callback.
107 
108 **/
109 VOID
110 EFIAPI
HttpTcpTransmitNotify(IN EFI_EVENT Event,IN VOID * Context)111 HttpTcpTransmitNotify (
112   IN EFI_EVENT                Event,
113   IN VOID                     *Context
114   )
115 {
116   //
117   // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
118   //
119   QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);
120 }
121 
122 /**
123   The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().
124 
125   @param[in]  Context The context.
126 
127 **/
128 VOID
129 EFIAPI
HttpTcpReceiveNotifyDpc(IN VOID * Context)130 HttpTcpReceiveNotifyDpc (
131   IN VOID       *Context
132   )
133 {
134   HTTP_TOKEN_WRAP          *Wrap;
135   NET_MAP_ITEM             *Item;
136   UINTN                    Length;
137   EFI_STATUS               Status;
138   HTTP_PROTOCOL            *HttpInstance;
139   BOOLEAN                  UsingIpv6;
140 
141   if (Context == NULL) {
142     return ;
143   }
144 
145   Wrap = (HTTP_TOKEN_WRAP *) Context;
146   HttpInstance = Wrap->HttpInstance;
147   UsingIpv6    = HttpInstance->LocalAddressIsIPv6;
148 
149   if (UsingIpv6) {
150     gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
151     Wrap->TcpWrap.Rx6Token.CompletionToken.Event = NULL;
152 
153     if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) {
154       DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx6Token.CompletionToken.Status));
155       Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
156       gBS->SignalEvent (Wrap->HttpToken->Event);
157 
158       Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
159       if (Item != NULL) {
160         NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
161       }
162 
163       FreePool (Wrap);
164       Wrap = NULL;
165 
166       return ;
167     }
168 
169   } else {
170     gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
171     Wrap->TcpWrap.Rx4Token.CompletionToken.Event = NULL;
172 
173     if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) {
174       DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx4Token.CompletionToken.Status));
175       Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
176       gBS->SignalEvent (Wrap->HttpToken->Event);
177 
178       Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
179       if (Item != NULL) {
180         NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
181       }
182 
183       FreePool (Wrap);
184       Wrap = NULL;
185 
186       return ;
187     }
188   }
189 
190   //
191   // Check whether we receive a complete HTTP message.
192   //
193   ASSERT (HttpInstance->MsgParser != NULL);
194   if (UsingIpv6) {
195     Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;
196   } else {
197     Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;
198   }
199 
200   Status = HttpParseMessageBody (
201              HttpInstance->MsgParser,
202              Length,
203              Wrap->HttpToken->Message->Body
204              );
205   if (EFI_ERROR (Status)) {
206     return ;
207   }
208 
209   if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
210     //
211     // Free the MsgParse since we already have a full HTTP message.
212     //
213     HttpFreeMsgParser (HttpInstance->MsgParser);
214     HttpInstance->MsgParser = NULL;
215   }
216 
217   Wrap->HttpToken->Message->BodyLength = Length;
218   ASSERT (HttpInstance->CacheBody == NULL);
219   //
220   // We receive part of header of next HTTP msg.
221   //
222   if (HttpInstance->NextMsg != NULL) {
223     Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg -
224                                            (CHAR8 *) Wrap->HttpToken->Message->Body;
225     HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;
226     if (HttpInstance->CacheLen != 0) {
227       HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
228       if (HttpInstance->CacheBody == NULL) {
229         return ;
230       }
231       CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
232       HttpInstance->NextMsg = HttpInstance->CacheBody;
233       HttpInstance->CacheOffset = 0;
234     }
235   }
236 
237   Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
238   if (Item != NULL) {
239     NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
240   }
241 
242 
243   Wrap->TcpWrap.IsRxDone = TRUE;
244   if (UsingIpv6) {
245     Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
246   } else {
247     Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
248   }
249 
250 
251   gBS->SignalEvent (Wrap->HttpToken->Event);
252 
253   //
254   // Check pending RxTokens and receive the HTTP message.
255   //
256   NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
257 
258   FreePool (Wrap);
259   Wrap = NULL;
260 }
261 
262 /**
263   Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
264 
265   @param  Event                 The receive event delivered to TCP for receive.
266   @param  Context               Context for the callback.
267 
268 **/
269 VOID
270 EFIAPI
HttpTcpReceiveNotify(IN EFI_EVENT Event,IN VOID * Context)271 HttpTcpReceiveNotify (
272   IN EFI_EVENT                Event,
273   IN VOID                     *Context
274   )
275 {
276   //
277   // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
278   //
279   QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
280 }
281 
282 /**
283   Create events for the TCP connection token and TCP close token.
284 
285   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
286 
287   @retval EFI_SUCCESS            The events are created successfully.
288   @retval others                 Other error as indicated.
289 
290 **/
291 EFI_STATUS
HttpCreateTcpConnCloseEvent(IN HTTP_PROTOCOL * HttpInstance)292 HttpCreateTcpConnCloseEvent (
293   IN  HTTP_PROTOCOL        *HttpInstance
294   )
295 {
296   EFI_STATUS               Status;
297 
298   if (!HttpInstance->LocalAddressIsIPv6) {
299     //
300     // Create events for variuos asynchronous operations.
301     //
302     Status = gBS->CreateEvent (
303                     EVT_NOTIFY_SIGNAL,
304                     TPL_NOTIFY,
305                     HttpCommonNotify,
306                     &HttpInstance->IsTcp4ConnDone,
307                     &HttpInstance->Tcp4ConnToken.CompletionToken.Event
308                     );
309     if (EFI_ERROR (Status)) {
310       goto ERROR;
311     }
312 
313     //
314     // Initialize Tcp4CloseToken
315     //
316     Status = gBS->CreateEvent (
317                     EVT_NOTIFY_SIGNAL,
318                     TPL_NOTIFY,
319                     HttpCommonNotify,
320                     &HttpInstance->IsTcp4CloseDone,
321                     &HttpInstance->Tcp4CloseToken.CompletionToken.Event
322                     );
323     if (EFI_ERROR (Status)) {
324       goto ERROR;
325     }
326 
327   } else {
328     //
329     // Create events for variuos asynchronous operations.
330     //
331     Status = gBS->CreateEvent (
332                     EVT_NOTIFY_SIGNAL,
333                     TPL_NOTIFY,
334                     HttpCommonNotify,
335                     &HttpInstance->IsTcp6ConnDone,
336                     &HttpInstance->Tcp6ConnToken.CompletionToken.Event
337                     );
338     if (EFI_ERROR (Status)) {
339       goto ERROR;
340     }
341 
342     //
343     // Initialize Tcp6CloseToken
344     //
345     Status = gBS->CreateEvent (
346                     EVT_NOTIFY_SIGNAL,
347                     TPL_NOTIFY,
348                     HttpCommonNotify,
349                     &HttpInstance->IsTcp6CloseDone,
350                     &HttpInstance->Tcp6CloseToken.CompletionToken.Event
351                     );
352     if (EFI_ERROR (Status)) {
353       goto ERROR;
354     }
355   }
356 
357   return EFI_SUCCESS;
358 
359 ERROR:
360   //
361   // Error handling
362   //
363   HttpCloseTcpConnCloseEvent (HttpInstance);
364 
365   return Status;
366 }
367 
368 
369 /**
370   Close events in the TCP connection token and TCP close token.
371 
372   @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.
373 
374 **/
375 VOID
HttpCloseTcpConnCloseEvent(IN HTTP_PROTOCOL * HttpInstance)376 HttpCloseTcpConnCloseEvent (
377   IN  HTTP_PROTOCOL        *HttpInstance
378   )
379 {
380   ASSERT (HttpInstance != NULL);
381 
382   if (HttpInstance->LocalAddressIsIPv6) {
383     if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {
384       gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);
385       HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;
386     }
387 
388     if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {
389       gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event);
390       HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;
391     }
392 
393   } else {
394     if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {
395       gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);
396       HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;
397     }
398 
399     if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {
400       gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event);
401       HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;
402     }
403   }
404 
405 }
406 
407 /**
408   Create event for the TCP transmit token.
409 
410   @param[in]  Wrap               Point to HTTP token's wrap data.
411 
412   @retval EFI_SUCCESS            The events is created successfully.
413   @retval others                 Other error as indicated.
414 
415 **/
416 EFI_STATUS
HttpCreateTcpTxEvent(IN HTTP_TOKEN_WRAP * Wrap)417 HttpCreateTcpTxEvent (
418   IN  HTTP_TOKEN_WRAP      *Wrap
419   )
420 {
421   EFI_STATUS               Status;
422   HTTP_PROTOCOL            *HttpInstance;
423   HTTP_TCP_TOKEN_WRAP      *TcpWrap;
424 
425   HttpInstance = Wrap->HttpInstance;
426   TcpWrap      = &Wrap->TcpWrap;
427 
428   if (!HttpInstance->LocalAddressIsIPv6) {
429     Status = gBS->CreateEvent (
430                     EVT_NOTIFY_SIGNAL,
431                     TPL_NOTIFY,
432                     HttpTcpTransmitNotify,
433                     Wrap,
434                     &TcpWrap->Tx4Token.CompletionToken.Event
435                     );
436     if (EFI_ERROR (Status)) {
437       return Status;
438     }
439 
440     TcpWrap->Tx4Data.Push = TRUE;
441     TcpWrap->Tx4Data.Urgent = FALSE;
442     TcpWrap->Tx4Data.FragmentCount = 1;
443     TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data;
444     TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY;
445 
446   } else {
447     Status = gBS->CreateEvent (
448                     EVT_NOTIFY_SIGNAL,
449                     TPL_NOTIFY,
450                     HttpTcpTransmitNotify,
451                     Wrap,
452                     &TcpWrap->Tx6Token.CompletionToken.Event
453                     );
454     if (EFI_ERROR (Status)) {
455       return Status;
456     }
457 
458     TcpWrap->Tx6Data.Push   = TRUE;
459     TcpWrap->Tx6Data.Urgent = FALSE;
460     TcpWrap->Tx6Data.FragmentCount  = 1;
461     TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data;
462     TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY;
463 
464   }
465 
466   return EFI_SUCCESS;
467 }
468 
469 /**
470   Create event for the TCP receive token which is used to receive HTTP header.
471 
472   @param[in]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
473 
474   @retval EFI_SUCCESS            The events is created successfully.
475   @retval others                 Other error as indicated.
476 
477 **/
478 EFI_STATUS
HttpCreateTcpRxEventForHeader(IN HTTP_PROTOCOL * HttpInstance)479 HttpCreateTcpRxEventForHeader (
480   IN  HTTP_PROTOCOL        *HttpInstance
481   )
482 {
483   EFI_STATUS               Status;
484 
485   if (!HttpInstance->LocalAddressIsIPv6) {
486     Status = gBS->CreateEvent (
487                     EVT_NOTIFY_SIGNAL,
488                     TPL_NOTIFY,
489                     HttpCommonNotify,
490                     &HttpInstance->IsRxDone,
491                     &HttpInstance->Rx4Token.CompletionToken.Event
492                     );
493     if (EFI_ERROR (Status)) {
494       return Status;
495     }
496 
497     HttpInstance->Rx4Data.FragmentCount = 1;
498     HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;
499     HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
500 
501   } else {
502     Status = gBS->CreateEvent (
503                     EVT_NOTIFY_SIGNAL,
504                     TPL_NOTIFY,
505                     HttpCommonNotify,
506                     &HttpInstance->IsRxDone,
507                     &HttpInstance->Rx6Token.CompletionToken.Event
508                     );
509     if (EFI_ERROR (Status)) {
510       return Status;
511     }
512 
513     HttpInstance->Rx6Data.FragmentCount  =1;
514     HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;
515     HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
516 
517   }
518 
519 
520   return EFI_SUCCESS;
521 }
522 
523 /**
524   Create event for the TCP receive token which is used to receive HTTP body.
525 
526   @param[in]  Wrap               Point to HTTP token's wrap data.
527 
528   @retval EFI_SUCCESS            The events is created successfully.
529   @retval others                 Other error as indicated.
530 
531 **/
532 EFI_STATUS
HttpCreateTcpRxEvent(IN HTTP_TOKEN_WRAP * Wrap)533 HttpCreateTcpRxEvent (
534   IN  HTTP_TOKEN_WRAP      *Wrap
535   )
536 {
537   EFI_STATUS               Status;
538   HTTP_PROTOCOL            *HttpInstance;
539   HTTP_TCP_TOKEN_WRAP      *TcpWrap;
540 
541   HttpInstance = Wrap->HttpInstance;
542   TcpWrap      = &Wrap->TcpWrap;
543   if (!HttpInstance->LocalAddressIsIPv6) {
544     Status = gBS->CreateEvent (
545                     EVT_NOTIFY_SIGNAL,
546                     TPL_NOTIFY,
547                     HttpTcpReceiveNotify,
548                     Wrap,
549                     &TcpWrap->Rx4Token.CompletionToken.Event
550                     );
551     if (EFI_ERROR (Status)) {
552       return Status;
553     }
554 
555     TcpWrap->Rx4Data.FragmentCount = 1;
556     TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;
557     TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
558 
559   } else {
560     Status = gBS->CreateEvent (
561                     EVT_NOTIFY_SIGNAL,
562                     TPL_NOTIFY,
563                     HttpTcpReceiveNotify,
564                     Wrap,
565                     &TcpWrap->Rx6Token.CompletionToken.Event
566                     );
567     if (EFI_ERROR (Status)) {
568       return Status;
569     }
570 
571     TcpWrap->Rx6Data.FragmentCount = 1;
572     TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;
573     TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
574   }
575 
576   return EFI_SUCCESS;
577 }
578 
579 /**
580   Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
581 
582   @param[in]  Wrap               Pointer to HTTP token's wrap data.
583 
584 **/
585 VOID
HttpCloseTcpRxEvent(IN HTTP_TOKEN_WRAP * Wrap)586 HttpCloseTcpRxEvent (
587   IN  HTTP_TOKEN_WRAP      *Wrap
588   )
589 {
590   HTTP_PROTOCOL            *HttpInstance;
591 
592   ASSERT (Wrap != NULL);
593   HttpInstance   = Wrap->HttpInstance;
594 
595   if (HttpInstance->LocalAddressIsIPv6) {
596     if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
597       gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
598     }
599 
600     if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {
601       gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);
602       HttpInstance->Rx6Token.CompletionToken.Event = NULL;
603     }
604   } else {
605     if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
606       gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
607     }
608 
609     if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {
610       gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);
611       HttpInstance->Rx4Token.CompletionToken.Event = NULL;
612     }
613   }
614 }
615 
616 /**
617   Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
618 
619   @param[in, out]  HttpInstance         Pointer to HTTP_PROTOCOL structure.
620   @param[in]       IpVersion            Indicate us TCP4 protocol or TCP6 protocol.
621 
622   @retval EFI_SUCCESS       HTTP_PROTOCOL structure is initialized successfully.
623   @retval Others            Other error as indicated.
624 
625 **/
626 EFI_STATUS
HttpInitProtocol(IN OUT HTTP_PROTOCOL * HttpInstance,IN BOOLEAN IpVersion)627 HttpInitProtocol (
628   IN OUT HTTP_PROTOCOL           *HttpInstance,
629   IN     BOOLEAN                 IpVersion
630   )
631 {
632   EFI_STATUS                     Status;
633   VOID                           *Interface;
634   BOOLEAN                        UsingIpv6;
635 
636   ASSERT (HttpInstance != NULL);
637   UsingIpv6 = IpVersion;
638 
639   if (!UsingIpv6) {
640     //
641     // Create TCP4 child.
642     //
643     Status = NetLibCreateServiceChild (
644                HttpInstance->Service->ControllerHandle,
645                HttpInstance->Service->ImageHandle,
646                &gEfiTcp4ServiceBindingProtocolGuid,
647                &HttpInstance->Tcp4ChildHandle
648                );
649 
650     if (EFI_ERROR (Status)) {
651       goto ON_ERROR;
652     }
653 
654     Status = gBS->OpenProtocol (
655                     HttpInstance->Tcp4ChildHandle,
656                     &gEfiTcp4ProtocolGuid,
657                     (VOID **) &Interface,
658                     HttpInstance->Service->ImageHandle,
659                     HttpInstance->Service->ControllerHandle,
660                     EFI_OPEN_PROTOCOL_BY_DRIVER
661                     );
662 
663     if (EFI_ERROR (Status)) {
664       goto ON_ERROR;
665     }
666 
667     Status = gBS->OpenProtocol (
668                     HttpInstance->Tcp4ChildHandle,
669                     &gEfiTcp4ProtocolGuid,
670                     (VOID **) &HttpInstance->Tcp4,
671                     HttpInstance->Service->ImageHandle,
672                     HttpInstance->Handle,
673                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
674                     );
675     if (EFI_ERROR(Status)) {
676       goto ON_ERROR;
677     }
678 
679     Status = gBS->OpenProtocol (
680                     HttpInstance->Service->Tcp4ChildHandle,
681                     &gEfiTcp4ProtocolGuid,
682                     (VOID **) &Interface,
683                     HttpInstance->Service->ImageHandle,
684                     HttpInstance->Handle,
685                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
686                     );
687     if (EFI_ERROR(Status)) {
688       goto ON_ERROR;
689     }
690   } else {
691     //
692     // Create TCP6 Child.
693     //
694     Status = NetLibCreateServiceChild (
695                HttpInstance->Service->ControllerHandle,
696                HttpInstance->Service->ImageHandle,
697                &gEfiTcp6ServiceBindingProtocolGuid,
698                &HttpInstance->Tcp6ChildHandle
699                );
700 
701     if (EFI_ERROR (Status)) {
702       goto ON_ERROR;
703     }
704 
705     Status = gBS->OpenProtocol (
706                     HttpInstance->Tcp6ChildHandle,
707                     &gEfiTcp6ProtocolGuid,
708                     (VOID **) &Interface,
709                     HttpInstance->Service->ImageHandle,
710                     HttpInstance->Service->ControllerHandle,
711                     EFI_OPEN_PROTOCOL_BY_DRIVER
712                     );
713 
714     if (EFI_ERROR (Status)) {
715       goto ON_ERROR;
716     }
717 
718     Status = gBS->OpenProtocol (
719                     HttpInstance->Tcp6ChildHandle,
720                     &gEfiTcp6ProtocolGuid,
721                     (VOID **) &HttpInstance->Tcp6,
722                     HttpInstance->Service->ImageHandle,
723                     HttpInstance->Handle,
724                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
725                     );
726 
727     if (EFI_ERROR(Status)) {
728       goto ON_ERROR;
729     }
730 
731     Status = gBS->OpenProtocol (
732                     HttpInstance->Service->Tcp6ChildHandle,
733                     &gEfiTcp6ProtocolGuid,
734                     (VOID **) &Interface,
735                     HttpInstance->Service->ImageHandle,
736                     HttpInstance->Handle,
737                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
738                     );
739 
740     if (EFI_ERROR(Status)) {
741       goto ON_ERROR;
742     }
743   }
744 
745   HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
746   if (HttpInstance->Url == NULL) {
747     Status = EFI_OUT_OF_RESOURCES;
748     goto ON_ERROR;
749   }
750 
751   return EFI_SUCCESS;
752 
753 ON_ERROR:
754 
755   if (HttpInstance->Tcp4ChildHandle != NULL) {
756     gBS->CloseProtocol (
757            HttpInstance->Tcp4ChildHandle,
758            &gEfiTcp4ProtocolGuid,
759            HttpInstance->Service->ImageHandle,
760            HttpInstance->Service->ControllerHandle
761            );
762 
763     gBS->CloseProtocol (
764            HttpInstance->Tcp4ChildHandle,
765            &gEfiTcp4ProtocolGuid,
766            HttpInstance->Service->ImageHandle,
767            HttpInstance->Handle
768            );
769 
770     NetLibDestroyServiceChild (
771       HttpInstance->Service->ControllerHandle,
772       HttpInstance->Service->ImageHandle,
773       &gEfiTcp4ServiceBindingProtocolGuid,
774       HttpInstance->Tcp4ChildHandle
775       );
776   }
777 
778   if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
779     gBS->CloseProtocol (
780            HttpInstance->Service->Tcp4ChildHandle,
781            &gEfiTcp4ProtocolGuid,
782            HttpInstance->Service->ImageHandle,
783            HttpInstance->Handle
784            );
785   }
786 
787   if (HttpInstance->Tcp6ChildHandle != NULL) {
788     gBS->CloseProtocol (
789            HttpInstance->Tcp6ChildHandle,
790            &gEfiTcp6ProtocolGuid,
791            HttpInstance->Service->ImageHandle,
792            HttpInstance->Service->ControllerHandle
793            );
794 
795     gBS->CloseProtocol (
796            HttpInstance->Tcp6ChildHandle,
797            &gEfiTcp6ProtocolGuid,
798            HttpInstance->Service->ImageHandle,
799            HttpInstance->Handle
800            );
801 
802     NetLibDestroyServiceChild (
803       HttpInstance->Service->ControllerHandle,
804       HttpInstance->Service->ImageHandle,
805       &gEfiTcp6ServiceBindingProtocolGuid,
806       HttpInstance->Tcp6ChildHandle
807       );
808   }
809 
810   if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
811     gBS->CloseProtocol (
812            HttpInstance->Service->Tcp6ChildHandle,
813            &gEfiTcp6ProtocolGuid,
814            HttpInstance->Service->ImageHandle,
815            HttpInstance->Handle
816            );
817   }
818 
819   return EFI_UNSUPPORTED;
820 
821 }
822 
823 /**
824   Clean up the HTTP child, release all the resources used by it.
825 
826   @param[in]  HttpInstance       The HTTP child to clean up.
827 
828 **/
829 VOID
HttpCleanProtocol(IN HTTP_PROTOCOL * HttpInstance)830 HttpCleanProtocol (
831   IN  HTTP_PROTOCOL          *HttpInstance
832   )
833 {
834   HttpCloseConnection (HttpInstance);
835 
836   HttpCloseTcpConnCloseEvent (HttpInstance);
837 
838   if (HttpInstance->TimeoutEvent != NULL) {
839     gBS->CloseEvent (HttpInstance->TimeoutEvent);
840     HttpInstance->TimeoutEvent = NULL;
841   }
842 
843   if (HttpInstance->CacheBody != NULL) {
844     FreePool (HttpInstance->CacheBody);
845     HttpInstance->CacheBody = NULL;
846     HttpInstance->NextMsg   = NULL;
847   }
848 
849   if (HttpInstance->RemoteHost != NULL) {
850     FreePool (HttpInstance->RemoteHost);
851     HttpInstance->RemoteHost = NULL;
852   }
853 
854   if (HttpInstance->MsgParser != NULL) {
855     HttpFreeMsgParser (HttpInstance->MsgParser);
856     HttpInstance->MsgParser = NULL;
857   }
858 
859   if (HttpInstance->Url != NULL) {
860     FreePool (HttpInstance->Url);
861     HttpInstance->Url = NULL;
862   }
863 
864   NetMapClean (&HttpInstance->TxTokens);
865   NetMapClean (&HttpInstance->RxTokens);
866 
867   if (HttpInstance->Tcp4ChildHandle != NULL) {
868     gBS->CloseProtocol (
869            HttpInstance->Tcp4ChildHandle,
870            &gEfiTcp4ProtocolGuid,
871            HttpInstance->Service->ImageHandle,
872            HttpInstance->Service->ControllerHandle
873            );
874 
875     gBS->CloseProtocol (
876            HttpInstance->Tcp4ChildHandle,
877            &gEfiTcp4ProtocolGuid,
878            HttpInstance->Service->ImageHandle,
879            HttpInstance->Handle
880            );
881 
882     NetLibDestroyServiceChild (
883       HttpInstance->Service->ControllerHandle,
884       HttpInstance->Service->ImageHandle,
885       &gEfiTcp4ServiceBindingProtocolGuid,
886       HttpInstance->Tcp4ChildHandle
887       );
888   }
889 
890   if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
891     gBS->CloseProtocol (
892            HttpInstance->Service->Tcp4ChildHandle,
893            &gEfiTcp4ProtocolGuid,
894            HttpInstance->Service->ImageHandle,
895            HttpInstance->Handle
896            );
897   }
898 
899   if (HttpInstance->Tcp6ChildHandle != NULL) {
900     gBS->CloseProtocol (
901            HttpInstance->Tcp6ChildHandle,
902            &gEfiTcp6ProtocolGuid,
903            HttpInstance->Service->ImageHandle,
904            HttpInstance->Service->ControllerHandle
905            );
906 
907     gBS->CloseProtocol (
908            HttpInstance->Tcp6ChildHandle,
909            &gEfiTcp6ProtocolGuid,
910            HttpInstance->Service->ImageHandle,
911            HttpInstance->Handle
912            );
913 
914     NetLibDestroyServiceChild (
915       HttpInstance->Service->ControllerHandle,
916       HttpInstance->Service->ImageHandle,
917       &gEfiTcp6ServiceBindingProtocolGuid,
918       HttpInstance->Tcp6ChildHandle
919       );
920   }
921 
922   if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
923     gBS->CloseProtocol (
924            HttpInstance->Service->Tcp6ChildHandle,
925            &gEfiTcp6ProtocolGuid,
926            HttpInstance->Service->ImageHandle,
927            HttpInstance->Handle
928            );
929   }
930 
931   TlsCloseTxRxEvent (HttpInstance);
932 }
933 
934 /**
935   Establish TCP connection with HTTP server.
936 
937   @param[in]  HttpInstance       The HTTP instance private data.
938 
939   @retval EFI_SUCCESS            The TCP connection is established.
940   @retval Others                 Other error as indicated.
941 
942 **/
943 EFI_STATUS
HttpCreateConnection(IN HTTP_PROTOCOL * HttpInstance)944 HttpCreateConnection (
945   IN  HTTP_PROTOCOL        *HttpInstance
946   )
947 {
948   EFI_STATUS                    Status;
949 
950   //
951   // Connect to Http server
952   //
953   if (!HttpInstance->LocalAddressIsIPv6) {
954     HttpInstance->IsTcp4ConnDone = FALSE;
955     HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;
956     Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);
957     if (EFI_ERROR (Status)) {
958       DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
959       return Status;
960     }
961 
962     while (!HttpInstance->IsTcp4ConnDone) {
963       HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
964     }
965 
966     Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
967 
968   } else {
969     HttpInstance->IsTcp6ConnDone = FALSE;
970     HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
971     Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
972     if (EFI_ERROR (Status)) {
973       DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
974       return Status;
975     }
976 
977     while(!HttpInstance->IsTcp6ConnDone) {
978       HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
979     }
980 
981     Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
982   }
983 
984   if (!EFI_ERROR (Status)) {
985     HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
986   }
987 
988   return Status;
989 }
990 
991 /**
992   Close existing TCP connection.
993 
994   @param[in]  HttpInstance       The HTTP instance private data.
995 
996   @retval EFI_SUCCESS            The TCP connection is closed.
997   @retval Others                 Other error as indicated.
998 
999 **/
1000 EFI_STATUS
HttpCloseConnection(IN HTTP_PROTOCOL * HttpInstance)1001 HttpCloseConnection (
1002   IN  HTTP_PROTOCOL        *HttpInstance
1003   )
1004 {
1005   EFI_STATUS                Status;
1006 
1007   if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
1008 
1009     if (HttpInstance->LocalAddressIsIPv6) {
1010       HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
1011       HttpInstance->IsTcp6CloseDone             = FALSE;
1012       Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
1013       if (EFI_ERROR (Status)) {
1014         return Status;
1015       }
1016 
1017       while (!HttpInstance->IsTcp6CloseDone) {
1018         HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
1019       }
1020 
1021     } else {
1022       HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
1023       HttpInstance->IsTcp4CloseDone             = FALSE;
1024       Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
1025       if (EFI_ERROR (Status)) {
1026         return Status;
1027       }
1028 
1029       while (!HttpInstance->IsTcp4CloseDone) {
1030         HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
1031       }
1032     }
1033 
1034   }
1035 
1036   HttpInstance->State = HTTP_STATE_TCP_CLOSED;
1037   return EFI_SUCCESS;
1038 }
1039 
1040 /**
1041   Configure TCP4 protocol child.
1042 
1043   @param[in]  HttpInstance       The HTTP instance private data.
1044   @param[in]  Wrap               The HTTP token's wrap data.
1045 
1046   @retval EFI_SUCCESS            The TCP4 protocol child is configured.
1047   @retval Others                 Other error as indicated.
1048 
1049 **/
1050 EFI_STATUS
HttpConfigureTcp4(IN HTTP_PROTOCOL * HttpInstance,IN HTTP_TOKEN_WRAP * Wrap)1051 HttpConfigureTcp4 (
1052   IN  HTTP_PROTOCOL        *HttpInstance,
1053   IN  HTTP_TOKEN_WRAP      *Wrap
1054   )
1055 {
1056   EFI_STATUS                 Status;
1057   EFI_TCP4_CONFIG_DATA       *Tcp4CfgData;
1058   EFI_TCP4_ACCESS_POINT      *Tcp4AP;
1059   EFI_TCP4_OPTION            *Tcp4Option;
1060 
1061   ASSERT (HttpInstance != NULL);
1062 
1063 
1064   Tcp4CfgData = &HttpInstance->Tcp4CfgData;
1065   ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
1066 
1067   Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
1068   Tcp4CfgData->TimeToLive    = HTTP_TTL_DEAULT;
1069   Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
1070 
1071   Tcp4AP = &Tcp4CfgData->AccessPoint;
1072   Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
1073   if (!Tcp4AP->UseDefaultAddress) {
1074     IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
1075     IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
1076   }
1077 
1078   Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
1079   Tcp4AP->RemotePort  = HttpInstance->RemotePort;
1080   Tcp4AP->ActiveFlag  = TRUE;
1081   IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
1082 
1083   Tcp4Option = Tcp4CfgData->ControlOption;
1084   Tcp4Option->ReceiveBufferSize      = HTTP_BUFFER_SIZE_DEAULT;
1085   Tcp4Option->SendBufferSize         = HTTP_BUFFER_SIZE_DEAULT;
1086   Tcp4Option->MaxSynBackLog          = HTTP_MAX_SYN_BACK_LOG;
1087   Tcp4Option->ConnectionTimeout      = HTTP_CONNECTION_TIMEOUT;
1088   Tcp4Option->DataRetries            = HTTP_DATA_RETRIES;
1089   Tcp4Option->FinTimeout             = HTTP_FIN_TIMEOUT;
1090   Tcp4Option->KeepAliveProbes        = HTTP_KEEP_ALIVE_PROBES;
1091   Tcp4Option->KeepAliveTime          = HTTP_KEEP_ALIVE_TIME;
1092   Tcp4Option->KeepAliveInterval      = HTTP_KEEP_ALIVE_INTERVAL;
1093   Tcp4Option->EnableNagle            = TRUE;
1094   Tcp4CfgData->ControlOption         = Tcp4Option;
1095 
1096   Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
1097   if (EFI_ERROR (Status)) {
1098     DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
1099     return Status;
1100   }
1101 
1102   Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1103   if (EFI_ERROR (Status)) {
1104     return Status;
1105   }
1106 
1107   Status = HttpCreateTcpTxEvent (Wrap);
1108   if (EFI_ERROR (Status)) {
1109     return Status;
1110   }
1111 
1112   HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1113 
1114   return EFI_SUCCESS;
1115 }
1116 
1117 /**
1118   Configure TCP6 protocol child.
1119 
1120   @param[in]  HttpInstance       The HTTP instance private data.
1121   @param[in]  Wrap               The HTTP token's wrap data.
1122 
1123   @retval EFI_SUCCESS            The TCP6 protocol child is configured.
1124   @retval Others                 Other error as indicated.
1125 
1126 **/
1127 EFI_STATUS
HttpConfigureTcp6(IN HTTP_PROTOCOL * HttpInstance,IN HTTP_TOKEN_WRAP * Wrap)1128 HttpConfigureTcp6 (
1129   IN  HTTP_PROTOCOL        *HttpInstance,
1130   IN  HTTP_TOKEN_WRAP      *Wrap
1131   )
1132 {
1133   EFI_STATUS               Status;
1134   EFI_TCP6_CONFIG_DATA     *Tcp6CfgData;
1135   EFI_TCP6_ACCESS_POINT    *Tcp6Ap;
1136   EFI_TCP6_OPTION          *Tcp6Option;
1137 
1138   ASSERT (HttpInstance != NULL);
1139 
1140   Tcp6CfgData = &HttpInstance->Tcp6CfgData;
1141   ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
1142 
1143   Tcp6CfgData->TrafficClass  = 0;
1144   Tcp6CfgData->HopLimit      = 255;
1145   Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
1146 
1147   Tcp6Ap  = &Tcp6CfgData->AccessPoint;
1148   Tcp6Ap->ActiveFlag  = TRUE;
1149   Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
1150   Tcp6Ap->RemotePort  = HttpInstance->RemotePort;
1151   IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
1152   IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);
1153 
1154   Tcp6Option = Tcp6CfgData->ControlOption;
1155   Tcp6Option->ReceiveBufferSize  = HTTP_BUFFER_SIZE_DEAULT;
1156   Tcp6Option->SendBufferSize     = HTTP_BUFFER_SIZE_DEAULT;
1157   Tcp6Option->MaxSynBackLog      = HTTP_MAX_SYN_BACK_LOG;
1158   Tcp6Option->ConnectionTimeout  = HTTP_CONNECTION_TIMEOUT;
1159   Tcp6Option->DataRetries        = HTTP_DATA_RETRIES;
1160   Tcp6Option->FinTimeout         = HTTP_FIN_TIMEOUT;
1161   Tcp6Option->KeepAliveProbes    = HTTP_KEEP_ALIVE_PROBES;
1162   Tcp6Option->KeepAliveTime      = HTTP_KEEP_ALIVE_TIME;
1163   Tcp6Option->KeepAliveInterval  = HTTP_KEEP_ALIVE_INTERVAL;
1164   Tcp6Option->EnableNagle        = TRUE;
1165 
1166   Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
1167   if (EFI_ERROR (Status)) {
1168     DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));
1169     return Status;
1170   }
1171 
1172   Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1173   if (EFI_ERROR (Status)) {
1174     return Status;
1175   }
1176 
1177   Status = HttpCreateTcpTxEvent (Wrap);
1178   if (EFI_ERROR (Status)) {
1179     return Status;
1180   }
1181 
1182   HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1183 
1184   return EFI_SUCCESS;
1185 
1186 }
1187 
1188 /**
1189   Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1190   connect one TLS session if required.
1191 
1192   @param[in]  HttpInstance       The HTTP instance private data.
1193 
1194   @retval EFI_SUCCESS            The TCP connection is established.
1195   @retval EFI_NOT_READY          TCP4 protocol child is not created or configured.
1196   @retval Others                 Other error as indicated.
1197 
1198 **/
1199 EFI_STATUS
HttpConnectTcp4(IN HTTP_PROTOCOL * HttpInstance)1200 HttpConnectTcp4 (
1201   IN  HTTP_PROTOCOL        *HttpInstance
1202   )
1203 {
1204   EFI_STATUS                Status;
1205   EFI_TCP4_CONNECTION_STATE Tcp4State;
1206 
1207 
1208   if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
1209     return EFI_NOT_READY;
1210   }
1211 
1212   Status = HttpInstance->Tcp4->GetModeData(
1213                                  HttpInstance->Tcp4,
1214                                  &Tcp4State,
1215                                  NULL,
1216                                  NULL,
1217                                  NULL,
1218                                  NULL
1219                                  );
1220   if (EFI_ERROR(Status)){
1221     DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
1222     return Status;
1223   }
1224 
1225   if (Tcp4State == Tcp4StateEstablished) {
1226     return EFI_SUCCESS;
1227   } else if (Tcp4State > Tcp4StateEstablished ) {
1228     HttpCloseConnection(HttpInstance);
1229   }
1230 
1231   Status = HttpCreateConnection (HttpInstance);
1232   if (EFI_ERROR(Status)){
1233     DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));
1234     return Status;
1235   }
1236 
1237   //
1238   // Tls session connection.
1239   //
1240   if (HttpInstance->UseHttps) {
1241     if (HttpInstance->TimeoutEvent == NULL) {
1242       //
1243       // Create TimeoutEvent for TLS connection.
1244       //
1245       Status = gBS->CreateEvent (
1246                       EVT_TIMER,
1247                       TPL_CALLBACK,
1248                       NULL,
1249                       NULL,
1250                       &HttpInstance->TimeoutEvent
1251                       );
1252       if (EFI_ERROR (Status)) {
1253         TlsCloseTxRxEvent (HttpInstance);
1254         return Status;
1255       }
1256     }
1257 
1258     //
1259     // Start the timer, and wait Timeout seconds for connection.
1260     //
1261     Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1262     if (EFI_ERROR (Status)) {
1263       TlsCloseTxRxEvent (HttpInstance);
1264       return Status;
1265     }
1266 
1267     Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1268 
1269     gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1270 
1271     if (EFI_ERROR (Status)) {
1272       TlsCloseTxRxEvent (HttpInstance);
1273       return Status;
1274     }
1275   }
1276 
1277   return Status;
1278 }
1279 
1280 /**
1281   Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1282   connect one TLS session if required.
1283 
1284   @param[in]  HttpInstance       The HTTP instance private data.
1285 
1286   @retval EFI_SUCCESS            The TCP connection is established.
1287   @retval EFI_NOT_READY          TCP6 protocol child is not created or configured.
1288   @retval Others                 Other error as indicated.
1289 
1290 **/
1291 EFI_STATUS
HttpConnectTcp6(IN HTTP_PROTOCOL * HttpInstance)1292 HttpConnectTcp6 (
1293   IN  HTTP_PROTOCOL        *HttpInstance
1294   )
1295 {
1296   EFI_STATUS                Status;
1297   EFI_TCP6_CONNECTION_STATE Tcp6State;
1298 
1299   if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {
1300     return EFI_NOT_READY;
1301   }
1302 
1303   Status = HttpInstance->Tcp6->GetModeData (
1304                                  HttpInstance->Tcp6,
1305                                  &Tcp6State,
1306                                  NULL,
1307                                  NULL,
1308                                  NULL,
1309                                  NULL
1310                                  );
1311 
1312   if (EFI_ERROR(Status)){
1313      DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
1314      return Status;
1315   }
1316 
1317   if (Tcp6State == Tcp6StateEstablished) {
1318     return EFI_SUCCESS;
1319   } else if (Tcp6State > Tcp6StateEstablished ) {
1320     HttpCloseConnection(HttpInstance);
1321   }
1322 
1323   Status = HttpCreateConnection (HttpInstance);
1324   if (EFI_ERROR(Status)){
1325     DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));
1326     return Status;
1327   }
1328 
1329   //
1330   // Tls session connection.
1331   //
1332   if (HttpInstance->UseHttps) {
1333     if (HttpInstance->TimeoutEvent == NULL) {
1334       //
1335       // Create TimeoutEvent for TLS connection.
1336       //
1337       Status = gBS->CreateEvent (
1338                       EVT_TIMER,
1339                       TPL_CALLBACK,
1340                       NULL,
1341                       NULL,
1342                       &HttpInstance->TimeoutEvent
1343                       );
1344       if (EFI_ERROR (Status)) {
1345         TlsCloseTxRxEvent (HttpInstance);
1346         return Status;
1347       }
1348     }
1349 
1350     //
1351     // Start the timer, and wait Timeout seconds for connection.
1352     //
1353     Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1354     if (EFI_ERROR (Status)) {
1355       TlsCloseTxRxEvent (HttpInstance);
1356       return Status;
1357     }
1358 
1359     Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1360 
1361     gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1362 
1363     if (EFI_ERROR (Status)) {
1364       TlsCloseTxRxEvent (HttpInstance);
1365       return Status;
1366     }
1367   }
1368 
1369   return Status;
1370 }
1371 
1372 /**
1373   Initialize Http session.
1374 
1375   @param[in]  HttpInstance       The HTTP instance private data.
1376   @param[in]  Wrap               The HTTP token's wrap data.
1377   @param[in]  Configure          The Flag indicates whether need to initialize session.
1378   @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls session.
1379 
1380   @retval EFI_SUCCESS            The initialization of session is done.
1381   @retval Others                 Other error as indicated.
1382 
1383 **/
1384 EFI_STATUS
HttpInitSession(IN HTTP_PROTOCOL * HttpInstance,IN HTTP_TOKEN_WRAP * Wrap,IN BOOLEAN Configure,IN BOOLEAN TlsConfigure)1385 HttpInitSession (
1386   IN  HTTP_PROTOCOL    *HttpInstance,
1387   IN  HTTP_TOKEN_WRAP  *Wrap,
1388   IN  BOOLEAN          Configure,
1389   IN  BOOLEAN          TlsConfigure
1390   )
1391 {
1392   EFI_STATUS           Status;
1393   ASSERT (HttpInstance != NULL);
1394 
1395   //
1396   // Configure Tls session.
1397   //
1398   if (TlsConfigure) {
1399     Status = TlsConfigureSession (HttpInstance);
1400     if (EFI_ERROR (Status)) {
1401       return Status;
1402     }
1403   }
1404 
1405   if (!HttpInstance->LocalAddressIsIPv6) {
1406     //
1407     // Configure TCP instance.
1408     //
1409     if (Configure) {
1410       Status = HttpConfigureTcp4 (HttpInstance, Wrap);
1411       if (EFI_ERROR (Status)) {
1412         return Status;
1413       }
1414     }
1415 
1416     //
1417     // Connect TCP.
1418     //
1419     Status = HttpConnectTcp4 (HttpInstance);
1420     if (EFI_ERROR (Status)) {
1421       return Status;
1422     }
1423   } else {
1424     //
1425     // Configure TCP instance.
1426     //
1427     if (Configure) {
1428       Status = HttpConfigureTcp6 (HttpInstance, Wrap);
1429       if (EFI_ERROR (Status)) {
1430         return Status;
1431       }
1432     }
1433 
1434     //
1435     // Connect TCP.
1436     //
1437     Status = HttpConnectTcp6 (HttpInstance);
1438     if (EFI_ERROR (Status)) {
1439       return Status;
1440     }
1441   }
1442 
1443   return EFI_SUCCESS;
1444 
1445 }
1446 
1447 /**
1448   Send the HTTP or HTTPS message through TCP4 or TCP6.
1449 
1450   @param[in]  HttpInstance       The HTTP instance private data.
1451   @param[in]  Wrap               The HTTP token's wrap data.
1452   @param[in]  TxString           Buffer containing the HTTP message string.
1453   @param[in]  TxStringLen        Length of the HTTP message string in bytes.
1454 
1455   @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit queue.
1456   @retval Others                 Other error as indicated.
1457 
1458 **/
1459 EFI_STATUS
HttpTransmitTcp(IN HTTP_PROTOCOL * HttpInstance,IN HTTP_TOKEN_WRAP * Wrap,IN UINT8 * TxString,IN UINTN TxStringLen)1460 HttpTransmitTcp (
1461   IN  HTTP_PROTOCOL    *HttpInstance,
1462   IN  HTTP_TOKEN_WRAP  *Wrap,
1463   IN  UINT8            *TxString,
1464   IN  UINTN            TxStringLen
1465   )
1466 {
1467   EFI_STATUS                    Status;
1468   EFI_TCP4_IO_TOKEN             *Tx4Token;
1469   EFI_TCP4_PROTOCOL             *Tcp4;
1470   EFI_TCP6_IO_TOKEN             *Tx6Token;
1471   EFI_TCP6_PROTOCOL             *Tcp6;
1472   UINT8                         *Buffer;
1473   UINTN                         BufferSize;
1474   NET_FRAGMENT                  TempFragment;
1475 
1476   Status                = EFI_SUCCESS;
1477   Buffer                = NULL;
1478   TempFragment.Len      = 0;
1479   TempFragment.Bulk     = NULL;
1480 
1481   //
1482   // Need to encrypt data.
1483   //
1484   if (HttpInstance->UseHttps) {
1485     //
1486     // Build BufferOut data
1487     //
1488     BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;
1489     Buffer     = AllocateZeroPool (BufferSize);
1490     if (Buffer == NULL) {
1491       Status = EFI_OUT_OF_RESOURCES;
1492       return Status;
1493     }
1494     ((TLS_RECORD_HEADER *) Buffer)->ContentType = TLS_CONTENT_TYPE_APPLICATION_DATA;
1495     ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
1496     ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
1497     ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);
1498     CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);
1499 
1500     //
1501     // Encrypt Packet.
1502     //
1503     Status = TlsProcessMessage (
1504                HttpInstance,
1505                Buffer,
1506                BufferSize,
1507                EfiTlsEncrypt,
1508                &TempFragment
1509                );
1510 
1511     FreePool (Buffer);
1512 
1513     if (EFI_ERROR (Status)) {
1514       return Status;
1515     }
1516   }
1517 
1518   if (!HttpInstance->LocalAddressIsIPv6) {
1519     Tcp4 = HttpInstance->Tcp4;
1520     Tx4Token = &Wrap->TcpWrap.Tx4Token;
1521 
1522     if (HttpInstance->UseHttps) {
1523       Tx4Token->Packet.TxData->DataLength = TempFragment.Len;
1524       Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
1525       Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
1526     } else {
1527       Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1528       Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1529       Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1530     }
1531 
1532     Tx4Token->CompletionToken.Status = EFI_NOT_READY;
1533 
1534     Wrap->TcpWrap.IsTxDone = FALSE;
1535     Status  = Tcp4->Transmit (Tcp4, Tx4Token);
1536     if (EFI_ERROR (Status)) {
1537       DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1538       return Status;
1539     }
1540 
1541   } else {
1542     Tcp6 = HttpInstance->Tcp6;
1543     Tx6Token = &Wrap->TcpWrap.Tx6Token;
1544 
1545     if (HttpInstance->UseHttps) {
1546       Tx6Token->Packet.TxData->DataLength = TempFragment.Len;
1547       Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
1548       Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
1549     } else {
1550       Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1551       Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1552       Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1553     }
1554 
1555     Tx6Token->CompletionToken.Status = EFI_NOT_READY;
1556 
1557     Wrap->TcpWrap.IsTxDone = FALSE;
1558     Status = Tcp6->Transmit (Tcp6, Tx6Token);
1559     if (EFI_ERROR (Status)) {
1560       DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1561       return Status;
1562     }
1563   }
1564 
1565   return Status;
1566 }
1567 
1568 /**
1569   Check whether the user's token or event has already
1570   been enqueue on HTTP Tx or Rx Token list.
1571 
1572   @param[in]  Map                The container of either user's transmit or receive
1573                                  token.
1574   @param[in]  Item               Current item to check against.
1575   @param[in]  Context            The Token to check againist.
1576 
1577   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP
1578   @retval EFI_SUCCESS            The current item isn't the same token/event as the
1579                                  context.
1580 
1581 **/
1582 EFI_STATUS
1583 EFIAPI
HttpTokenExist(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1584 HttpTokenExist (
1585   IN NET_MAP                *Map,
1586   IN NET_MAP_ITEM           *Item,
1587   IN VOID                   *Context
1588   )
1589 {
1590   EFI_HTTP_TOKEN            *Token;
1591   EFI_HTTP_TOKEN            *TokenInItem;
1592 
1593   Token       = (EFI_HTTP_TOKEN *) Context;
1594   TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
1595 
1596   if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
1597     return EFI_ACCESS_DENIED;
1598   }
1599 
1600   return EFI_SUCCESS;
1601 }
1602 
1603 /**
1604   Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1605 
1606   @param[in]  Map                The container of Tx4Token or Tx6Token.
1607   @param[in]  Item               Current item to check against.
1608   @param[in]  Context            The Token to check againist.
1609 
1610   @retval EFI_NOT_READY          The HTTP message is still queued in the list.
1611   @retval EFI_SUCCESS            The HTTP message has been sent out.
1612 
1613 **/
1614 EFI_STATUS
1615 EFIAPI
HttpTcpNotReady(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1616 HttpTcpNotReady (
1617   IN NET_MAP                *Map,
1618   IN NET_MAP_ITEM           *Item,
1619   IN VOID                   *Context
1620   )
1621 {
1622   HTTP_TOKEN_WRAP           *ValueInItem;
1623 
1624   ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1625 
1626   if (!ValueInItem->TcpWrap.IsTxDone) {
1627     return EFI_NOT_READY;
1628   }
1629 
1630   return EFI_SUCCESS;
1631 }
1632 
1633 /**
1634   Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.
1635 
1636   @param[in]  Map                The container of Tx4Token or Tx6Token.
1637   @param[in]  Item               Current item to check against.
1638   @param[in]  Context            The Token to check againist.
1639 
1640   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
1641   @retval EFI_SUCCESS            The HTTP message is queued into TCP transmit
1642                                  queue.
1643 
1644 **/
1645 EFI_STATUS
1646 EFIAPI
HttpTcpTransmit(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1647 HttpTcpTransmit (
1648   IN NET_MAP                *Map,
1649   IN NET_MAP_ITEM           *Item,
1650   IN VOID                   *Context
1651   )
1652 {
1653   HTTP_TOKEN_WRAP           *ValueInItem;
1654   EFI_STATUS                Status;
1655   CHAR8                     *RequestMsg;
1656   CHAR8                     *Url;
1657   UINTN                     UrlSize;
1658   UINTN                     RequestMsgSize;
1659 
1660   RequestMsg = NULL;
1661 
1662   ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1663   if (ValueInItem->TcpWrap.IsTxDone) {
1664     return EFI_SUCCESS;
1665   }
1666 
1667   //
1668   // Parse the URI of the remote host.
1669   //
1670   UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
1671   Url = AllocatePool (UrlSize);
1672   if (Url == NULL) {
1673     return EFI_OUT_OF_RESOURCES;
1674   }
1675 
1676   UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
1677 
1678   //
1679   // Create request message.
1680   //
1681   Status = HttpGenRequestMessage (
1682                  ValueInItem->HttpToken->Message,
1683                  Url,
1684                  &RequestMsg,
1685                  &RequestMsgSize
1686                  );
1687   FreePool (Url);
1688 
1689   if (EFI_ERROR (Status) || NULL == RequestMsg){
1690     return Status;
1691   }
1692 
1693   ASSERT (RequestMsg != NULL);
1694 
1695   //
1696   // Transmit the request message.
1697   //
1698   Status = HttpTransmitTcp (
1699              ValueInItem->HttpInstance,
1700              ValueInItem,
1701              (UINT8*) RequestMsg,
1702              RequestMsgSize
1703              );
1704   FreePool (RequestMsg);
1705   return Status;
1706 }
1707 
1708 /**
1709   Receive the HTTP response by processing the associated HTTP token.
1710 
1711   @param[in]  Map                The container of Rx4Token or Rx6Token.
1712   @param[in]  Item               Current item to check against.
1713   @param[in]  Context            The Token to check againist.
1714 
1715   @retval EFI_SUCCESS            The HTTP response is queued into TCP receive
1716                                  queue.
1717   @retval Others                 Other error as indicated.
1718 
1719 **/
1720 EFI_STATUS
1721 EFIAPI
HttpTcpReceive(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1722 HttpTcpReceive (
1723   IN NET_MAP                *Map,
1724   IN NET_MAP_ITEM           *Item,
1725   IN VOID                   *Context
1726   )
1727 {
1728   //
1729   // Process the queued HTTP response.
1730   //
1731   return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
1732 }
1733 
1734 /**
1735   Receive the HTTP header by processing the associated HTTP token.
1736 
1737   @param[in]       HttpInstance     The HTTP instance private data.
1738   @param[in, out]  SizeofHeaders    The HTTP header length.
1739   @param[in, out]  BufferSize       The size of buffer to cacahe the header message.
1740   @param[in]       Timeout          The time to wait for receiving the header packet.
1741 
1742   @retval EFI_SUCCESS               The HTTP header is received.
1743   @retval Others                    Other errors as indicated.
1744 
1745 **/
1746 EFI_STATUS
HttpTcpReceiveHeader(IN HTTP_PROTOCOL * HttpInstance,IN OUT UINTN * SizeofHeaders,IN OUT UINTN * BufferSize,IN EFI_EVENT Timeout)1747 HttpTcpReceiveHeader (
1748   IN  HTTP_PROTOCOL         *HttpInstance,
1749   IN  OUT UINTN             *SizeofHeaders,
1750   IN  OUT UINTN             *BufferSize,
1751   IN  EFI_EVENT             Timeout
1752   )
1753 {
1754   EFI_STATUS                    Status;
1755   EFI_TCP4_IO_TOKEN             *Rx4Token;
1756   EFI_TCP4_PROTOCOL             *Tcp4;
1757   EFI_TCP6_IO_TOKEN             *Rx6Token;
1758   EFI_TCP6_PROTOCOL             *Tcp6;
1759   CHAR8                         **EndofHeader;
1760   CHAR8                         **HttpHeaders;
1761   CHAR8                         *Buffer;
1762   NET_FRAGMENT                  Fragment;
1763 
1764   ASSERT (HttpInstance != NULL);
1765 
1766   EndofHeader = HttpInstance->EndofHeader;
1767   HttpHeaders = HttpInstance->HttpHeaders;
1768   Tcp4 = HttpInstance->Tcp4;
1769   Tcp6 = HttpInstance->Tcp6;
1770   Buffer      = NULL;
1771   Rx4Token    = NULL;
1772   Rx6Token    = NULL;
1773   Fragment.Len  = 0;
1774   Fragment.Bulk = NULL;
1775 
1776   if (HttpInstance->LocalAddressIsIPv6) {
1777     ASSERT (Tcp6 != NULL);
1778   } else {
1779     ASSERT (Tcp4 != NULL);
1780   }
1781 
1782   if (!HttpInstance->UseHttps) {
1783     Status = HttpCreateTcpRxEventForHeader (HttpInstance);
1784     if (EFI_ERROR (Status)) {
1785       return Status;
1786     }
1787   }
1788 
1789   if (!HttpInstance->LocalAddressIsIPv6) {
1790     if (!HttpInstance->UseHttps) {
1791       Rx4Token = &HttpInstance->Rx4Token;
1792       Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1793       if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1794         Status = EFI_OUT_OF_RESOURCES;
1795         return Status;
1796       }
1797     }
1798 
1799     //
1800     // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1801     //
1802     while (*EndofHeader == NULL) {
1803       if (!HttpInstance->UseHttps) {
1804         HttpInstance->IsRxDone = FALSE;
1805         Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1806         Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1807         Status = Tcp4->Receive (Tcp4, Rx4Token);
1808         if (EFI_ERROR (Status)) {
1809           DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1810           return Status;
1811         }
1812 
1813         while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1814           Tcp4->Poll (Tcp4);
1815         }
1816 
1817         if (!HttpInstance->IsRxDone) {
1818           //
1819           // Cancle the Token before close its Event.
1820           //
1821           Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
1822           gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1823           Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1824         }
1825 
1826         Status = Rx4Token->CompletionToken.Status;
1827         if (EFI_ERROR (Status)) {
1828           return Status;
1829         }
1830 
1831         Fragment.Len  = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
1832         Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1833       } else {
1834         if (Fragment.Bulk != NULL) {
1835           FreePool (Fragment.Bulk);
1836           Fragment.Bulk = NULL;
1837         }
1838 
1839         Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1840         if (EFI_ERROR (Status)) {
1841           DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1842           return Status;
1843         }
1844       }
1845 
1846       //
1847       // Append the response string.
1848       //
1849       *BufferSize = *SizeofHeaders + Fragment.Len;
1850       Buffer      = AllocateZeroPool (*BufferSize);
1851       if (Buffer == NULL) {
1852         Status = EFI_OUT_OF_RESOURCES;
1853         return Status;
1854       }
1855 
1856       if (*HttpHeaders != NULL) {
1857         CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1858         FreePool (*HttpHeaders);
1859       }
1860 
1861       CopyMem (
1862         Buffer + *SizeofHeaders,
1863         Fragment.Bulk,
1864         Fragment.Len
1865         );
1866       *HttpHeaders   = Buffer;
1867       *SizeofHeaders = *BufferSize;
1868 
1869       //
1870       // Check whether we received end of HTTP headers.
1871       //
1872       *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1873     };
1874 
1875     //
1876     // Free the buffer.
1877     //
1878     if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1879       FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1880       Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1881       Fragment.Bulk = NULL;
1882     }
1883 
1884     if (Fragment.Bulk != NULL) {
1885       FreePool (Fragment.Bulk);
1886       Fragment.Bulk = NULL;
1887     }
1888   } else {
1889     if (!HttpInstance->UseHttps) {
1890       Rx6Token = &HttpInstance->Rx6Token;
1891       Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1892       if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1893         Status = EFI_OUT_OF_RESOURCES;
1894         return Status;
1895       }
1896     }
1897 
1898     //
1899     // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1900     //
1901     while (*EndofHeader == NULL) {
1902       if (!HttpInstance->UseHttps) {
1903         HttpInstance->IsRxDone = FALSE;
1904         Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1905         Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1906         Status = Tcp6->Receive (Tcp6, Rx6Token);
1907         if (EFI_ERROR (Status)) {
1908           DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1909           return Status;
1910         }
1911 
1912         while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1913           Tcp6->Poll (Tcp6);
1914         }
1915 
1916         if (!HttpInstance->IsRxDone) {
1917           //
1918           // Cancle the Token before close its Event.
1919           //
1920           Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
1921           gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1922           Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1923         }
1924 
1925         Status = Rx6Token->CompletionToken.Status;
1926         if (EFI_ERROR (Status)) {
1927           return Status;
1928         }
1929 
1930         Fragment.Len  = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
1931         Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1932       } else {
1933         if (Fragment.Bulk != NULL) {
1934           FreePool (Fragment.Bulk);
1935           Fragment.Bulk = NULL;
1936         }
1937 
1938         Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1939         if (EFI_ERROR (Status)) {
1940           DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1941           return Status;
1942         }
1943       }
1944 
1945       //
1946       // Append the response string.
1947       //
1948       *BufferSize = *SizeofHeaders + Fragment.Len;
1949       Buffer      = AllocateZeroPool (*BufferSize);
1950       if (Buffer == NULL) {
1951         Status = EFI_OUT_OF_RESOURCES;
1952         return Status;
1953       }
1954 
1955       if (*HttpHeaders != NULL) {
1956         CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1957         FreePool (*HttpHeaders);
1958       }
1959 
1960       CopyMem (
1961         Buffer + *SizeofHeaders,
1962         Fragment.Bulk,
1963         Fragment.Len
1964         );
1965       *HttpHeaders   = Buffer;
1966       *SizeofHeaders = *BufferSize;
1967 
1968       //
1969       // Check whether we received end of HTTP headers.
1970       //
1971       *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1972     };
1973 
1974     //
1975     // Free the buffer.
1976     //
1977     if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1978       FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1979       Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1980       Fragment.Bulk = NULL;
1981     }
1982 
1983     if (Fragment.Bulk != NULL) {
1984       FreePool (Fragment.Bulk);
1985       Fragment.Bulk = NULL;
1986     }
1987   }
1988 
1989   //
1990   // Skip the CRLF after the HTTP headers.
1991   //
1992   *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
1993 
1994   return EFI_SUCCESS;
1995 }
1996 
1997 /**
1998   Receive the HTTP body by processing the associated HTTP token.
1999 
2000   @param[in]  Wrap               The HTTP token's wrap data.
2001   @param[in]  HttpMsg            The HTTP message data.
2002 
2003   @retval EFI_SUCCESS            The HTTP body is received.
2004   @retval Others                 Other error as indicated.
2005 
2006 **/
2007 EFI_STATUS
HttpTcpReceiveBody(IN HTTP_TOKEN_WRAP * Wrap,IN EFI_HTTP_MESSAGE * HttpMsg)2008 HttpTcpReceiveBody (
2009   IN  HTTP_TOKEN_WRAP       *Wrap,
2010   IN  EFI_HTTP_MESSAGE      *HttpMsg
2011   )
2012 {
2013   EFI_STATUS                Status;
2014   HTTP_PROTOCOL             *HttpInstance;
2015   EFI_TCP6_PROTOCOL         *Tcp6;
2016   EFI_TCP6_IO_TOKEN         *Rx6Token;
2017   EFI_TCP4_PROTOCOL         *Tcp4;
2018   EFI_TCP4_IO_TOKEN         *Rx4Token;
2019 
2020   HttpInstance   = Wrap->HttpInstance;
2021   Tcp4 = HttpInstance->Tcp4;
2022   Tcp6 = HttpInstance->Tcp6;
2023   Rx4Token       = NULL;
2024   Rx6Token       = NULL;
2025 
2026   if (HttpInstance->LocalAddressIsIPv6) {
2027     ASSERT (Tcp6 != NULL);
2028   } else {
2029     ASSERT (Tcp4 != NULL);
2030   }
2031 
2032   if (HttpInstance->LocalAddressIsIPv6) {
2033     Rx6Token = &Wrap->TcpWrap.Rx6Token;
2034     Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
2035     Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
2036     Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
2037     Rx6Token->CompletionToken.Status = EFI_NOT_READY;
2038 
2039     Status = Tcp6->Receive (Tcp6, Rx6Token);
2040     if (EFI_ERROR (Status)) {
2041       DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
2042       return Status;
2043     }
2044   } else {
2045     Rx4Token = &Wrap->TcpWrap.Rx4Token;
2046     Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
2047     Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
2048     Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
2049 
2050     Rx4Token->CompletionToken.Status = EFI_NOT_READY;
2051     Status = Tcp4->Receive (Tcp4, Rx4Token);
2052     if (EFI_ERROR (Status)) {
2053       DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
2054       return Status;
2055     }
2056   }
2057 
2058   return EFI_SUCCESS;
2059 
2060 }
2061 
2062 /**
2063   Clean up Tcp Tokens while the Tcp transmission error occurs.
2064 
2065   @param[in]  Wrap               Pointer to HTTP token's wrap data.
2066 
2067 **/
2068 VOID
HttpTcpTokenCleanup(IN HTTP_TOKEN_WRAP * Wrap)2069 HttpTcpTokenCleanup (
2070   IN  HTTP_TOKEN_WRAP      *Wrap
2071   )
2072 {
2073   HTTP_PROTOCOL            *HttpInstance;
2074   EFI_TCP4_IO_TOKEN        *Rx4Token;
2075   EFI_TCP6_IO_TOKEN        *Rx6Token;
2076 
2077   ASSERT (Wrap != NULL);
2078   HttpInstance   = Wrap->HttpInstance;
2079   Rx4Token       = NULL;
2080   Rx6Token       = NULL;
2081 
2082   if (HttpInstance->LocalAddressIsIPv6) {
2083     Rx6Token = &Wrap->TcpWrap.Rx6Token;
2084 
2085     if (Rx6Token->CompletionToken.Event != NULL) {
2086       gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2087       Rx6Token->CompletionToken.Event = NULL;
2088     }
2089 
2090     FreePool (Wrap);
2091 
2092     Rx6Token = &HttpInstance->Rx6Token;
2093 
2094     if (Rx6Token->CompletionToken.Event != NULL) {
2095       gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2096       Rx6Token->CompletionToken.Event = NULL;
2097     }
2098 
2099     if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2100       FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2101       Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2102     }
2103 
2104   } else {
2105     Rx4Token = &Wrap->TcpWrap.Rx4Token;
2106 
2107     if (Rx4Token->CompletionToken.Event != NULL) {
2108       gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2109       Rx4Token->CompletionToken.Event = NULL;
2110     }
2111 
2112     FreePool (Wrap);
2113 
2114     Rx4Token = &HttpInstance->Rx4Token;
2115 
2116     if (Rx4Token->CompletionToken.Event != NULL) {
2117       gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2118       Rx4Token->CompletionToken.Event = NULL;
2119     }
2120 
2121 
2122     if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2123       FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2124       Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2125     }
2126   }
2127 
2128 }
2129