/** @file The Miscellaneous Routines for WiFi Connection Manager. Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "WifiConnectionMgrDxe.h" // // STA AKM preference order // REF: https://www.wi-fi.org/file/wpa3-specification // STATIC UINT32 mAKMSuitePreference[] = { IEEE_80211_AKM_SUITE_8021X_SUITE_B192, // AKM Suite 12 IEEE_80211_AKM_SUITE_8021X_SUITE_B, // AKM Suite 11 IEEE_80211_AKM_SUITE_8021X_OR_PMKSA_SHA256, // AKM Suite 5 IEEE_80211_AKM_SUITE_8021X_OR_PMKSA, // AKM Suite 1 IEEE_80211_AKM_SUITE_SAE, // AKM Suite 8 IEEE_80211_AKM_SUITE_PSK_SHA256, // AKM Suite 6 IEEE_80211_AKM_SUITE_PSK, // AKM Suite 2 IEEE_80211_AKM_SUITE_OWE // AKM Suite 18 }; #define AKM_SUITE_PREFERENCE_COUNT (sizeof (mAKMSuitePreference) / sizeof (UINT32)) /** 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; UINT32 *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 < AKM_SUITE_PREFERENCE_COUNT; AKMIndex++) { AKMSuite = mAKMSuitePreference + AKMIndex; if (WifiMgrSupportAKMSuite (AKMList->AKMSuiteCount, (UINT32 *)AKMList->AKMSuiteList, AKMSuite) && WifiMgrSupportAKMSuite (SupportedAKMSuites->AKMSuiteCount, (UINT32 *)SupportedAKMSuites->AKMSuiteList, AKMSuite)) { if ((AKMSuiteSupported != NULL) && (CipherSuiteSupported != NULL)) { *AKMSuiteSupported = TRUE; } // // OWE transition mode allow CipherSuiteCount is 0 // if (CipherList->CipherSuiteCount == 0) { *SecurityType = WifiMgrGetSecurityType ((UINT32 *)AKMSuite, NULL); if (*SecurityType != SECURITY_TYPE_UNKNOWN) { if ((AKMSuiteSupported != NULL) && (CipherSuiteSupported != NULL)) { *CipherSuiteSupported = TRUE; } return EFI_SUCCESS; } } 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 ((AKMSuite != NULL) && (*AKMSuite == IEEE_80211_AKM_SUITE_OWE)) { return SECURITY_TYPE_NONE; } 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_SAE) { return SECURITY_TYPE_WPA3_PERSONAL; } else 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 if (*CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_GCMP) { if (AKMSuite == NULL) { return SECURITY_TYPE_UNKNOWN; } if (*AKMSuite == IEEE_80211_AKM_SUITE_8021X_SUITE_B) { return SECURITY_TYPE_WPA3_ENTERPRISE; } else { return SECURITY_TYPE_UNKNOWN; } } else if (*CipherSuite == IEEE_80211_PAIRWISE_CIPHER_SUITE_GCMP256) { if (AKMSuite == NULL) { return SECURITY_TYPE_UNKNOWN; } if (*AKMSuite == IEEE_80211_AKM_SUITE_8021X_SUITE_B192) { return SECURITY_TYPE_WPA3_ENTERPRISE; } 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 ) { EFI_STATUS Status; EDKII_WIFI_PROFILE_SYNC_PROTOCOL *WiFiProfileSyncProtocol; ZeroMem (Profile->Password, sizeof (CHAR16) * PASSWORD_STORAGE_SIZE); ZeroMem (Profile->EapPassword, sizeof (CHAR16) * PASSWORD_STORAGE_SIZE); ZeroMem (Profile->PrivateKeyPassword, sizeof (CHAR16) * PASSWORD_STORAGE_SIZE); // // When EFI WiFi profile sync protocol is found the system is performing a recovery boot in secure // boot mode. The profile sync driver will manage the CA certificate, client certificate, and key // data, cleaning them at exit boot services. // Status = gBS->LocateProtocol (&gEdkiiWiFiProfileSyncProtocolGuid, NULL, (VOID **)&WiFiProfileSyncProtocol); if (!EFI_ERROR (Status)) { return; } 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; } }