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