NetworkPkg: Convert files to CRLF line ending
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpsSupport.c
index f0077dd..e4d9a37 100644 (file)
-/** @file
-  Miscellaneous routines specific to Https for HttpDxe driver.
-
-Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "HttpDriver.h"
-
-/**
-  Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
-  ASCII string and ignore case during the search process.
-
-  This function scans the contents of the ASCII string specified by String
-  and returns the first occurrence of SearchString and ignore case during the search process.
-  If SearchString is not found in String, then NULL is returned. If the length of SearchString
-  is zero, then String is returned.
-
-  If String is NULL, then ASSERT().
-  If SearchString is NULL, then ASSERT().
-
-  @param[in]  String          A pointer to a Null-terminated ASCII string.
-  @param[in]  SearchString    A pointer to a Null-terminated ASCII string to search for.
-
-  @retval NULL            If the SearchString does not appear in String.
-  @retval others          If there is a match return the first occurrence of SearchingString.
-                          If the length of SearchString is zero,return String.
-
-**/
-CHAR8 *
-AsciiStrCaseStr (
-  IN      CONST CHAR8               *String,
-  IN      CONST CHAR8               *SearchString
-  )
-{
-  CONST CHAR8 *FirstMatch;
-  CONST CHAR8 *SearchStringTmp;
-
-  CHAR8 Src;
-  CHAR8 Dst;
-
-  //
-  // ASSERT both strings are less long than PcdMaximumAsciiStringLength
-  //
-  ASSERT (AsciiStrSize (String) != 0);
-  ASSERT (AsciiStrSize (SearchString) != 0);
-
-  if (*SearchString == '\0') {
-    return (CHAR8 *) String;
-  }
-
-  while (*String != '\0') {
-    SearchStringTmp = SearchString;
-    FirstMatch = String;
-
-    while ((*SearchStringTmp != '\0')
-            && (*String != '\0')) {
-      Src = *String;
-      Dst = *SearchStringTmp;
-
-      if ((Src >= 'A') && (Src <= 'Z')) {
-        Src -= ('A' - 'a');
-      }
-
-      if ((Dst >= 'A') && (Dst <= 'Z')) {
-        Dst -= ('A' - 'a');
-      }
-
-      if (Src != Dst) {
-        break;
-      }
-
-      String++;
-      SearchStringTmp++;
-    }
-
-    if (*SearchStringTmp == '\0') {
-      return (CHAR8 *) FirstMatch;
-    }
-
-    String = FirstMatch + 1;
-  }
-
-  return NULL;
-}
-
-/**
-  The callback function to free the net buffer list.
-
-  @param[in]  Arg The opaque parameter.
-
-**/
-VOID
-EFIAPI
-FreeNbufList (
-  IN VOID *Arg
-  )
-{
-  ASSERT (Arg != NULL);
-
-  NetbufFreeList ((LIST_ENTRY *) Arg);
-  FreePool (Arg);
-}
-
-/**
-  Check whether the Url is from Https.
-
-  @param[in]    Url             The pointer to a HTTP or HTTPS URL string.
-
-  @retval TRUE                  The Url is from HTTPS.
-  @retval FALSE                 The Url is from HTTP.
-
-**/
-BOOLEAN
-IsHttpsUrl (
-  IN CHAR8    *Url
-  )
-{
-  CHAR8  *Tmp;
-
-  Tmp = NULL;
-
-  Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);
-  if (Tmp != NULL && Tmp == Url) {
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
-
-  @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
-  @param[out] TlsProto              Pointer to the EFI_TLS_PROTOCOL instance.
-  @param[out] TlsConfiguration      Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
-
-  @return  The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
-
-**/
-EFI_HANDLE
-EFIAPI
-TlsCreateChild (
-  IN  EFI_HANDLE                     ImageHandle,
-  OUT EFI_TLS_PROTOCOL               **TlsProto,
-  OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
-  )
-{
-  EFI_STATUS                    Status;
-  EFI_SERVICE_BINDING_PROTOCOL  *TlsSb;
-  EFI_HANDLE                    TlsChildHandle;
-
-  TlsSb          = NULL;
-  TlsChildHandle = 0;
-
-  //
-  // Locate TlsServiceBinding protocol.
-  //
-  gBS->LocateProtocol (
-     &gEfiTlsServiceBindingProtocolGuid,
-     NULL,
-     (VOID **) &TlsSb
-     );
-  if (TlsSb == NULL) {
-    return NULL;
-  }
-
-  Status = TlsSb->CreateChild (TlsSb, &TlsChildHandle);
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  Status = gBS->OpenProtocol (
-                  TlsChildHandle,
-                  &gEfiTlsProtocolGuid,
-                  (VOID **) TlsProto,
-                  ImageHandle,
-                  TlsChildHandle,
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
-                  );
-  if (EFI_ERROR (Status)) {
-    TlsSb->DestroyChild (TlsSb, TlsChildHandle);
-    return NULL;
-  }
-
-  Status = gBS->OpenProtocol (
-                  TlsChildHandle,
-                  &gEfiTlsConfigurationProtocolGuid,
-                  (VOID **) TlsConfiguration,
-                  ImageHandle,
-                  TlsChildHandle,
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
-                  );
-  if (EFI_ERROR (Status)) {
-    TlsSb->DestroyChild (TlsSb, TlsChildHandle);
-    return NULL;
-  }
-
-  return TlsChildHandle;
-}
-
-/**
-  Create event for the TLS receive and transmit tokens which are used to receive and
-  transmit TLS related messages.
-
-  @param[in, out]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
-
-  @retval EFI_SUCCESS            The events are created successfully.
-  @retval others                 Other error as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsCreateTxRxEvent (
-  IN OUT HTTP_PROTOCOL      *HttpInstance
-  )
-{
-  EFI_STATUS                Status;
-
-  if (!HttpInstance->LocalAddressIsIPv6) {
-    //
-    // For Tcp4TlsTxToken.
-    //
-    Status = gBS->CreateEvent (
-                    EVT_NOTIFY_SIGNAL,
-                    TPL_NOTIFY,
-                    HttpCommonNotify,
-                    &HttpInstance->TlsIsTxDone,
-                    &HttpInstance->Tcp4TlsTxToken.CompletionToken.Event
-                    );
-    if (EFI_ERROR (Status)) {
-      goto ERROR;
-    }
-
-    HttpInstance->Tcp4TlsTxData.Push = TRUE;
-    HttpInstance->Tcp4TlsTxData.Urgent = FALSE;
-    HttpInstance->Tcp4TlsTxData.DataLength = 0;
-    HttpInstance->Tcp4TlsTxData.FragmentCount = 1;
-    HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;
-    HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
-    HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;
-    HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
-
-    //
-    // For Tcp4TlsRxToken.
-    //
-    Status = gBS->CreateEvent (
-                    EVT_NOTIFY_SIGNAL,
-                    TPL_NOTIFY,
-                    HttpCommonNotify,
-                    &HttpInstance->TlsIsRxDone,
-                    &HttpInstance->Tcp4TlsRxToken.CompletionToken.Event
-                    );
-    if (EFI_ERROR (Status)) {
-      goto ERROR;
-    }
-
-    HttpInstance->Tcp4TlsRxData.DataLength                       = 0;
-    HttpInstance->Tcp4TlsRxData.FragmentCount                    = 1;
-    HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp4TlsRxData.DataLength ;
-    HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;
-    HttpInstance->Tcp4TlsRxToken.Packet.RxData          = &HttpInstance->Tcp4TlsRxData;
-    HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
-  } else {
-    //
-    // For Tcp6TlsTxToken.
-    //
-    Status = gBS->CreateEvent (
-                    EVT_NOTIFY_SIGNAL,
-                    TPL_NOTIFY,
-                    HttpCommonNotify,
-                    &HttpInstance->TlsIsTxDone,
-                    &HttpInstance->Tcp6TlsTxToken.CompletionToken.Event
-                    );
-    if (EFI_ERROR (Status)) {
-      goto ERROR;
-    }
-
-    HttpInstance->Tcp6TlsTxData.Push = TRUE;
-    HttpInstance->Tcp6TlsTxData.Urgent = FALSE;
-    HttpInstance->Tcp6TlsTxData.DataLength = 0;
-    HttpInstance->Tcp6TlsTxData.FragmentCount = 1;
-    HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;
-    HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
-    HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;
-    HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
-
-    //
-    // For Tcp6TlsRxToken.
-    //
-    Status = gBS->CreateEvent (
-                    EVT_NOTIFY_SIGNAL,
-                    TPL_NOTIFY,
-                    HttpCommonNotify,
-                    &HttpInstance->TlsIsRxDone,
-                    &HttpInstance->Tcp6TlsRxToken.CompletionToken.Event
-                    );
-    if (EFI_ERROR (Status)) {
-      goto ERROR;
-    }
-
-    HttpInstance->Tcp6TlsRxData.DataLength                       = 0;
-    HttpInstance->Tcp6TlsRxData.FragmentCount                    = 1;
-    HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp6TlsRxData.DataLength ;
-    HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;
-    HttpInstance->Tcp6TlsRxToken.Packet.RxData          = &HttpInstance->Tcp6TlsRxData;
-    HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
-  }
-
-  return Status;
-
-ERROR:
-  //
-  // Error handling
-  //
-  TlsCloseTxRxEvent (HttpInstance);
-
-  return Status;
-}
-
-/**
-  Close events in the TlsTxToken and TlsRxToken.
-
-  @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.
-
-**/
-VOID
-EFIAPI
-TlsCloseTxRxEvent (
-  IN  HTTP_PROTOCOL        *HttpInstance
-  )
-{
-  ASSERT (HttpInstance != NULL);
-  if (!HttpInstance->LocalAddressIsIPv6) {
-    if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {
-      gBS->CloseEvent(HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);
-      HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;
-    }
-
-    if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {
-      gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);
-      HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;
-    }
-  } else {
-    if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {
-      gBS->CloseEvent(HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);
-      HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;
-    }
-
-    if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {
-      gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);
-      HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;
-    }
-  }
-}
-
-/**
-  Read the TlsCaCertificate variable and configure it.
-
-  @param[in, out]  HttpInstance       The HTTP instance private data.
-
-  @retval EFI_SUCCESS            TlsCaCertificate is configured.
-  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
-  @retval EFI_NOT_FOUND          Fail to get 'TlsCaCertificate' variable.
-  @retval Others                 Other error as indicated.
-
-**/
-EFI_STATUS
-TlsConfigCertificate (
-  IN OUT HTTP_PROTOCOL      *HttpInstance
-  )
-{
-  EFI_STATUS          Status;
-  UINT8               *CACert;
-  UINTN               CACertSize;
-  UINT32              Index;
-  EFI_SIGNATURE_LIST  *CertList;
-  EFI_SIGNATURE_DATA  *Cert;
-  UINTN               CertCount;
-  UINT32              ItemDataSize;
-
-  CACert     = NULL;
-  CACertSize = 0;
-  
-  //
-  // Try to read the TlsCaCertificate variable.
-  //
-  Status  = gRT->GetVariable (
-                   EFI_TLS_CA_CERTIFICATE_VARIABLE,
-                   &gEfiTlsCaCertificateGuid,
-                   NULL,
-                   &CACertSize,
-                   NULL
-                   );
-
-  if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
-    return Status;
-  }
-
-  //
-  // Allocate buffer and read the config variable.
-  //
-  CACert = AllocatePool (CACertSize);
-  if (CACert == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  Status = gRT->GetVariable (
-                  EFI_TLS_CA_CERTIFICATE_VARIABLE,
-                  &gEfiTlsCaCertificateGuid,
-                  NULL,
-                  &CACertSize,
-                  CACert
-                  );
-  if (EFI_ERROR (Status)) {
-    //
-    // GetVariable still error or the variable is corrupted.
-    // Fall back to the default value.
-    //
-    FreePool (CACert);
-
-    return EFI_NOT_FOUND;
-  }
-
-  ASSERT (CACert != NULL);
-
-  //
-  // Enumerate all data and erasing the target item.
-  //
-  ItemDataSize = (UINT32) CACertSize;
-  CertList = (EFI_SIGNATURE_LIST *) CACert;
-  while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
-    Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
-    CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
-    for (Index = 0; Index < CertCount; Index++) {
-      //
-      // EfiTlsConfigDataTypeCACertificate
-      //
-      Status = HttpInstance->TlsConfiguration->SetData (
-                                                 HttpInstance->TlsConfiguration,
-                                                 EfiTlsConfigDataTypeCACertificate,
-                                                 Cert->SignatureData,
-                                                 CertList->SignatureSize - sizeof (Cert->SignatureOwner)
-                                                 );
-      if (EFI_ERROR (Status)) {
-        FreePool (CACert);
-        return Status;
-      }
-
-      Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
-    }
-
-    ItemDataSize -= CertList->SignatureListSize;
-    CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
-  }
-
-  FreePool (CACert);
-  return Status;
-}
-
-/**
-  Configure TLS session data.
-
-  @param[in, out]  HttpInstance       The HTTP instance private data.
-
-  @retval EFI_SUCCESS            TLS session data is configured.
-  @retval Others                 Other error as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsConfigureSession (
-  IN OUT HTTP_PROTOCOL      *HttpInstance
-  )
-{
-  EFI_STATUS                 Status;
-
-  //
-  // TlsConfigData initialization
-  //
-  HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
-  HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
-  HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
-
-  //
-  // EfiTlsConnectionEnd,
-  // EfiTlsVerifyMethod
-  // EfiTlsSessionState
-  //
-  Status = HttpInstance->Tls->SetSessionData (
-                                HttpInstance->Tls,
-                                EfiTlsConnectionEnd,
-                                &(HttpInstance->TlsConfigData.ConnectionEnd),
-                                sizeof (EFI_TLS_CONNECTION_END)
-                                );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  Status = HttpInstance->Tls->SetSessionData (
-                                HttpInstance->Tls,
-                                EfiTlsVerifyMethod,
-                                &HttpInstance->TlsConfigData.VerifyMethod,
-                                sizeof (EFI_TLS_VERIFY)
-                                );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  Status = HttpInstance->Tls->SetSessionData (
-                                HttpInstance->Tls,
-                                EfiTlsSessionState,
-                                &(HttpInstance->TlsConfigData.SessionState),
-                                sizeof (EFI_TLS_SESSION_STATE)
-                                );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Tls Config Certificate
-  //
-  Status = TlsConfigCertificate (HttpInstance);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
-    return Status;
-  }
-
-  //
-  // TlsCreateTxRxEvent
-  //
-  Status = TlsCreateTxRxEvent (HttpInstance);
-  if (EFI_ERROR (Status)) {
-    goto ERROR;
-  }
-
-  return Status;
-
-ERROR:
-  TlsCloseTxRxEvent (HttpInstance);
-
-  return Status;
-}
-
-/**
-  Transmit the Packet by processing the associated HTTPS token.
-
-  @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.
-  @param[in]        Packet          The packet to transmit.
-
-  @retval EFI_SUCCESS            The packet is transmitted.
-  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.
-  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
-  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
-  @retval Others                 Other errors as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsCommonTransmit (
-  IN OUT HTTP_PROTOCOL      *HttpInstance,
-  IN     NET_BUF            *Packet
-  )
-{
-  EFI_STATUS                Status;
-  VOID                      *Data;
-  UINTN                     Size;
-
-  if ((HttpInstance == NULL) || (Packet == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (!HttpInstance->LocalAddressIsIPv6) {
-    Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
-           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
-  } else {
-    Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
-           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
-  }
-
-  Data = AllocatePool (Size);
-  if (Data == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  if (!HttpInstance->LocalAddressIsIPv6) {
-    ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push        = TRUE;
-    ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
-    ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
-
-    //
-    // Build the fragment table.
-    //
-    ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
-
-    NetbufBuildExt (
-      Packet,
-      (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
-      &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
-      );
-
-    HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
-
-    Status = EFI_DEVICE_ERROR;
-
-    //
-    // Transmit the packet.
-    //
-    Status  = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
-    if (EFI_ERROR (Status)) {
-      goto ON_EXIT;
-    }
-
-    while (!HttpInstance->TlsIsTxDone) {
-      HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
-    }
-
-    HttpInstance->TlsIsTxDone = FALSE;
-    Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
-  } else {
-    ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push        = TRUE;
-    ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
-    ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
-
-    //
-    // Build the fragment table.
-    //
-    ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
-
-    NetbufBuildExt (
-      Packet,
-      (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
-      &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
-      );
-
-    HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
-
-    Status = EFI_DEVICE_ERROR;
-
-    //
-    // Transmit the packet.
-    //
-    Status  = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
-    if (EFI_ERROR (Status)) {
-      goto ON_EXIT;
-    }
-
-    while (!HttpInstance->TlsIsTxDone) {
-      HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
-    }
-
-    HttpInstance->TlsIsTxDone = FALSE;
-    Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
-  }
-
-ON_EXIT:
-  FreePool (Data);
-
-  return Status;
-}
-
-/**
-  Receive the Packet by processing the associated HTTPS token.
-
-  @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.
-  @param[in]        Packet          The packet to transmit.
-  @param[in]        Timeout         The time to wait for connection done.
-
-  @retval EFI_SUCCESS            The Packet is received.
-  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.
-  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
-  @retval EFI_TIMEOUT            The operation is time out.
-  @retval Others                 Other error as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsCommonReceive (
-  IN OUT HTTP_PROTOCOL      *HttpInstance,
-  IN     NET_BUF            *Packet,
-  IN     EFI_EVENT          Timeout
-  )
-{
-  EFI_TCP4_RECEIVE_DATA     *Tcp4RxData;
-  EFI_TCP6_RECEIVE_DATA     *Tcp6RxData;
-  EFI_STATUS                Status;
-  NET_FRAGMENT              *Fragment;
-  UINT32                    FragmentCount;
-  UINT32                    CurrentFragment;
-
-  Tcp4RxData = NULL;
-  Tcp6RxData = NULL;
-
-  if ((HttpInstance == NULL) || (Packet == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  FragmentCount = Packet->BlockOpNum;
-  Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
-  if (Fragment == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    goto ON_EXIT;
-  }
-
-  //
-  // Build the fragment table.
-  //
-  NetbufBuildExt (Packet, Fragment, &FragmentCount);
-
-  if (!HttpInstance->LocalAddressIsIPv6) {
-    Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
-    if (Tcp4RxData == NULL) {
-      return EFI_INVALID_PARAMETER;
-    }
-    Tcp4RxData->FragmentCount         = 1;
-  } else {
-    Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
-    if (Tcp6RxData == NULL) {
-      return EFI_INVALID_PARAMETER;
-    }
-    Tcp6RxData->FragmentCount         = 1;
-  }
-
-  CurrentFragment               = 0;
-  Status                        = EFI_SUCCESS;
-
-  while (CurrentFragment < FragmentCount) {
-    if (!HttpInstance->LocalAddressIsIPv6) {
-      Tcp4RxData->DataLength                       = Fragment[CurrentFragment].Len;
-      Tcp4RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
-      Tcp4RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
-      Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
-    } else {
-      Tcp6RxData->DataLength                       = Fragment[CurrentFragment].Len;
-      Tcp6RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
-      Tcp6RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
-      Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
-    }
-    if (EFI_ERROR (Status)) {
-      goto ON_EXIT;
-    }
-
-    while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
-      //
-      // Poll until some data is received or an error occurs.
-      //
-      if (!HttpInstance->LocalAddressIsIPv6) {
-        HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
-      } else {
-        HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
-      }
-    }
-
-    if (!HttpInstance->TlsIsRxDone) {
-      //
-      // Timeout occurs, cancel the receive request.
-      //
-      if (!HttpInstance->LocalAddressIsIPv6) {
-        HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
-      } else {
-        HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
-      }
-
-      Status = EFI_TIMEOUT;
-      goto ON_EXIT;
-    } else {
-      HttpInstance->TlsIsRxDone = FALSE;
-    }
-
-    if (!HttpInstance->LocalAddressIsIPv6) {
-      Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
-      if (EFI_ERROR (Status)) {
-        goto ON_EXIT;
-      }
-
-      Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
-      if (Fragment[CurrentFragment].Len == 0) {
-        CurrentFragment++;
-      } else {
-        Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
-      }
-    } else {
-      Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
-      if (EFI_ERROR (Status)) {
-        goto ON_EXIT;
-      }
-
-      Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
-      if (Fragment[CurrentFragment].Len == 0) {
-        CurrentFragment++;
-      } else {
-        Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
-      }
-    }
-  }
-
-ON_EXIT:
-
-  if (Fragment != NULL) {
-    FreePool (Fragment);
-  }
-
-  return Status;
-}
-
-/**
-  Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
-  corresponding record data. These two parts will be put into two blocks of buffers in the
-  net buffer.
-
-  @param[in, out]      HttpInstance    Pointer to HTTP_PROTOCOL structure.
-  @param[out]          Pdu             The received TLS PDU.
-  @param[in]           Timeout         The time to wait for connection done.
-
-  @retval EFI_SUCCESS          An TLS PDU is received.
-  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
-  @retval EFI_PROTOCOL_ERROR   An unexpected TLS packet was received.
-  @retval Others               Other errors as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsReceiveOnePdu (
-  IN OUT HTTP_PROTOCOL      *HttpInstance,
-     OUT NET_BUF            **Pdu,
-  IN     EFI_EVENT          Timeout
-  )
-{
-  EFI_STATUS      Status;
-
-  LIST_ENTRY      *NbufList;
-
-  UINT32          Len;
-
-  NET_BUF           *PduHdr;
-  UINT8             *Header;
-  TLS_RECORD_HEADER RecordHeader;
-
-  NET_BUF           *DataSeg;
-
-  NbufList = NULL;
-  PduHdr   = NULL;
-  Header   = NULL;
-  DataSeg  = NULL;
-
-  NbufList = AllocatePool (sizeof (LIST_ENTRY));
-  if (NbufList == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  InitializeListHead (NbufList);
-
-  //
-  // Allocate buffer to receive one TLS header.
-  //
-  Len     = sizeof (TLS_RECORD_HEADER);
-  PduHdr  = NetbufAlloc (Len);
-  if (PduHdr == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    goto ON_EXIT;
-  }
-
-  Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
-  if (Header == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    goto ON_EXIT;
-  }
-
-  //
-  // First step, receive one TLS header.
-  //
-  Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
-  if (EFI_ERROR (Status)) {
-    goto ON_EXIT;
-  }
-
-  RecordHeader = *(TLS_RECORD_HEADER *) Header;
-  if ((RecordHeader.ContentType == TlsContentTypeHandshake ||
-    RecordHeader.ContentType == TlsContentTypeAlert ||
-    RecordHeader.ContentType == TlsContentTypeChangeCipherSpec ||
-    RecordHeader.ContentType == TlsContentTypeApplicationData) &&
-    (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
-    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
-    RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
-    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
-   ) {
-    InsertTailList (NbufList, &PduHdr->List);
-  } else {
-    Status = EFI_PROTOCOL_ERROR;
-    goto ON_EXIT;
-  }
-
-  Len = SwapBytes16(RecordHeader.Length);
-  if (Len == 0) {
-    //
-    // No TLS payload.
-    //
-    goto FORM_PDU;
-  }
-
-  //
-  // Allocate buffer to receive one TLS payload.
-  //
-  DataSeg = NetbufAlloc (Len);
-  if (DataSeg == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    goto ON_EXIT;
-  }
-
-  NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
-
-  //
-  // Second step, receive one TLS payload.
-  //
-  Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
-  if (EFI_ERROR (Status)) {
-    goto ON_EXIT;
-  }
-
-  InsertTailList (NbufList, &DataSeg->List);
-
-FORM_PDU:
-  //
-  // Form the PDU from a list of PDU.
-  //
-  *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
-  if (*Pdu == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-  }
-
-ON_EXIT:
-
-  if (EFI_ERROR (Status)) {
-    //
-    // Free the Nbufs in this NbufList and the NbufList itself.
-    //
-    FreeNbufList (NbufList);
-  }
-
-  return Status;
-}
-
-/**
-  Connect one TLS session by finishing the TLS handshake process.
-
-  @param[in]  HttpInstance       The HTTP instance private data.
-  @param[in]  Timeout            The time to wait for connection done.
-
-  @retval EFI_SUCCESS            The TLS session is established.
-  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
-  @retval EFI_ABORTED            TLS session state is incorrect.
-  @retval Others                 Other error as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsConnectSession (
-  IN  HTTP_PROTOCOL            *HttpInstance,
-  IN  EFI_EVENT                Timeout
-  )
-{
-  EFI_STATUS              Status;
-  UINT8                   *BufferOut;
-  UINTN                   BufferOutSize;
-  NET_BUF                 *PacketOut;
-  UINT8                   *DataOut;
-  NET_BUF                 *Pdu;
-  UINT8                   *BufferIn;
-  UINTN                   BufferInSize;
-  UINT8                   *GetSessionDataBuffer;
-  UINTN                   GetSessionDataBufferSize;
-
-  BufferOut    = NULL;
-  PacketOut    = NULL;
-  DataOut      = NULL;
-  Pdu          = NULL;
-  BufferIn     = NULL;
-
-  //
-  // Initialize TLS state.
-  //
-  HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
-  Status = HttpInstance->Tls->SetSessionData (
-                                HttpInstance->Tls,
-                                EfiTlsSessionState,
-                                &(HttpInstance->TlsSessionState),
-                                sizeof (EFI_TLS_SESSION_STATE)
-                                );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Create ClientHello
-  //
-  BufferOutSize = DEF_BUF_LEN;
-  BufferOut = AllocateZeroPool (BufferOutSize);
-  if (BufferOut == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    return Status;
-  }
-
-  Status = HttpInstance->Tls->BuildResponsePacket (
-                                HttpInstance->Tls,
-                                NULL,
-                                0,
-                                BufferOut,
-                                &BufferOutSize
-                                );
-  if (Status == EFI_BUFFER_TOO_SMALL) {
-    FreePool (BufferOut);
-    BufferOut = AllocateZeroPool (BufferOutSize);
-    if (BufferOut == NULL) {
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    Status = HttpInstance->Tls->BuildResponsePacket (
-                                  HttpInstance->Tls,
-                                  NULL,
-                                  0,
-                                  BufferOut,
-                                  &BufferOutSize
-                                  );
-  }
-  if (EFI_ERROR (Status)) {
-    FreePool (BufferOut);
-    return Status;
-  }
-
-  //
-  // Transmit ClientHello
-  //
-  PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
-  DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
-  if (DataOut == NULL) {
-    FreePool (BufferOut);
-    return EFI_OUT_OF_RESOURCES;
-  }
-  
-  CopyMem (DataOut, BufferOut, BufferOutSize);
-  Status = TlsCommonTransmit (HttpInstance, PacketOut);
-
-  FreePool (BufferOut);
-  NetbufFree (PacketOut);
-
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
-    ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
-    //
-    // Receive one TLS record.
-    //
-    Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    BufferInSize = Pdu->TotalSize;
-    BufferIn = AllocateZeroPool (BufferInSize);
-    if (BufferIn == NULL) {
-      NetbufFree (Pdu);
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
-
-    NetbufFree (Pdu);
-
-    //
-    // Handle Receive data.
-    //
-    BufferOutSize = DEF_BUF_LEN;
-    BufferOut = AllocateZeroPool (BufferOutSize);
-    if (BufferOut == NULL) {
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    Status = HttpInstance->Tls->BuildResponsePacket (
-                                  HttpInstance->Tls,
-                                  BufferIn,
-                                  BufferInSize,
-                                  BufferOut,
-                                  &BufferOutSize
-                                  );
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-       FreePool (BufferOut);
-       BufferOut = AllocateZeroPool (BufferOutSize);
-       if (BufferOut == NULL) {
-         FreePool (BufferIn);
-         Status = EFI_OUT_OF_RESOURCES;
-         return Status;
-       }
-
-       Status = HttpInstance->Tls->BuildResponsePacket (
-                                     HttpInstance->Tls,
-                                     BufferIn,
-                                     BufferInSize,
-                                     BufferOut,
-                                     &BufferOutSize
-                                     );
-    }
-
-    FreePool (BufferIn);
-
-    if (EFI_ERROR (Status)) {
-      FreePool (BufferOut);
-      return Status;
-    }
-
-    if (BufferOutSize != 0) {
-      //
-      // Transmit the response packet.
-      //
-      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
-      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
-      if (DataOut == NULL) {
-        FreePool (BufferOut);
-        return EFI_OUT_OF_RESOURCES;
-      }
-      
-      CopyMem (DataOut, BufferOut, BufferOutSize);
-
-      Status = TlsCommonTransmit (HttpInstance, PacketOut);
-
-      NetbufFree (PacketOut);
-
-      if (EFI_ERROR (Status)) {
-        FreePool (BufferOut);
-        return Status;
-      }
-    }
-
-    FreePool (BufferOut);
-
-    //
-    // Get the session state, then decide whether need to continue handle received packet.
-    //
-    GetSessionDataBufferSize = DEF_BUF_LEN;
-    GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
-    if (GetSessionDataBuffer == NULL) {
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    Status = HttpInstance->Tls->GetSessionData (
-                                  HttpInstance->Tls,
-                                  EfiTlsSessionState,
-                                  GetSessionDataBuffer,
-                                  &GetSessionDataBufferSize
-                                  );
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-       FreePool (GetSessionDataBuffer);
-       GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
-       if (GetSessionDataBuffer == NULL) {
-         Status = EFI_OUT_OF_RESOURCES;
-         return Status;
-       }
-
-       Status = HttpInstance->Tls->GetSessionData (
-                                     HttpInstance->Tls,
-                                     EfiTlsSessionState,
-                                     GetSessionDataBuffer,
-                                     &GetSessionDataBufferSize
-                                     );
-    }
-    if (EFI_ERROR (Status)) {
-      FreePool(GetSessionDataBuffer);
-      return Status;
-    }
-
-    ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
-    HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
-
-    FreePool (GetSessionDataBuffer);
-
-    if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
-      return EFI_ABORTED;
-    }
-  }
-
-  if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
-    Status = EFI_ABORTED;
-  }
-
-  return Status;
-}
-
-/**
-  Close the TLS session and send out the close notification message.
-
-  @param[in]  HttpInstance       The HTTP instance private data.
-
-  @retval EFI_SUCCESS            The TLS session is closed.
-  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL.
-  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
-  @retval Others                 Other error as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsCloseSession (
-  IN  HTTP_PROTOCOL            *HttpInstance
-  )
-{
-  EFI_STATUS      Status;
-
-  UINT8           *BufferOut;
-  UINTN           BufferOutSize;
-
-  NET_BUF         *PacketOut;
-  UINT8           *DataOut;
-
-  Status    = EFI_SUCCESS;
-  BufferOut = NULL;
-  PacketOut = NULL;
-  DataOut   = NULL;
-
-  if (HttpInstance == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  HttpInstance->TlsSessionState = EfiTlsSessionClosing;
-
-  Status = HttpInstance->Tls->SetSessionData (
-                                HttpInstance->Tls,
-                                EfiTlsSessionState,
-                                &(HttpInstance->TlsSessionState),
-                                sizeof (EFI_TLS_SESSION_STATE)
-                                );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  BufferOutSize = DEF_BUF_LEN;
-  BufferOut = AllocateZeroPool (BufferOutSize);
-  if (BufferOut == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    return Status;
-  }
-
-  Status = HttpInstance->Tls->BuildResponsePacket (
-                                HttpInstance->Tls,
-                                NULL,
-                                0,
-                                BufferOut,
-                                &BufferOutSize
-                                );
-  if (Status == EFI_BUFFER_TOO_SMALL) {
-    FreePool (BufferOut);
-    BufferOut = AllocateZeroPool (BufferOutSize);
-    if (BufferOut == NULL) {
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    Status = HttpInstance->Tls->BuildResponsePacket (
-                                  HttpInstance->Tls,
-                                  NULL,
-                                  0,
-                                  BufferOut,
-                                  &BufferOutSize
-                                  );
-  }
-
-  if (EFI_ERROR (Status)) {
-    FreePool (BufferOut);
-    return Status;
-  }
-
-  PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
-  DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
-  if (DataOut == NULL) {
-    FreePool (BufferOut);
-    return EFI_OUT_OF_RESOURCES;
-  }
-  
-  CopyMem (DataOut, BufferOut, BufferOutSize);
-
-  Status = TlsCommonTransmit (HttpInstance, PacketOut);
-
-  FreePool (BufferOut);
-  NetbufFree (PacketOut);
-
-  return Status;
-}
-
-/**
-  Process one message according to the CryptMode.
-
-  @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
-  @param[in]           Message         Pointer to the message buffer needed to processed.
-  @param[in]           MessageSize     Pointer to the message buffer size.
-  @param[in]           ProcessMode     Process mode.
-  @param[in, out]      Fragment        Only one Fragment returned after the Message is
-                                       processed successfully.
-
-  @retval EFI_SUCCESS          Message is processed successfully.
-  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
-  @retval Others               Other errors as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-TlsProcessMessage (
-  IN     HTTP_PROTOCOL            *HttpInstance,
-  IN     UINT8                    *Message,
-  IN     UINTN                    MessageSize,
-  IN     EFI_TLS_CRYPT_MODE       ProcessMode,
-  IN OUT NET_FRAGMENT             *Fragment
-  )
-{
-  EFI_STATUS                      Status;
-  UINT8                           *Buffer;
-  UINT32                          BufferSize;
-  UINT32                          BytesCopied;
-  EFI_TLS_FRAGMENT_DATA           *FragmentTable;
-  UINT32                          FragmentCount;
-  EFI_TLS_FRAGMENT_DATA           *OriginalFragmentTable;
-  UINTN                           Index;
-
-  Status                   = EFI_SUCCESS;
-  Buffer                   = NULL;
-  BufferSize               = 0;
-  BytesCopied              = 0;
-  FragmentTable            = NULL;
-  OriginalFragmentTable    = NULL;
-
-  //
-  // Rebuild fragment table from BufferIn.
-  //
-  FragmentCount = 1;
-  FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
-  if (FragmentTable == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    goto ON_EXIT;
-  }
-
-  FragmentTable->FragmentLength = (UINT32) MessageSize;
-  FragmentTable->FragmentBuffer = Message;
-
-  //
-  // Record the original FragmentTable.
-  //
-  OriginalFragmentTable = FragmentTable;
-
-  //
-  // Process the Message.
-  //
-  Status = HttpInstance->Tls->ProcessPacket (
-                                HttpInstance->Tls,
-                                &FragmentTable,
-                                &FragmentCount,
-                                ProcessMode
-                                );
-  if (EFI_ERROR (Status)) {
-    goto ON_EXIT;
-  }
-
-  //
-  // Calculate the size according to FragmentTable.
-  //
-  for (Index = 0; Index < FragmentCount; Index++) {
-    BufferSize += FragmentTable[Index].FragmentLength;
-  }
-
-  //
-  // Allocate buffer for processed data.
-  //
-  Buffer = AllocateZeroPool (BufferSize);
-  if (Buffer == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    goto ON_EXIT;
-  }
-
-  //
-  // Copy the new FragmentTable buffer into Buffer.
-  //
-  for (Index = 0; Index < FragmentCount; Index++) {
-    CopyMem (
-      (Buffer + BytesCopied),
-      FragmentTable[Index].FragmentBuffer,
-      FragmentTable[Index].FragmentLength
-      );
-    BytesCopied += FragmentTable[Index].FragmentLength;
-
-    //
-    // Free the FragmentBuffer since it has been copied.
-    //
-    FreePool (FragmentTable[Index].FragmentBuffer);
-  }
-
-  Fragment->Len  = BufferSize;
-  Fragment->Bulk = Buffer;
-
-ON_EXIT:
-
-  if (OriginalFragmentTable != NULL) {
-    FreePool (OriginalFragmentTable);
-    OriginalFragmentTable = NULL;
-  }
-
-  //
-  // Caller has the responsibility to free the FragmentTable.
-  //
-  if (FragmentTable != NULL) {
-    FreePool (FragmentTable);
-    FragmentTable = NULL;
-  }
-
-  return Status;
-}
-
-/**
-  Receive one fragment decrypted from one TLS record.
-
-  @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
-  @param[in, out]      Fragment        The received Fragment.
-  @param[in]           Timeout         The time to wait for connection done.
-
-  @retval EFI_SUCCESS          One fragment is received.
-  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
-  @retval EFI_ABORTED          Something wrong decryption the message.
-  @retval Others               Other errors as indicated.
-
-**/
-EFI_STATUS
-EFIAPI
-HttpsReceive (
-  IN     HTTP_PROTOCOL         *HttpInstance,
-  IN OUT NET_FRAGMENT          *Fragment,
-  IN     EFI_EVENT             Timeout
-  )
-{
-  EFI_STATUS                      Status;
-  NET_BUF                         *Pdu;
-  TLS_RECORD_HEADER               RecordHeader;
-  UINT8                           *BufferIn;
-  UINTN                           BufferInSize;
-  NET_FRAGMENT                    TempFragment;
-  UINT8                           *BufferOut;
-  UINTN                           BufferOutSize;
-  NET_BUF                         *PacketOut;
-  UINT8                           *DataOut;
-  UINT8                           *GetSessionDataBuffer;
-  UINTN                           GetSessionDataBufferSize;
-
-  Status                   = EFI_SUCCESS;
-  Pdu                      = NULL;
-  BufferIn                 = NULL;
-  BufferInSize             = 0;
-  BufferOut                = NULL;
-  BufferOutSize            = 0;
-  PacketOut                = NULL;
-  DataOut                  = NULL;
-  GetSessionDataBuffer     = NULL;
-  GetSessionDataBufferSize = 0;
-
-  //
-  // Receive only one TLS record
-  //
-  Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  BufferInSize = Pdu->TotalSize;
-  BufferIn = AllocateZeroPool (BufferInSize);
-  if (BufferIn == NULL) {
-    Status = EFI_OUT_OF_RESOURCES;
-    NetbufFree (Pdu);
-    return Status;
-  }
-
-  NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
-
-  NetbufFree (Pdu);
-
-  //
-  // Handle Receive data.
-  //
-  RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
-
-  if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
-    (RecordHeader.Version.Major == 0x03) &&
-    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
-    RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
-    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
-  ) {
-    //
-    // Decrypt Packet.
-    //
-    Status = TlsProcessMessage (
-               HttpInstance,
-               BufferIn,
-               BufferInSize,
-               EfiTlsDecrypt,
-               &TempFragment
-               );
-
-    FreePool (BufferIn);
-
-    if (EFI_ERROR (Status)) {
-      if (Status == EFI_ABORTED) {
-        //
-        // Something wrong decryption the message.
-        // BuildResponsePacket() will be called to generate Error Alert message and send it out.
-        //
-        BufferOutSize = DEF_BUF_LEN;
-        BufferOut = AllocateZeroPool (BufferOutSize);
-        if (BufferOut == NULL) {
-          Status = EFI_OUT_OF_RESOURCES;
-          return Status;
-        }
-
-        Status = HttpInstance->Tls->BuildResponsePacket (
-                                      HttpInstance->Tls,
-                                      NULL,
-                                      0,
-                                      BufferOut,
-                                      &BufferOutSize
-                                      );
-        if (Status == EFI_BUFFER_TOO_SMALL) {
-          FreePool (BufferOut);
-          BufferOut = AllocateZeroPool (BufferOutSize);
-          if (BufferOut == NULL) {
-            Status = EFI_OUT_OF_RESOURCES;
-            return Status;
-          }
-
-          Status = HttpInstance->Tls->BuildResponsePacket (
-                                        HttpInstance->Tls,
-                                        NULL,
-                                        0,
-                                        BufferOut,
-                                        &BufferOutSize
-                                        );
-        }
-        if (EFI_ERROR (Status)) {
-          FreePool(BufferOut);
-          return Status;
-        }
-
-        if (BufferOutSize != 0) {
-          PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
-          DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
-          if (DataOut == NULL) {
-            FreePool (BufferOut);
-            return EFI_OUT_OF_RESOURCES;
-          }
-          
-          CopyMem (DataOut, BufferOut, BufferOutSize);
-
-          Status = TlsCommonTransmit (HttpInstance, PacketOut);
-
-          NetbufFree (PacketOut);
-        }
-
-        FreePool(BufferOut);
-
-        if (EFI_ERROR (Status)) {
-          return Status;
-        }
-
-        return EFI_ABORTED;
-      }
-
-      return Status;
-    }
-
-    //
-    // Parsing buffer.
-    //
-    ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);
-
-    BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
-    BufferIn = AllocateZeroPool (BufferInSize);
-    if (BufferIn == NULL) {
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
-
-    //
-    // Free the buffer in TempFragment.
-    //
-    FreePool (TempFragment.Bulk);
-
-  } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
-    (RecordHeader.Version.Major == 0x03) &&
-    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
-    RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
-    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
-    ) {
-    BufferOutSize = DEF_BUF_LEN;
-    BufferOut = AllocateZeroPool (BufferOutSize);
-    if (BufferOut == NULL) {
-      FreePool (BufferIn);
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    Status = HttpInstance->Tls->BuildResponsePacket (
-                                  HttpInstance->Tls,
-                                  BufferIn,
-                                  BufferInSize,
-                                  BufferOut,
-                                  &BufferOutSize
-                                  );
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-      FreePool (BufferOut);
-      BufferOut = AllocateZeroPool (BufferOutSize);
-      if (BufferOut == NULL) {
-        FreePool (BufferIn);
-        Status = EFI_OUT_OF_RESOURCES;
-        return Status;
-      }
-
-      Status = HttpInstance->Tls->BuildResponsePacket (
-                                    HttpInstance->Tls,
-                                    BufferIn,
-                                    BufferInSize,
-                                    BufferOut,
-                                    &BufferOutSize
-                                    );
-    }
-
-    FreePool (BufferIn);
-
-    if (EFI_ERROR (Status)) {
-      FreePool (BufferOut);
-      return Status;
-    }
-
-    if (BufferOutSize != 0) {
-      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
-      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
-      if (DataOut == NULL) {
-        FreePool (BufferOut);
-        return EFI_OUT_OF_RESOURCES;
-      }
-      
-      CopyMem (DataOut, BufferOut, BufferOutSize);
-
-      Status = TlsCommonTransmit (HttpInstance, PacketOut);
-
-      NetbufFree (PacketOut);
-    }
-
-    FreePool (BufferOut);
-
-    //
-    // Get the session state.
-    //
-    GetSessionDataBufferSize = DEF_BUF_LEN;
-    GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
-    if (GetSessionDataBuffer == NULL) {
-      Status = EFI_OUT_OF_RESOURCES;
-      return Status;
-    }
-
-    Status = HttpInstance->Tls->GetSessionData (
-                                  HttpInstance->Tls,
-                                  EfiTlsSessionState,
-                                  GetSessionDataBuffer,
-                                  &GetSessionDataBufferSize
-                                  );
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-       FreePool (GetSessionDataBuffer);
-       GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
-       if (GetSessionDataBuffer == NULL) {
-         Status = EFI_OUT_OF_RESOURCES;
-         return Status;
-       }
-
-       Status = HttpInstance->Tls->GetSessionData (
-                                     HttpInstance->Tls,
-                                     EfiTlsSessionState,
-                                     GetSessionDataBuffer,
-                                     &GetSessionDataBufferSize
-                                     );
-    }
-    if (EFI_ERROR (Status)) {
-      FreePool (GetSessionDataBuffer);
-      return Status;
-    }
-
-    ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
-    HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
-
-    FreePool (GetSessionDataBuffer);
-
-    if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
-      DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
-      return EFI_ABORTED;
-    }
-
-    BufferIn = NULL;
-    BufferInSize = 0;
-  }
-
-  Fragment->Bulk = BufferIn;
-  Fragment->Len = (UINT32) BufferInSize;
-
-  return Status;
-}
+/** @file\r
+  Miscellaneous routines specific to Https for HttpDxe driver.\r
+\r
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HttpDriver.h"\r
+\r
+/**\r
+  Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated\r
+  ASCII string and ignore case during the search process.\r
+\r
+  This function scans the contents of the ASCII string specified by String\r
+  and returns the first occurrence of SearchString and ignore case during the search process.\r
+  If SearchString is not found in String, then NULL is returned. If the length of SearchString\r
+  is zero, then String is returned.\r
+\r
+  If String is NULL, then ASSERT().\r
+  If SearchString is NULL, then ASSERT().\r
+\r
+  @param[in]  String          A pointer to a Null-terminated ASCII string.\r
+  @param[in]  SearchString    A pointer to a Null-terminated ASCII string to search for.\r
+\r
+  @retval NULL            If the SearchString does not appear in String.\r
+  @retval others          If there is a match return the first occurrence of SearchingString.\r
+                          If the length of SearchString is zero,return String.\r
+\r
+**/\r
+CHAR8 *\r
+AsciiStrCaseStr (\r
+  IN      CONST CHAR8               *String,\r
+  IN      CONST CHAR8               *SearchString\r
+  )\r
+{\r
+  CONST CHAR8 *FirstMatch;\r
+  CONST CHAR8 *SearchStringTmp;\r
+\r
+  CHAR8 Src;\r
+  CHAR8 Dst;\r
+\r
+  //\r
+  // ASSERT both strings are less long than PcdMaximumAsciiStringLength\r
+  //\r
+  ASSERT (AsciiStrSize (String) != 0);\r
+  ASSERT (AsciiStrSize (SearchString) != 0);\r
+\r
+  if (*SearchString == '\0') {\r
+    return (CHAR8 *) String;\r
+  }\r
+\r
+  while (*String != '\0') {\r
+    SearchStringTmp = SearchString;\r
+    FirstMatch = String;\r
+\r
+    while ((*SearchStringTmp != '\0')\r
+            && (*String != '\0')) {\r
+      Src = *String;\r
+      Dst = *SearchStringTmp;\r
+\r
+      if ((Src >= 'A') && (Src <= 'Z')) {\r
+        Src -= ('A' - 'a');\r
+      }\r
+\r
+      if ((Dst >= 'A') && (Dst <= 'Z')) {\r
+        Dst -= ('A' - 'a');\r
+      }\r
+\r
+      if (Src != Dst) {\r
+        break;\r
+      }\r
+\r
+      String++;\r
+      SearchStringTmp++;\r
+    }\r
+\r
+    if (*SearchStringTmp == '\0') {\r
+      return (CHAR8 *) FirstMatch;\r
+    }\r
+\r
+    String = FirstMatch + 1;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  The callback function to free the net buffer list.\r
+\r
+  @param[in]  Arg The opaque parameter.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreeNbufList (\r
+  IN VOID *Arg\r
+  )\r
+{\r
+  ASSERT (Arg != NULL);\r
+\r
+  NetbufFreeList ((LIST_ENTRY *) Arg);\r
+  FreePool (Arg);\r
+}\r
+\r
+/**\r
+  Check whether the Url is from Https.\r
+\r
+  @param[in]    Url             The pointer to a HTTP or HTTPS URL string.\r
+\r
+  @retval TRUE                  The Url is from HTTPS.\r
+  @retval FALSE                 The Url is from HTTP.\r
+\r
+**/\r
+BOOLEAN\r
+IsHttpsUrl (\r
+  IN CHAR8    *Url\r
+  )\r
+{\r
+  CHAR8  *Tmp;\r
+\r
+  Tmp = NULL;\r
+\r
+  Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);\r
+  if (Tmp != NULL && Tmp == Url) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.\r
+\r
+  @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.\r
+  @param[out] TlsProto              Pointer to the EFI_TLS_PROTOCOL instance.\r
+  @param[out] TlsConfiguration      Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.\r
+\r
+  @return  The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.\r
+\r
+**/\r
+EFI_HANDLE\r
+EFIAPI\r
+TlsCreateChild (\r
+  IN  EFI_HANDLE                     ImageHandle,\r
+  OUT EFI_TLS_PROTOCOL               **TlsProto,\r
+  OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_SERVICE_BINDING_PROTOCOL  *TlsSb;\r
+  EFI_HANDLE                    TlsChildHandle;\r
+\r
+  TlsSb          = NULL;\r
+  TlsChildHandle = 0;\r
+\r
+  //\r
+  // Locate TlsServiceBinding protocol.\r
+  //\r
+  gBS->LocateProtocol (\r
+     &gEfiTlsServiceBindingProtocolGuid,\r
+     NULL,\r
+     (VOID **) &TlsSb\r
+     );\r
+  if (TlsSb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = TlsSb->CreateChild (TlsSb, &TlsChildHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  TlsChildHandle,\r
+                  &gEfiTlsProtocolGuid,\r
+                  (VOID **) TlsProto,\r
+                  ImageHandle,\r
+                  TlsChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    TlsSb->DestroyChild (TlsSb, TlsChildHandle);\r
+    return NULL;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  TlsChildHandle,\r
+                  &gEfiTlsConfigurationProtocolGuid,\r
+                  (VOID **) TlsConfiguration,\r
+                  ImageHandle,\r
+                  TlsChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    TlsSb->DestroyChild (TlsSb, TlsChildHandle);\r
+    return NULL;\r
+  }\r
+\r
+  return TlsChildHandle;\r
+}\r
+\r
+/**\r
+  Create event for the TLS receive and transmit tokens which are used to receive and\r
+  transmit TLS related messages.\r
+\r
+  @param[in, out]  HttpInstance       Pointer to HTTP_PROTOCOL structure.\r
+\r
+  @retval EFI_SUCCESS            The events are created successfully.\r
+  @retval others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsCreateTxRxEvent (\r
+  IN OUT HTTP_PROTOCOL      *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    //\r
+    // For Tcp4TlsTxToken.\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->TlsIsTxDone,\r
+                    &HttpInstance->Tcp4TlsTxToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+\r
+    HttpInstance->Tcp4TlsTxData.Push = TRUE;\r
+    HttpInstance->Tcp4TlsTxData.Urgent = FALSE;\r
+    HttpInstance->Tcp4TlsTxData.DataLength = 0;\r
+    HttpInstance->Tcp4TlsTxData.FragmentCount = 1;\r
+    HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;\r
+    HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;\r
+    HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;\r
+    HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;\r
+\r
+    //\r
+    // For Tcp4TlsRxToken.\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->TlsIsRxDone,\r
+                    &HttpInstance->Tcp4TlsRxToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+\r
+    HttpInstance->Tcp4TlsRxData.DataLength                       = 0;\r
+    HttpInstance->Tcp4TlsRxData.FragmentCount                    = 1;\r
+    HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp4TlsRxData.DataLength ;\r
+    HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;\r
+    HttpInstance->Tcp4TlsRxToken.Packet.RxData          = &HttpInstance->Tcp4TlsRxData;\r
+    HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;\r
+  } else {\r
+    //\r
+    // For Tcp6TlsTxToken.\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->TlsIsTxDone,\r
+                    &HttpInstance->Tcp6TlsTxToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+\r
+    HttpInstance->Tcp6TlsTxData.Push = TRUE;\r
+    HttpInstance->Tcp6TlsTxData.Urgent = FALSE;\r
+    HttpInstance->Tcp6TlsTxData.DataLength = 0;\r
+    HttpInstance->Tcp6TlsTxData.FragmentCount = 1;\r
+    HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;\r
+    HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;\r
+    HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;\r
+    HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;\r
+\r
+    //\r
+    // For Tcp6TlsRxToken.\r
+    //\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    HttpCommonNotify,\r
+                    &HttpInstance->TlsIsRxDone,\r
+                    &HttpInstance->Tcp6TlsRxToken.CompletionToken.Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR;\r
+    }\r
+\r
+    HttpInstance->Tcp6TlsRxData.DataLength                       = 0;\r
+    HttpInstance->Tcp6TlsRxData.FragmentCount                    = 1;\r
+    HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp6TlsRxData.DataLength ;\r
+    HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;\r
+    HttpInstance->Tcp6TlsRxToken.Packet.RxData          = &HttpInstance->Tcp6TlsRxData;\r
+    HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;\r
+  }\r
+\r
+  return Status;\r
+\r
+ERROR:\r
+  //\r
+  // Error handling\r
+  //\r
+  TlsCloseTxRxEvent (HttpInstance);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Close events in the TlsTxToken and TlsRxToken.\r
+\r
+  @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TlsCloseTxRxEvent (\r
+  IN  HTTP_PROTOCOL        *HttpInstance\r
+  )\r
+{\r
+  ASSERT (HttpInstance != NULL);\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {\r
+      gBS->CloseEvent(HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);\r
+      HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;\r
+    }\r
+\r
+    if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {\r
+      gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);\r
+      HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;\r
+    }\r
+  } else {\r
+    if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {\r
+      gBS->CloseEvent(HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);\r
+      HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;\r
+    }\r
+\r
+    if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {\r
+      gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);\r
+      HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Read the TlsCaCertificate variable and configure it.\r
+\r
+  @param[in, out]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            TlsCaCertificate is configured.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_NOT_FOUND          Fail to get 'TlsCaCertificate' variable.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+TlsConfigCertificate (\r
+  IN OUT HTTP_PROTOCOL      *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               *CACert;\r
+  UINTN               CACertSize;\r
+  UINT32              Index;\r
+  EFI_SIGNATURE_LIST  *CertList;\r
+  EFI_SIGNATURE_DATA  *Cert;\r
+  UINTN               CertCount;\r
+  UINT32              ItemDataSize;\r
+\r
+  CACert     = NULL;\r
+  CACertSize = 0;\r
+\r
+  //\r
+  // Try to read the TlsCaCertificate variable.\r
+  //\r
+  Status  = gRT->GetVariable (\r
+                   EFI_TLS_CA_CERTIFICATE_VARIABLE,\r
+                   &gEfiTlsCaCertificateGuid,\r
+                   NULL,\r
+                   &CACertSize,\r
+                   NULL\r
+                   );\r
+\r
+  if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer and read the config variable.\r
+  //\r
+  CACert = AllocatePool (CACertSize);\r
+  if (CACert == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = gRT->GetVariable (\r
+                  EFI_TLS_CA_CERTIFICATE_VARIABLE,\r
+                  &gEfiTlsCaCertificateGuid,\r
+                  NULL,\r
+                  &CACertSize,\r
+                  CACert\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // GetVariable still error or the variable is corrupted.\r
+    // Fall back to the default value.\r
+    //\r
+    FreePool (CACert);\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ASSERT (CACert != NULL);\r
+\r
+  //\r
+  // Enumerate all data and erasing the target item.\r
+  //\r
+  ItemDataSize = (UINT32) CACertSize;\r
+  CertList = (EFI_SIGNATURE_LIST *) CACert;\r
+  while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {\r
+    Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+    CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+    for (Index = 0; Index < CertCount; Index++) {\r
+      //\r
+      // EfiTlsConfigDataTypeCACertificate\r
+      //\r
+      Status = HttpInstance->TlsConfiguration->SetData (\r
+                                                 HttpInstance->TlsConfiguration,\r
+                                                 EfiTlsConfigDataTypeCACertificate,\r
+                                                 Cert->SignatureData,\r
+                                                 CertList->SignatureSize - sizeof (Cert->SignatureOwner)\r
+                                                 );\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (CACert);\r
+        return Status;\r
+      }\r
+\r
+      Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+    }\r
+\r
+    ItemDataSize -= CertList->SignatureListSize;\r
+    CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+  }\r
+\r
+  FreePool (CACert);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Configure TLS session data.\r
+\r
+  @param[in, out]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            TLS session data is configured.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsConfigureSession (\r
+  IN OUT HTTP_PROTOCOL      *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+\r
+  //\r
+  // TlsConfigData initialization\r
+  //\r
+  HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;\r
+  HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;\r
+  HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;\r
+\r
+  //\r
+  // EfiTlsConnectionEnd,\r
+  // EfiTlsVerifyMethod\r
+  // EfiTlsSessionState\r
+  //\r
+  Status = HttpInstance->Tls->SetSessionData (\r
+                                HttpInstance->Tls,\r
+                                EfiTlsConnectionEnd,\r
+                                &(HttpInstance->TlsConfigData.ConnectionEnd),\r
+                                sizeof (EFI_TLS_CONNECTION_END)\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpInstance->Tls->SetSessionData (\r
+                                HttpInstance->Tls,\r
+                                EfiTlsVerifyMethod,\r
+                                &HttpInstance->TlsConfigData.VerifyMethod,\r
+                                sizeof (EFI_TLS_VERIFY)\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpInstance->Tls->SetSessionData (\r
+                                HttpInstance->Tls,\r
+                                EfiTlsSessionState,\r
+                                &(HttpInstance->TlsConfigData.SessionState),\r
+                                sizeof (EFI_TLS_SESSION_STATE)\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Tls Config Certificate\r
+  //\r
+  Status = TlsConfigCertificate (HttpInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // TlsCreateTxRxEvent\r
+  //\r
+  Status = TlsCreateTxRxEvent (HttpInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR;\r
+  }\r
+\r
+  return Status;\r
+\r
+ERROR:\r
+  TlsCloseTxRxEvent (HttpInstance);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Transmit the Packet by processing the associated HTTPS token.\r
+\r
+  @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]        Packet          The packet to transmit.\r
+\r
+  @retval EFI_SUCCESS            The packet is transmitted.\r
+  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsCommonTransmit (\r
+  IN OUT HTTP_PROTOCOL      *HttpInstance,\r
+  IN     NET_BUF            *Packet\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VOID                      *Data;\r
+  UINTN                     Size;\r
+\r
+  if ((HttpInstance == NULL) || (Packet == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +\r
+           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);\r
+  } else {\r
+    Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +\r
+           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);\r
+  }\r
+\r
+  Data = AllocatePool (Size);\r
+  if (Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push        = TRUE;\r
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent      = FALSE;\r
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;\r
+\r
+    //\r
+    // Build the fragment table.\r
+    //\r
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;\r
+\r
+    NetbufBuildExt (\r
+      Packet,\r
+      (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],\r
+      &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount\r
+      );\r
+\r
+    HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+\r
+    //\r
+    // Transmit the packet.\r
+    //\r
+    Status  = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    while (!HttpInstance->TlsIsTxDone) {\r
+      HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+    }\r
+\r
+    HttpInstance->TlsIsTxDone = FALSE;\r
+    Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;\r
+  } else {\r
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push        = TRUE;\r
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent      = FALSE;\r
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;\r
+\r
+    //\r
+    // Build the fragment table.\r
+    //\r
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;\r
+\r
+    NetbufBuildExt (\r
+      Packet,\r
+      (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],\r
+      &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount\r
+      );\r
+\r
+    HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+\r
+    //\r
+    // Transmit the packet.\r
+    //\r
+    Status  = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    while (!HttpInstance->TlsIsTxDone) {\r
+      HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
+    }\r
+\r
+    HttpInstance->TlsIsTxDone = FALSE;\r
+    Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;\r
+  }\r
+\r
+ON_EXIT:\r
+  FreePool (Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive the Packet by processing the associated HTTPS token.\r
+\r
+  @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]        Packet          The packet to transmit.\r
+  @param[in]        Timeout         The time to wait for connection done.\r
+\r
+  @retval EFI_SUCCESS            The Packet is received.\r
+  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_TIMEOUT            The operation is time out.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsCommonReceive (\r
+  IN OUT HTTP_PROTOCOL      *HttpInstance,\r
+  IN     NET_BUF            *Packet,\r
+  IN     EFI_EVENT          Timeout\r
+  )\r
+{\r
+  EFI_TCP4_RECEIVE_DATA     *Tcp4RxData;\r
+  EFI_TCP6_RECEIVE_DATA     *Tcp6RxData;\r
+  EFI_STATUS                Status;\r
+  NET_FRAGMENT              *Fragment;\r
+  UINT32                    FragmentCount;\r
+  UINT32                    CurrentFragment;\r
+\r
+  Tcp4RxData = NULL;\r
+  Tcp6RxData = NULL;\r
+\r
+  if ((HttpInstance == NULL) || (Packet == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FragmentCount = Packet->BlockOpNum;\r
+  Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));\r
+  if (Fragment == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Build the fragment table.\r
+  //\r
+  NetbufBuildExt (Packet, Fragment, &FragmentCount);\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;\r
+    if (Tcp4RxData == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    Tcp4RxData->FragmentCount         = 1;\r
+  } else {\r
+    Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;\r
+    if (Tcp6RxData == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    Tcp6RxData->FragmentCount         = 1;\r
+  }\r
+\r
+  CurrentFragment               = 0;\r
+  Status                        = EFI_SUCCESS;\r
+\r
+  while (CurrentFragment < FragmentCount) {\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      Tcp4RxData->DataLength                       = Fragment[CurrentFragment].Len;\r
+      Tcp4RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;\r
+      Tcp4RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;\r
+      Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);\r
+    } else {\r
+      Tcp6RxData->DataLength                       = Fragment[CurrentFragment].Len;\r
+      Tcp6RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;\r
+      Tcp6RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;\r
+      Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+      //\r
+      // Poll until some data is received or an error occurs.\r
+      //\r
+      if (!HttpInstance->LocalAddressIsIPv6) {\r
+        HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
+      } else {\r
+        HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);\r
+      }\r
+    }\r
+\r
+    if (!HttpInstance->TlsIsRxDone) {\r
+      //\r
+      // Timeout occurs, cancel the receive request.\r
+      //\r
+      if (!HttpInstance->LocalAddressIsIPv6) {\r
+        HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);\r
+      } else {\r
+        HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);\r
+      }\r
+\r
+      Status = EFI_TIMEOUT;\r
+      goto ON_EXIT;\r
+    } else {\r
+      HttpInstance->TlsIsRxDone = FALSE;\r
+    }\r
+\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;\r
+      if (Fragment[CurrentFragment].Len == 0) {\r
+        CurrentFragment++;\r
+      } else {\r
+        Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;\r
+      }\r
+    } else {\r
+      Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;\r
+      if (Fragment[CurrentFragment].Len == 0) {\r
+        CurrentFragment++;\r
+      } else {\r
+        Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;\r
+      }\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  if (Fragment != NULL) {\r
+    FreePool (Fragment);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive one TLS PDU. An TLS PDU contains an TLS record header and it's\r
+  corresponding record data. These two parts will be put into two blocks of buffers in the\r
+  net buffer.\r
+\r
+  @param[in, out]      HttpInstance    Pointer to HTTP_PROTOCOL structure.\r
+  @param[out]          Pdu             The received TLS PDU.\r
+  @param[in]           Timeout         The time to wait for connection done.\r
+\r
+  @retval EFI_SUCCESS          An TLS PDU is received.\r
+  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+  @retval EFI_PROTOCOL_ERROR   An unexpected TLS packet was received.\r
+  @retval Others               Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsReceiveOnePdu (\r
+  IN OUT HTTP_PROTOCOL      *HttpInstance,\r
+     OUT NET_BUF            **Pdu,\r
+  IN     EFI_EVENT          Timeout\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+\r
+  LIST_ENTRY      *NbufList;\r
+\r
+  UINT32          Len;\r
+\r
+  NET_BUF           *PduHdr;\r
+  UINT8             *Header;\r
+  TLS_RECORD_HEADER RecordHeader;\r
+\r
+  NET_BUF           *DataSeg;\r
+\r
+  NbufList = NULL;\r
+  PduHdr   = NULL;\r
+  Header   = NULL;\r
+  DataSeg  = NULL;\r
+\r
+  NbufList = AllocatePool (sizeof (LIST_ENTRY));\r
+  if (NbufList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  InitializeListHead (NbufList);\r
+\r
+  //\r
+  // Allocate buffer to receive one TLS header.\r
+  //\r
+  Len     = sizeof (TLS_RECORD_HEADER);\r
+  PduHdr  = NetbufAlloc (Len);\r
+  if (PduHdr == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);\r
+  if (Header == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // First step, receive one TLS header.\r
+  //\r
+  Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  RecordHeader = *(TLS_RECORD_HEADER *) Header;\r
+  if ((RecordHeader.ContentType == TlsContentTypeHandshake ||\r
+    RecordHeader.ContentType == TlsContentTypeAlert ||\r
+    RecordHeader.ContentType == TlsContentTypeChangeCipherSpec ||\r
+    RecordHeader.ContentType == TlsContentTypeApplicationData) &&\r
+    (RecordHeader.Version.Major == 0x03) && /// Major versions are same.\r
+    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||\r
+    RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||\r
+    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)\r
+   ) {\r
+    InsertTailList (NbufList, &PduHdr->List);\r
+  } else {\r
+    Status = EFI_PROTOCOL_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Len = SwapBytes16(RecordHeader.Length);\r
+  if (Len == 0) {\r
+    //\r
+    // No TLS payload.\r
+    //\r
+    goto FORM_PDU;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer to receive one TLS payload.\r
+  //\r
+  DataSeg = NetbufAlloc (Len);\r
+  if (DataSeg == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);\r
+\r
+  //\r
+  // Second step, receive one TLS payload.\r
+  //\r
+  Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  InsertTailList (NbufList, &DataSeg->List);\r
+\r
+FORM_PDU:\r
+  //\r
+  // Form the PDU from a list of PDU.\r
+  //\r
+  *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);\r
+  if (*Pdu == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Free the Nbufs in this NbufList and the NbufList itself.\r
+    //\r
+    FreeNbufList (NbufList);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Connect one TLS session by finishing the TLS handshake process.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+  @param[in]  Timeout            The time to wait for connection done.\r
+\r
+  @retval EFI_SUCCESS            The TLS session is established.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_ABORTED            TLS session state is incorrect.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsConnectSession (\r
+  IN  HTTP_PROTOCOL            *HttpInstance,\r
+  IN  EFI_EVENT                Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT8                   *BufferOut;\r
+  UINTN                   BufferOutSize;\r
+  NET_BUF                 *PacketOut;\r
+  UINT8                   *DataOut;\r
+  NET_BUF                 *Pdu;\r
+  UINT8                   *BufferIn;\r
+  UINTN                   BufferInSize;\r
+  UINT8                   *GetSessionDataBuffer;\r
+  UINTN                   GetSessionDataBufferSize;\r
+\r
+  BufferOut    = NULL;\r
+  PacketOut    = NULL;\r
+  DataOut      = NULL;\r
+  Pdu          = NULL;\r
+  BufferIn     = NULL;\r
+\r
+  //\r
+  // Initialize TLS state.\r
+  //\r
+  HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;\r
+  Status = HttpInstance->Tls->SetSessionData (\r
+                                HttpInstance->Tls,\r
+                                EfiTlsSessionState,\r
+                                &(HttpInstance->TlsSessionState),\r
+                                sizeof (EFI_TLS_SESSION_STATE)\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Create ClientHello\r
+  //\r
+  BufferOutSize = DEF_BUF_LEN;\r
+  BufferOut = AllocateZeroPool (BufferOutSize);\r
+  if (BufferOut == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                HttpInstance->Tls,\r
+                                NULL,\r
+                                0,\r
+                                BufferOut,\r
+                                &BufferOutSize\r
+                                );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FreePool (BufferOut);\r
+    BufferOut = AllocateZeroPool (BufferOutSize);\r
+    if (BufferOut == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                  HttpInstance->Tls,\r
+                                  NULL,\r
+                                  0,\r
+                                  BufferOut,\r
+                                  &BufferOutSize\r
+                                  );\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (BufferOut);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Transmit ClientHello\r
+  //\r
+  PacketOut = NetbufAlloc ((UINT32) BufferOutSize);\r
+  DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);\r
+  if (DataOut == NULL) {\r
+    FreePool (BufferOut);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopyMem (DataOut, BufferOut, BufferOutSize);\r
+  Status = TlsCommonTransmit (HttpInstance, PacketOut);\r
+\r
+  FreePool (BufferOut);\r
+  NetbufFree (PacketOut);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \\r
+    ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+    //\r
+    // Receive one TLS record.\r
+    //\r
+    Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    BufferInSize = Pdu->TotalSize;\r
+    BufferIn = AllocateZeroPool (BufferInSize);\r
+    if (BufferIn == NULL) {\r
+      NetbufFree (Pdu);\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);\r
+\r
+    NetbufFree (Pdu);\r
+\r
+    //\r
+    // Handle Receive data.\r
+    //\r
+    BufferOutSize = DEF_BUF_LEN;\r
+    BufferOut = AllocateZeroPool (BufferOutSize);\r
+    if (BufferOut == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                  HttpInstance->Tls,\r
+                                  BufferIn,\r
+                                  BufferInSize,\r
+                                  BufferOut,\r
+                                  &BufferOutSize\r
+                                  );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+       FreePool (BufferOut);\r
+       BufferOut = AllocateZeroPool (BufferOutSize);\r
+       if (BufferOut == NULL) {\r
+         FreePool (BufferIn);\r
+         Status = EFI_OUT_OF_RESOURCES;\r
+         return Status;\r
+       }\r
+\r
+       Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                     HttpInstance->Tls,\r
+                                     BufferIn,\r
+                                     BufferInSize,\r
+                                     BufferOut,\r
+                                     &BufferOutSize\r
+                                     );\r
+    }\r
+\r
+    FreePool (BufferIn);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (BufferOut);\r
+      return Status;\r
+    }\r
+\r
+    if (BufferOutSize != 0) {\r
+      //\r
+      // Transmit the response packet.\r
+      //\r
+      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);\r
+      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);\r
+      if (DataOut == NULL) {\r
+        FreePool (BufferOut);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      CopyMem (DataOut, BufferOut, BufferOutSize);\r
+\r
+      Status = TlsCommonTransmit (HttpInstance, PacketOut);\r
+\r
+      NetbufFree (PacketOut);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (BufferOut);\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    FreePool (BufferOut);\r
+\r
+    //\r
+    // Get the session state, then decide whether need to continue handle received packet.\r
+    //\r
+    GetSessionDataBufferSize = DEF_BUF_LEN;\r
+    GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);\r
+    if (GetSessionDataBuffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    Status = HttpInstance->Tls->GetSessionData (\r
+                                  HttpInstance->Tls,\r
+                                  EfiTlsSessionState,\r
+                                  GetSessionDataBuffer,\r
+                                  &GetSessionDataBufferSize\r
+                                  );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+       FreePool (GetSessionDataBuffer);\r
+       GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);\r
+       if (GetSessionDataBuffer == NULL) {\r
+         Status = EFI_OUT_OF_RESOURCES;\r
+         return Status;\r
+       }\r
+\r
+       Status = HttpInstance->Tls->GetSessionData (\r
+                                     HttpInstance->Tls,\r
+                                     EfiTlsSessionState,\r
+                                     GetSessionDataBuffer,\r
+                                     &GetSessionDataBufferSize\r
+                                     );\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool(GetSessionDataBuffer);\r
+      return Status;\r
+    }\r
+\r
+    ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));\r
+    HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;\r
+\r
+    FreePool (GetSessionDataBuffer);\r
+\r
+    if(HttpInstance->TlsSessionState == EfiTlsSessionError) {\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+\r
+  if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {\r
+    Status = EFI_ABORTED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Close the TLS session and send out the close notification message.\r
+\r
+  @param[in]  HttpInstance       The HTTP instance private data.\r
+\r
+  @retval EFI_SUCCESS            The TLS session is closed.\r
+  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval Others                 Other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsCloseSession (\r
+  IN  HTTP_PROTOCOL            *HttpInstance\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+\r
+  UINT8           *BufferOut;\r
+  UINTN           BufferOutSize;\r
+\r
+  NET_BUF         *PacketOut;\r
+  UINT8           *DataOut;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  BufferOut = NULL;\r
+  PacketOut = NULL;\r
+  DataOut   = NULL;\r
+\r
+  if (HttpInstance == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  HttpInstance->TlsSessionState = EfiTlsSessionClosing;\r
+\r
+  Status = HttpInstance->Tls->SetSessionData (\r
+                                HttpInstance->Tls,\r
+                                EfiTlsSessionState,\r
+                                &(HttpInstance->TlsSessionState),\r
+                                sizeof (EFI_TLS_SESSION_STATE)\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BufferOutSize = DEF_BUF_LEN;\r
+  BufferOut = AllocateZeroPool (BufferOutSize);\r
+  if (BufferOut == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    return Status;\r
+  }\r
+\r
+  Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                HttpInstance->Tls,\r
+                                NULL,\r
+                                0,\r
+                                BufferOut,\r
+                                &BufferOutSize\r
+                                );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FreePool (BufferOut);\r
+    BufferOut = AllocateZeroPool (BufferOutSize);\r
+    if (BufferOut == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                  HttpInstance->Tls,\r
+                                  NULL,\r
+                                  0,\r
+                                  BufferOut,\r
+                                  &BufferOutSize\r
+                                  );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (BufferOut);\r
+    return Status;\r
+  }\r
+\r
+  PacketOut = NetbufAlloc ((UINT32) BufferOutSize);\r
+  DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);\r
+  if (DataOut == NULL) {\r
+    FreePool (BufferOut);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopyMem (DataOut, BufferOut, BufferOutSize);\r
+\r
+  Status = TlsCommonTransmit (HttpInstance, PacketOut);\r
+\r
+  FreePool (BufferOut);\r
+  NetbufFree (PacketOut);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process one message according to the CryptMode.\r
+\r
+  @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.\r
+  @param[in]           Message         Pointer to the message buffer needed to processed.\r
+  @param[in]           MessageSize     Pointer to the message buffer size.\r
+  @param[in]           ProcessMode     Process mode.\r
+  @param[in, out]      Fragment        Only one Fragment returned after the Message is\r
+                                       processed successfully.\r
+\r
+  @retval EFI_SUCCESS          Message is processed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval Others               Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsProcessMessage (\r
+  IN     HTTP_PROTOCOL            *HttpInstance,\r
+  IN     UINT8                    *Message,\r
+  IN     UINTN                    MessageSize,\r
+  IN     EFI_TLS_CRYPT_MODE       ProcessMode,\r
+  IN OUT NET_FRAGMENT             *Fragment\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINT8                           *Buffer;\r
+  UINT32                          BufferSize;\r
+  UINT32                          BytesCopied;\r
+  EFI_TLS_FRAGMENT_DATA           *FragmentTable;\r
+  UINT32                          FragmentCount;\r
+  EFI_TLS_FRAGMENT_DATA           *OriginalFragmentTable;\r
+  UINTN                           Index;\r
+\r
+  Status                   = EFI_SUCCESS;\r
+  Buffer                   = NULL;\r
+  BufferSize               = 0;\r
+  BytesCopied              = 0;\r
+  FragmentTable            = NULL;\r
+  OriginalFragmentTable    = NULL;\r
+\r
+  //\r
+  // Rebuild fragment table from BufferIn.\r
+  //\r
+  FragmentCount = 1;\r
+  FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));\r
+  if (FragmentTable == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  FragmentTable->FragmentLength = (UINT32) MessageSize;\r
+  FragmentTable->FragmentBuffer = Message;\r
+\r
+  //\r
+  // Record the original FragmentTable.\r
+  //\r
+  OriginalFragmentTable = FragmentTable;\r
+\r
+  //\r
+  // Process the Message.\r
+  //\r
+  Status = HttpInstance->Tls->ProcessPacket (\r
+                                HttpInstance->Tls,\r
+                                &FragmentTable,\r
+                                &FragmentCount,\r
+                                ProcessMode\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Calculate the size according to FragmentTable.\r
+  //\r
+  for (Index = 0; Index < FragmentCount; Index++) {\r
+    BufferSize += FragmentTable[Index].FragmentLength;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer for processed data.\r
+  //\r
+  Buffer = AllocateZeroPool (BufferSize);\r
+  if (Buffer == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Copy the new FragmentTable buffer into Buffer.\r
+  //\r
+  for (Index = 0; Index < FragmentCount; Index++) {\r
+    CopyMem (\r
+      (Buffer + BytesCopied),\r
+      FragmentTable[Index].FragmentBuffer,\r
+      FragmentTable[Index].FragmentLength\r
+      );\r
+    BytesCopied += FragmentTable[Index].FragmentLength;\r
+\r
+    //\r
+    // Free the FragmentBuffer since it has been copied.\r
+    //\r
+    FreePool (FragmentTable[Index].FragmentBuffer);\r
+  }\r
+\r
+  Fragment->Len  = BufferSize;\r
+  Fragment->Bulk = Buffer;\r
+\r
+ON_EXIT:\r
+\r
+  if (OriginalFragmentTable != NULL) {\r
+    FreePool (OriginalFragmentTable);\r
+    OriginalFragmentTable = NULL;\r
+  }\r
+\r
+  //\r
+  // Caller has the responsibility to free the FragmentTable.\r
+  //\r
+  if (FragmentTable != NULL) {\r
+    FreePool (FragmentTable);\r
+    FragmentTable = NULL;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive one fragment decrypted from one TLS record.\r
+\r
+  @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.\r
+  @param[in, out]      Fragment        The received Fragment.\r
+  @param[in]           Timeout         The time to wait for connection done.\r
+\r
+  @retval EFI_SUCCESS          One fragment is received.\r
+  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+  @retval EFI_ABORTED          Something wrong decryption the message.\r
+  @retval Others               Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HttpsReceive (\r
+  IN     HTTP_PROTOCOL         *HttpInstance,\r
+  IN OUT NET_FRAGMENT          *Fragment,\r
+  IN     EFI_EVENT             Timeout\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  NET_BUF                         *Pdu;\r
+  TLS_RECORD_HEADER               RecordHeader;\r
+  UINT8                           *BufferIn;\r
+  UINTN                           BufferInSize;\r
+  NET_FRAGMENT                    TempFragment;\r
+  UINT8                           *BufferOut;\r
+  UINTN                           BufferOutSize;\r
+  NET_BUF                         *PacketOut;\r
+  UINT8                           *DataOut;\r
+  UINT8                           *GetSessionDataBuffer;\r
+  UINTN                           GetSessionDataBufferSize;\r
+\r
+  Status                   = EFI_SUCCESS;\r
+  Pdu                      = NULL;\r
+  BufferIn                 = NULL;\r
+  BufferInSize             = 0;\r
+  BufferOut                = NULL;\r
+  BufferOutSize            = 0;\r
+  PacketOut                = NULL;\r
+  DataOut                  = NULL;\r
+  GetSessionDataBuffer     = NULL;\r
+  GetSessionDataBufferSize = 0;\r
+\r
+  //\r
+  // Receive only one TLS record\r
+  //\r
+  Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BufferInSize = Pdu->TotalSize;\r
+  BufferIn = AllocateZeroPool (BufferInSize);\r
+  if (BufferIn == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    NetbufFree (Pdu);\r
+    return Status;\r
+  }\r
+\r
+  NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);\r
+\r
+  NetbufFree (Pdu);\r
+\r
+  //\r
+  // Handle Receive data.\r
+  //\r
+  RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;\r
+\r
+  if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&\r
+    (RecordHeader.Version.Major == 0x03) &&\r
+    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||\r
+    RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||\r
+    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)\r
+  ) {\r
+    //\r
+    // Decrypt Packet.\r
+    //\r
+    Status = TlsProcessMessage (\r
+               HttpInstance,\r
+               BufferIn,\r
+               BufferInSize,\r
+               EfiTlsDecrypt,\r
+               &TempFragment\r
+               );\r
+\r
+    FreePool (BufferIn);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_ABORTED) {\r
+        //\r
+        // Something wrong decryption the message.\r
+        // BuildResponsePacket() will be called to generate Error Alert message and send it out.\r
+        //\r
+        BufferOutSize = DEF_BUF_LEN;\r
+        BufferOut = AllocateZeroPool (BufferOutSize);\r
+        if (BufferOut == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          return Status;\r
+        }\r
+\r
+        Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                      HttpInstance->Tls,\r
+                                      NULL,\r
+                                      0,\r
+                                      BufferOut,\r
+                                      &BufferOutSize\r
+                                      );\r
+        if (Status == EFI_BUFFER_TOO_SMALL) {\r
+          FreePool (BufferOut);\r
+          BufferOut = AllocateZeroPool (BufferOutSize);\r
+          if (BufferOut == NULL) {\r
+            Status = EFI_OUT_OF_RESOURCES;\r
+            return Status;\r
+          }\r
+\r
+          Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                        HttpInstance->Tls,\r
+                                        NULL,\r
+                                        0,\r
+                                        BufferOut,\r
+                                        &BufferOutSize\r
+                                        );\r
+        }\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool(BufferOut);\r
+          return Status;\r
+        }\r
+\r
+        if (BufferOutSize != 0) {\r
+          PacketOut = NetbufAlloc ((UINT32)BufferOutSize);\r
+          DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);\r
+          if (DataOut == NULL) {\r
+            FreePool (BufferOut);\r
+            return EFI_OUT_OF_RESOURCES;\r
+          }\r
+\r
+          CopyMem (DataOut, BufferOut, BufferOutSize);\r
+\r
+          Status = TlsCommonTransmit (HttpInstance, PacketOut);\r
+\r
+          NetbufFree (PacketOut);\r
+        }\r
+\r
+        FreePool(BufferOut);\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Parsing buffer.\r
+    //\r
+    ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);\r
+\r
+    BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;\r
+    BufferIn = AllocateZeroPool (BufferInSize);\r
+    if (BufferIn == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);\r
+\r
+    //\r
+    // Free the buffer in TempFragment.\r
+    //\r
+    FreePool (TempFragment.Bulk);\r
+\r
+  } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&\r
+    (RecordHeader.Version.Major == 0x03) &&\r
+    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||\r
+    RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||\r
+    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)\r
+    ) {\r
+    BufferOutSize = DEF_BUF_LEN;\r
+    BufferOut = AllocateZeroPool (BufferOutSize);\r
+    if (BufferOut == NULL) {\r
+      FreePool (BufferIn);\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                  HttpInstance->Tls,\r
+                                  BufferIn,\r
+                                  BufferInSize,\r
+                                  BufferOut,\r
+                                  &BufferOutSize\r
+                                  );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      FreePool (BufferOut);\r
+      BufferOut = AllocateZeroPool (BufferOutSize);\r
+      if (BufferOut == NULL) {\r
+        FreePool (BufferIn);\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
+      }\r
+\r
+      Status = HttpInstance->Tls->BuildResponsePacket (\r
+                                    HttpInstance->Tls,\r
+                                    BufferIn,\r
+                                    BufferInSize,\r
+                                    BufferOut,\r
+                                    &BufferOutSize\r
+                                    );\r
+    }\r
+\r
+    FreePool (BufferIn);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (BufferOut);\r
+      return Status;\r
+    }\r
+\r
+    if (BufferOutSize != 0) {\r
+      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);\r
+      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);\r
+      if (DataOut == NULL) {\r
+        FreePool (BufferOut);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      CopyMem (DataOut, BufferOut, BufferOutSize);\r
+\r
+      Status = TlsCommonTransmit (HttpInstance, PacketOut);\r
+\r
+      NetbufFree (PacketOut);\r
+    }\r
+\r
+    FreePool (BufferOut);\r
+\r
+    //\r
+    // Get the session state.\r
+    //\r
+    GetSessionDataBufferSize = DEF_BUF_LEN;\r
+    GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);\r
+    if (GetSessionDataBuffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+\r
+    Status = HttpInstance->Tls->GetSessionData (\r
+                                  HttpInstance->Tls,\r
+                                  EfiTlsSessionState,\r
+                                  GetSessionDataBuffer,\r
+                                  &GetSessionDataBufferSize\r
+                                  );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+       FreePool (GetSessionDataBuffer);\r
+       GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);\r
+       if (GetSessionDataBuffer == NULL) {\r
+         Status = EFI_OUT_OF_RESOURCES;\r
+         return Status;\r
+       }\r
+\r
+       Status = HttpInstance->Tls->GetSessionData (\r
+                                     HttpInstance->Tls,\r
+                                     EfiTlsSessionState,\r
+                                     GetSessionDataBuffer,\r
+                                     &GetSessionDataBufferSize\r
+                                     );\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (GetSessionDataBuffer);\r
+      return Status;\r
+    }\r
+\r
+    ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));\r
+    HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;\r
+\r
+    FreePool (GetSessionDataBuffer);\r
+\r
+    if(HttpInstance->TlsSessionState == EfiTlsSessionError) {\r
+      DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    BufferIn = NULL;\r
+    BufferInSize = 0;\r
+  }\r
+\r
+  Fragment->Bulk = BufferIn;\r
+  Fragment->Len = (UINT32) BufferInSize;\r
+\r
+  return Status;\r
+}\r
+\r