blob: baac907048b91e41a7a5cca98c1e4b7062484ee2 [file] [log] [blame]
/** @file
The Miscellaneous Routines for WiFi Connection Manager.
Copyright (c) 2019, Intel Corporation. All rights reserved.<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 "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;
}
}