/** @file
  The Miscellaneous Routines for WiFi Connection Manager.

  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "WifiConnectionMgrDxe.h"

/**
  Empty function for event process function.

  @param Event    The Event need to be process
  @param Context  The context of the event.

**/
VOID
EFIAPI
WifiMgrInternalEmptyFunction (
  IN  EFI_EVENT    Event,
  IN  VOID         *Context
  )
{
  return;
}

/**
  Convert the mac address into a hexadecimal encoded ":" seperated string.

  @param[in]  Mac     The mac address.
  @param[in]  StrSize The size, in bytes, of the output buffer specified by Str.
  @param[out] Str     The storage to return the mac string.

**/
VOID
WifiMgrMacAddrToStr (
  IN  EFI_80211_MAC_ADDRESS  *Mac,
  IN  UINT32                 StrSize,
  OUT CHAR16                 *Str
  )
{
  if (Mac == NULL || Str == NULL) {
    return;
  }

  UnicodeSPrint (
    Str,
    StrSize,
    L"%02X:%02X:%02X:%02X:%02X:%02X",
    Mac->Addr[0], Mac->Addr[1], Mac->Addr[2],
    Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]
    );
}

/**
  Read private key file to buffer.

  @param[in]   FileContext           The file context of private key file.
  @param[out]  PrivateKeyDataAddr    The buffer address to restore private key file, should be
                                     freed by caller.
  @param[out]  PrivateKeyDataSize    The size of read private key file.

  @retval EFI_SUCCESS                Successfully read the private key file.
  @retval EFI_INVALID_PARAMETER      One or more of the parameters is invalid.

**/
EFI_STATUS
WifiMgrReadFileToBuffer (
  IN   WIFI_MGR_FILE_CONTEXT          *FileContext,
  OUT  VOID                           **DataAddr,
  OUT  UINTN                          *DataSize
  )
{
  EFI_STATUS    Status;

  if (FileContext != NULL && FileContext->FHandle != NULL) {

    Status = ReadFileContent (
               FileContext->FHandle,
               DataAddr,
               DataSize,
               0
               );

    if (FileContext->FHandle != NULL) {
      FileContext->FHandle->Close (FileContext->FHandle);
    }
    FileContext->FHandle = NULL;
    return Status;
  }

  return EFI_INVALID_PARAMETER;
}

/**
  Get the Nic data by the NicIndex.

  @param[in]  Private        The pointer to the global private data structure.
  @param[in]  NicIndex       The index indicates the position of wireless NIC.

  @return     Pointer to the Nic data, or NULL if not found.

**/
WIFI_MGR_DEVICE_DATA *
WifiMgrGetNicByIndex (
  IN WIFI_MGR_PRIVATE_DATA   *Private,
  IN UINT32                  NicIndex
  )
{
  LIST_ENTRY             *Entry;
  WIFI_MGR_DEVICE_DATA   *Nic;

  if (Private == NULL) {
    return NULL;
  }

  NET_LIST_FOR_EACH (Entry, &Private->NicList) {
    Nic = NET_LIST_USER_STRUCT_S (Entry, WIFI_MGR_DEVICE_DATA,
            Link, WIFI_MGR_DEVICE_DATA_SIGNATURE);
    if (Nic->NicIndex == NicIndex) {
      return Nic;
    }
  }

  return NULL;
}

/**
  Find a network profile through its' SSId and securit type, and the SSId is an unicode string.

  @param[in]  SSId                   The target network's SSId.
  @param[in]  SecurityType           The target network's security type.
  @param[in]  ProfileList            The profile list on a Nic.

  @return Pointer to a network profile, or NULL if not found.

**/
WIFI_MGR_NETWORK_PROFILE *
WifiMgrGetProfileByUnicodeSSId (
  IN  CHAR16                         *SSId,
  IN  UINT8                          SecurityType,
  IN  LIST_ENTRY                     *ProfileList
  )
{
  LIST_ENTRY                         *Entry;
  WIFI_MGR_NETWORK_PROFILE           *Profile;

  if (SSId == NULL || ProfileList == NULL) {
    return NULL;
  }

  NET_LIST_FOR_EACH (Entry, ProfileList) {
    Profile = NET_LIST_USER_STRUCT_S (Entry, WIFI_MGR_NETWORK_PROFILE,
                Link, WIFI_MGR_PROFILE_SIGNATURE);
    if (StrCmp (SSId, Profile->SSId) == 0 && SecurityType == Profile->SecurityType) {
      return Profile;
    }
  }

  return NULL;
}

