Home | History | Annotate | Download | only in HttpDxe
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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 *
   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