/**
  Find a network profile through its' SSId and securit type, and the SSId is an ascii string.

  @param[in]  SSId               The target network's SSId.
  @param[in]  SecurityType       The target network's security type.
  @param[in]  ProfileList        The profile list on a Nic.

  @return Pointer to a network profile, or NULL if not found.

**/
WIFI_MGR_NETWORK_PROFILE *
WifiMgrGetProfileByAsciiSSId (
  IN  CHAR8                      *SSId,
  IN  UINT8                      SecurityType,
  IN  LIST_ENTRY                 *ProfileList
  )
{
  CHAR16   SSIdUniCode[SSID_STORAGE_SIZE];

  if (SSId == NULL) {
    return NULL;
  }
  if (AsciiStrToUnicodeStrS (SSId, SSIdUniCode, SSID_STORAGE_SIZE) != RETURN_SUCCESS) {
    return NULL;
  }

  return WifiMgrGetProfileByUnicodeSSId (SSIdUniCode, SecurityType, ProfileList);
}

/**
  Find a network profile through its' profile index.

  @param[in]  ProfileIndex           The target network's profile index.
  @param[in]  ProfileList            The profile list on a Nic.

  @return Pointer to a network profile, or NULL if not found.

**/
WIFI_MGR_NETWORK_PROFILE *
WifiMgrGetProfileByProfileIndex (
  IN  UINT32                         ProfileIndex,
  IN  LIST_ENTRY                     *ProfileList
  )
{
  WIFI_MGR_NETWORK_PROFILE           *Profile;
  LIST_ENTRY                         *Entry;

  if (ProfileList == NULL) {
    return NULL;
  }
  NET_LIST_FOR_EACH (Entry, ProfileList) {
    Profile = NET_LIST_USER_STRUCT_S (Entry, WIFI_MGR_NETWORK_PROFILE,
                Link, WIFI_MGR_PROFILE_SIGNATURE);
    if (Profile->ProfileIndex == ProfileIndex) {
      return Profile;
    }
  }
  return NULL;
}

/**
  To test if the AKMSuite is in supported AKMSuite list.

  @param[in]  SupportedAKMSuiteCount       The count of the supported AKMSuites.
  @param[in]  SupportedAKMSuiteList        The supported AKMSuite list.
  @param[in]  AKMSuite                     The AKMSuite to be tested.

  @return True if this AKMSuite is supported, or False if not.

**/
BOOLEAN
WifiMgrSupportAKMSuite (
  IN  UINT16                               SupportedAKMSuiteCount,
  IN  UINT32                               *SupportedAKMSuiteList,
  IN  UINT32                               *AKMSuite
  )
{
  UINT16    Index;

  if (AKMSuite == NULL || SupportedAKMSuiteList == NULL ||
    SupportedAKMSuiteCount == 0) {
    return FALSE;
  }

  for (Index = 0; Index < SupportedAKMSuiteCount; Index ++) {
    if (SupportedAKMSuiteList[Index] == *AKMSuite) {
      return TRUE;
    }
  }

  return FALSE;
}

/**
  To check if the CipherSuite is in supported CipherSuite list.

  @param[in]  SupportedCipherSuiteCount       The count of the supported CipherSuites.
  @param[in]  SupportedCipherSuiteList        The supported CipherSuite list.
  @param[in]  CipherSuite                     The CipherSuite to be tested.

  @return True if this CipherSuite is supported, or False if not.

**/
BOOLEAN
WifiMgrSupportCipherSuite (
  IN  UINT16                                  SupportedCipherSuiteCount,
  IN  UINT32                                  *SupportedCipherSuiteList,
  IN  UINT32                                  *CipherSuite
  )
{
  UINT16  Index;

  if (CipherSuite == NULL || SupportedCipherSuiteCount == 0 ||
    SupportedCipherSuiteList == NULL) {
    return FALSE;
  }

  for (Index = 0; Index < SupportedCipherSuiteCount; Index ++) {
    if (SupportedCipherSuiteList[Index] == *CipherSuite) {
      return TRUE;
    }
  }

  return FALSE;
}

/**
  Check an AKM suite list and a Cipher suite list to see if one or more AKM suites or Cipher suites
  are supported and find the matchable security type.

  @param[in]   AKMList                     The target AKM suite list to be checked.
  @param[in]   CipherList                  The target Cipher suite list to be checked
  @param[in]   Nic                         The Nic to operate, contains the supported AKMSuite list
                                           and supported CipherSuite list
  @param[out]  SecurityType                To identify a security type from the AKM suite list and
                                           Cipher suite list
  @param[out]  AKMSuiteSupported           To identify if this security type is supported. If it is
                                           NULL, overcome this field
  @param[out]  CipherSuiteSupported        To identify if this security type is supported. If it is
                                           NULL, overcome this field

  @retval EFI_SUCCESS                      This operation has completed successfully.
  @retval EFI_INVALID_PARAMETER            No Nic found or the suite list is null.

**/
EFI_STATUS
WifiMgrCheckRSN (
  IN    EFI_80211_AKM_SUITE_SELECTOR       *AKMList,
  IN    EFI_80211_CIPHER_SUITE_SELECTOR    *CipherList,
  IN    WIFI_MGR_DEVICE_DATA               *Nic,
  OUT   UINT8                              *SecurityType,
  OUT   BOOLEAN                            *AKMSuiteSupported,
  OUT   BOOLEAN                            *CipherSuiteSupported
  )
{
  EFI_80211_AKM_SUITE_SELECTOR             *SupportedAKMSuites;
  EFI_80211_CIPHER_SUITE_SELECTOR          *SupportedSwCipherSuites;
  EFI_80211_CIPHER_SUITE_SELECTOR          *SupportedHwCipherSuites;
  EFI_80211_SUITE_SELECTOR                 *AKMSuite;
  EFI_80211_SUITE_SELECTOR                 *CipherSuite;
  UINT16                                   AKMIndex;
  UINT16                                   CipherIndex;

  if (Nic == NULL || AKMList == NULL || CipherList == NULL|| SecurityType == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  SupportedAKMSuites      = Nic->SupportedSuites.SupportedAKMSuites;
  SupportedSwCipherSuites = Nic->SupportedSuites.SupportedSwCipherSuites;
  SupportedHwCipherSuites = Nic->SupportedSuites.SupportedHwCipherSuites;

  *SecurityType = SECURITY_TYPE_UNKNOWN;
  if (AKMSuiteSupported != NULL && CipherSuiteSupported != NULL) {
    *AKMSuiteSupported    = FALSE;
    *CipherSuiteSupported = FALSE;
  }

  if (AKMList->AKMSuiteCount == 0) {
    if (CipherList->CipherSuiteCount == 0) {
      *SecurityType = SECURITY_TYPE_NONE;
      if (AKMSuiteSupported != NULL && CipherSuiteSupported != NULL) {
        *AKMSuiteSupported    = TRUE;
        *CipherSuiteSupported = TRUE;
      }
    }

    return EFI_SUCCESS;
  }

  for (AKMIndex = 0; AKMIndex < AKMList->AKMSuiteCount; AKMIndex ++) {

    AKMSuite = AKMList->AKMSuiteList + AKMIndex;
    if (WifiMgrSupportAKMSuite(SupportedAKMSuites->AKMSuiteCount,
      (UINT32*) SupportedAKMSuites->AKMSuiteList, (UINT32*) AKMSuite)) {

      if (AKMSuiteSupported != NULL && CipherSuiteSupported != NULL) {
        *AKMSuiteSupported = TRUE;
      }
      for (CipherIndex = 0; CipherIndex < CipherList->CipherSuiteCount; CipherIndex ++) {

        CipherSuite = CipherList->CipherSuiteList + CipherIndex;

        if (SupportedSwCipherSuites != NULL) {

          if (WifiMgrSupportCipherSuite(SupportedSwCipherSuites->CipherSuiteCount,
            (UINT32*) SupportedSwCipherSuites->CipherSuiteList, (UINT32*) CipherSuite)) {

            *SecurityType = WifiMgrGetSecurityType ((UINT32*) AKMSuite, (UINT32*) CipherSuite);

            if (*SecurityType != SECURITY_TYPE_UNKNOWN) {

              if (AKMSuiteSupported != NULL && CipherSuiteSupported != NULL) {
                *CipherSuiteSupported = TRUE;
              }
              return EFI_SUCCESS;
            }
          }
        }

        if (SupportedHwCipherSuites != NULL) {

          if (WifiMgrSupportCipherSuite(SupportedHwCipherSuites->CipherSuiteCount,
            (UINT32*) SupportedHwCipherSuites->CipherSuiteList, (UINT32*) CipherSuite)) {

            *SecurityType = WifiMgrGetSecurityType ((UINT32*) AKMSuite, (UINT32*) CipherSuite);

            if (*SecurityType != SECURITY_TYPE_UNKNOWN) {

              if (AKMSuiteSupported != NULL && CipherSuiteSupported != NULL) {
                *CipherSuiteSupported = TRUE;
              }
              return EFI_SUCCESS;
            }
          }
        }
      }
    }
  }

  *SecurityType = WifiMgrGetSecurityType ((UINT32*) AKMList->AKMSuiteList,
                    (UINT32*) CipherList->CipherSuiteList);

  return EFI_SUCCESS;
}

/**
  Get the security type for a certain AKMSuite and CipherSuite.

  @param[in]   AKMSuite             An certain AKMSuite.
  @param[in]   CipherSuite          An certain CipherSuite.

  @return a security type if found, or SECURITY_TYPE_UNKNOWN.

**/
UINT8
WifiMgrGetSecurityType (
  IN  UINT32    *AKMSuite,
  IN  UINT32    *CipherSuite
  )
{
  if (CipherSuite == NULL) {

    if (AKMSuite == NULL) {
      return SECURITY_TYPE_NONE;
    } else {
      return SECURITY_TYPE_UNKNOWN;
    }
  } else if (*CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_USE_GROUP) {

    if (AKMSuite == NULL) {
      return SECURITY_TYPE_NONE;
    } else {
      return SECURITY_TYPE_UNKNOWN;
    }
  } else if (*CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_WEP40 ||
    *CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_WEP104) {

    return SECURITY_TYPE_WEP;
  } else if (*CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_CCMP) {

    if (AKMSuite == NULL) {
      return SECURITY_TYPE_UNKNOWN;
    }

    if (*AKMSuite == IEEE_80211_AKM_SUITE_8021X_OR_PMKSA ||
      *AKMSuite == IEEE_80211_AKM_SUITE_8021X_OR_PMKSA_SHA256) {

      return SECURITY_TYPE_WPA2_ENTERPRISE;
    } else if (*AKMSuite == IEEE_80211_AKM_SUITE_PSK ||
        *AKMSuite == IEEE_80211_AKM_SUITE_PSK_SHA256){

      return SECURITY_TYPE_WPA2_PERSONAL;
    }else {
      return SECURITY_TYPE_UNKNOWN;
    }
  } else if (*CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_TKIP) {

    if (AKMSuite == NULL) {
      return SECURITY_TYPE_UNKNOWN;
    }

    if (*AKMSuite == IEEE_80211_AKM_SUITE_8021X_OR_PMKSA ||
      *AKMSuite == IEEE_80211_AKM_SUITE_8021X_OR_PMKSA_SHA256) {

      return SECURITY_TYPE_WPA_ENTERPRISE;
    } else if (*AKMSuite == IEEE_80211_AKM_SUITE_PSK ||
        *AKMSuite == IEEE_80211_AKM_SUITE_PSK_SHA256){

      return SECURITY_TYPE_WPA_PERSONAL;
    }else {
      return SECURITY_TYPE_UNKNOWN;
    }
  } else {
    return SECURITY_TYPE_UNKNOWN;
  }
}

/**
  Get supported AKMSuites and CipherSuites from supplicant for a Nic.

  @param[in]   Nic                      The Nic to operate.

  @retval EFI_SUCCESS                   Get the supported suite list successfully.
  @retval EFI_INVALID_PARAMETER         No Nic found or supplicant is NULL.

**/
EFI_STATUS
WifiMgrGetSupportedSuites (
  IN    WIFI_MGR_DEVICE_DATA            *Nic
  )
{
  EFI_STATUS                            Status;
  EFI_SUPPLICANT_PROTOCOL               *Supplicant;
  EFI_80211_AKM_SUITE_SELECTOR          *SupportedAKMSuites;
  EFI_80211_CIPHER_SUITE_SELECTOR       *SupportedSwCipherSuites;
  EFI_80211_CIPHER_SUITE_SELECTOR       *SupportedHwCipherSuites;
  UINTN                                 DataSize;

  SupportedAKMSuites      = NULL;
  SupportedSwCipherSuites = NULL;
  SupportedHwCipherSuites = NULL;

  if (Nic == NULL || Nic->Supplicant == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Supplicant = Nic->Supplicant;

  DataSize  = 0;
  Status = Supplicant->GetData (Supplicant, EfiSupplicant80211SupportedAKMSuites, NULL, &DataSize);
  if (Status == EFI_BUFFER_TOO_SMALL && DataSize > 0) {

    SupportedAKMSuites = AllocateZeroPool(DataSize);
    if (SupportedAKMSuites == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    Status = Supplicant->GetData (Supplicant, EfiSupplicant80211SupportedAKMSuites,
                           (UINT8 *) SupportedAKMSuites, &DataSize);
    if (!EFI_ERROR (Status)) {
      Nic->SupportedSuites.SupportedAKMSuites = SupportedAKMSuites;
    } else {
      FreePool (SupportedAKMSuites);
    }
  } else {
    SupportedAKMSuites = NULL;
  }

  DataSize  = 0;
  Status = Supplicant->GetData (Supplicant, EfiSupplicant80211SupportedSoftwareCipherSuites, NULL, &DataSize);
  if (Status == EFI_BUFFER_TOO_SMALL && DataSize > 0) {


    SupportedSwCipherSuites = AllocateZeroPool(DataSize);
    if (SupportedSwCipherSuites == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    Status = Supplicant->GetData (Supplicant, EfiSupplicant80211SupportedSoftwareCipherSuites,
                           (UINT8 *) SupportedSwCipherSuites, &DataSize);
    if (!EFI_ERROR (Status)) {
      Nic->SupportedSuites.SupportedSwCipherSuites = SupportedSwCipherSuites;
    } else {
      FreePool (SupportedSwCipherSuites);
    }
  } else {
    SupportedSwCipherSuites = NULL;
  }

  DataSize  = 0;
  Status = Supplicant->GetData (Supplicant, EfiSupplicant80211SupportedHardwareCipherSuites, NULL, &DataSize);
  if (Status == EFI_BUFFER_TOO_SMALL && DataSize > 0) {

    SupportedHwCipherSuites = AllocateZeroPool(DataSize);
    if (SupportedHwCipherSuites == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    Status = Supplicant->GetData (Supplicant, EfiSupplicant80211SupportedHardwareCipherSuites,
                           (UINT8 *) SupportedHwCipherSuites, &DataSize);
    if (!EFI_ERROR (Status)) {
      Nic->SupportedSuites.SupportedHwCipherSuites = SupportedHwCipherSuites;
    } else {
      FreePool (SupportedHwCipherSuites);
    }
  } else {
    SupportedHwCipherSuites = NULL;
  }

  return EFI_SUCCESS;
}

/**
  Clean secrets from a network profile.

  @param[in]   Profile               The profile to be cleanned.

**/
VOID
WifiMgrCleanProfileSecrets (
  IN  WIFI_MGR_NETWORK_PROFILE       *Profile
  )
{
  ZeroMem (Profile->Password, sizeof (CHAR16) * PASSWORD_STORAGE_SIZE);
  ZeroMem (Profile->EapPassword, sizeof (CHAR16) * PASSWORD_STORAGE_SIZE);
  ZeroMem (Profile->PrivateKeyPassword, sizeof (CHAR16) * PASSWORD_STORAGE_SIZE);

  if (Profile->CACertData != NULL) {

    ZeroMem (Profile->CACertData, Profile->CACertSize);
    FreePool (Profile->CACertData);
  }
  Profile->CACertData = NULL;
  Profile->CACertSize = 0;

  if (Profile->ClientCertData != NULL) {

    ZeroMem (Profile->ClientCertData, Profile->ClientCertSize);
    FreePool (Profile->ClientCertData);
  }
  Profile->ClientCertData = NULL;
  Profile->ClientCertSize = 0;

  if (Profile->PrivateKeyData != NULL) {

    ZeroMem (Profile->PrivateKeyData, Profile->PrivateKeyDataSize);
    FreePool (Profile->PrivateKeyData);
  }
  Profile->PrivateKeyData     = NULL;
  Profile->PrivateKeyDataSize = 0;
}

/**
  Free all network profiles in a profile list.

  @param[in]   ProfileList           The profile list to be freed.

**/
VOID
WifiMgrFreeProfileList (
  IN  LIST_ENTRY                     *ProfileList
  )
{
  WIFI_MGR_NETWORK_PROFILE           *Profile;
  LIST_ENTRY                         *Entry;
  LIST_ENTRY                         *NextEntry;

  if (ProfileList == NULL) {
    return;
  }

  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, ProfileList) {

    Profile = NET_LIST_USER_STRUCT_S (Entry, WIFI_MGR_NETWORK_PROFILE,
                Link, WIFI_MGR_PROFILE_SIGNATURE);

    WifiMgrCleanProfileSecrets (Profile);

    if (Profile->Network.AKMSuite != NULL) {
      FreePool(Profile->Network.AKMSuite);
    }

    if (Profile->Network.CipherSuite != NULL) {
      FreePool(Profile->Network.CipherSuite);
    }

    FreePool (Profile);
  }
}

/**
  Free user configured hidden network list.

  @param[in]   HiddenList           The hidden network list to be freed.

**/
VOID
WifiMgrFreeHiddenList (
  IN  LIST_ENTRY                     *HiddenList
  )
{
  WIFI_HIDDEN_NETWORK_DATA           *HiddenNetwork;
  LIST_ENTRY                         *Entry;
  LIST_ENTRY                         *NextEntry;

  if (HiddenList == NULL) {
    return;
  }

  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, HiddenList) {

    HiddenNetwork = NET_LIST_USER_STRUCT_S (Entry, WIFI_HIDDEN_NETWORK_DATA,
                      Link, WIFI_MGR_HIDDEN_NETWORK_SIGNATURE);
    FreePool (HiddenNetwork);
  }
}


/**
  Free the resources of a config token.

  @param[in]   ConfigToken          The config token to be freed.
**/
VOID
WifiMgrFreeToken (
  IN   WIFI_MGR_MAC_CONFIG_TOKEN    *ConfigToken
  )
{
  EFI_80211_GET_NETWORKS_RESULT     *Result;

  if (ConfigToken == NULL) {
    return;
  }

  switch (ConfigToken->Type) {

    case TokenTypeGetNetworksToken:

      if (ConfigToken->Token.GetNetworksToken != NULL) {

        gBS->CloseEvent (ConfigToken->Token.GetNetworksToken->Event);
        if (ConfigToken->Token.GetNetworksToken->Data != NULL) {
          FreePool(ConfigToken->Token.GetNetworksToken->Data);
        }

        Result = ConfigToken->Token.GetNetworksToken->Result;
        if (Result != NULL) {
          FreePool (Result);
        }

        FreePool(ConfigToken->Token.GetNetworksToken);
      }

      FreePool (ConfigToken);
      break;

    case TokenTypeConnectNetworkToken:

      if (ConfigToken->Token.ConnectNetworkToken != NULL) {

        gBS->CloseEvent (ConfigToken->Token.ConnectNetworkToken->Event);
        if (ConfigToken->Token.ConnectNetworkToken->Data != NULL) {
          FreePool(ConfigToken->Token.ConnectNetworkToken->Data);
        }
        FreePool(ConfigToken->Token.ConnectNetworkToken);
      }
      FreePool (ConfigToken);
      break;

    case TokenTypeDisconnectNetworkToken:

      if (ConfigToken->Token.DisconnectNetworkToken != NULL) {

        FreePool(ConfigToken->Token.DisconnectNetworkToken);
      }

      FreePool (ConfigToken);
      break;

    default :
      break;
  }
}
