mirror of https://github.com/acidanthera/audk.git
1566 lines
49 KiB
C
1566 lines
49 KiB
C
/** @file
|
|
The Mac Connection2 Protocol adapter functions for WiFi Connection Manager.
|
|
|
|
Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "WifiConnectionMgrDxe.h"
|
|
|
|
EFI_EAP_TYPE mEapAuthMethod[] = {
|
|
EFI_EAP_TYPE_TTLS,
|
|
EFI_EAP_TYPE_PEAP,
|
|
EFI_EAP_TYPE_EAPTLS
|
|
};
|
|
|
|
EFI_EAP_TYPE mEapSecondAuthMethod[] = {
|
|
EFI_EAP_TYPE_MSCHAPV2
|
|
};
|
|
|
|
UINT8 mWifiConnectionCount = 0;
|
|
|
|
/**
|
|
The callback function for scan operation. This function updates networks
|
|
according to the latest scan result, and trigger UI refresh.
|
|
|
|
ASSERT when errors occur in config token.
|
|
|
|
@param[in] Event The GetNetworks token receive event.
|
|
@param[in] Context The context of the GetNetworks token.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
WifiMgrOnScanFinished (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
|
|
WIFI_MGR_DEVICE_DATA *Nic;
|
|
WIFI_MGR_NETWORK_PROFILE *Profile;
|
|
EFI_80211_NETWORK *Network;
|
|
UINTN DataSize;
|
|
EFI_80211_NETWORK_DESCRIPTION *NetworkDescription;
|
|
EFI_80211_GET_NETWORKS_RESULT *Result;
|
|
LIST_ENTRY *Entry;
|
|
UINT8 SecurityType;
|
|
BOOLEAN AKMSuiteSupported;
|
|
BOOLEAN CipherSuiteSupported;
|
|
CHAR8 *AsciiSSId;
|
|
UINTN Index;
|
|
|
|
ASSERT (Context != NULL);
|
|
|
|
ConfigToken = (WIFI_MGR_MAC_CONFIG_TOKEN *)Context;
|
|
ASSERT (ConfigToken->Nic != NULL);
|
|
ASSERT (ConfigToken->Type == TokenTypeGetNetworksToken);
|
|
|
|
//
|
|
// It is the GetNetworks token, set scan state to "ScanFinished"
|
|
//
|
|
ConfigToken->Nic->ScanState = WifiMgrScanFinished;
|
|
|
|
ASSERT (ConfigToken->Token.GetNetworksToken != NULL);
|
|
Result = ConfigToken->Token.GetNetworksToken->Result;
|
|
Nic = ConfigToken->Nic;
|
|
|
|
//
|
|
// Clean previous result, and update network list according to the scan result
|
|
//
|
|
Nic->AvailableCount = 0;
|
|
|
|
NET_LIST_FOR_EACH (Entry, &Nic->ProfileList) {
|
|
Profile = NET_LIST_USER_STRUCT_S (
|
|
Entry,
|
|
WIFI_MGR_NETWORK_PROFILE,
|
|
Link,
|
|
WIFI_MGR_PROFILE_SIGNATURE
|
|
);
|
|
Profile->IsAvailable = FALSE;
|
|
}
|
|
|
|
if (Result == NULL) {
|
|
gBS->SignalEvent (Nic->Private->NetworkListRefreshEvent);
|
|
WifiMgrFreeToken (ConfigToken);
|
|
return;
|
|
}
|
|
|
|
for (Index = 0; Index < Result->NumOfNetworkDesc; Index++) {
|
|
NetworkDescription = Result->NetworkDesc + Index;
|
|
if (NetworkDescription == NULL) {
|
|
continue;
|
|
}
|
|
|
|
Network = &NetworkDescription->Network;
|
|
if ((Network == NULL) || (Network->SSId.SSIdLen == 0)) {
|
|
continue;
|
|
}
|
|
|
|
Status = WifiMgrCheckRSN (
|
|
Network->AKMSuite,
|
|
Network->CipherSuite,
|
|
Nic,
|
|
&SecurityType,
|
|
&AKMSuiteSupported,
|
|
&CipherSuiteSupported
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
SecurityType = SECURITY_TYPE_UNKNOWN;
|
|
AKMSuiteSupported = FALSE;
|
|
CipherSuiteSupported = FALSE;
|
|
}
|
|
|
|
AsciiSSId = (CHAR8 *)AllocateZeroPool (sizeof (CHAR8) * (Network->SSId.SSIdLen + 1));
|
|
if (AsciiSSId == NULL) {
|
|
continue;
|
|
}
|
|
|
|
CopyMem (AsciiSSId, (CHAR8 *)Network->SSId.SSId, sizeof (CHAR8) * Network->SSId.SSIdLen);
|
|
*(AsciiSSId + Network->SSId.SSIdLen) = '\0';
|
|
|
|
Profile = WifiMgrGetProfileByAsciiSSId (AsciiSSId, SecurityType, &Nic->ProfileList);
|
|
if (Profile == NULL) {
|
|
if (Nic->MaxProfileIndex >= NETWORK_LIST_COUNT_MAX) {
|
|
FreePool (AsciiSSId);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create a new profile
|
|
//
|
|
Profile = AllocateZeroPool (sizeof (WIFI_MGR_NETWORK_PROFILE));
|
|
if (Profile == NULL) {
|
|
FreePool (AsciiSSId);
|
|
continue;
|
|
}
|
|
|
|
Profile->Signature = WIFI_MGR_PROFILE_SIGNATURE;
|
|
Profile->NicIndex = Nic->NicIndex;
|
|
Profile->ProfileIndex = Nic->MaxProfileIndex + 1;
|
|
AsciiStrToUnicodeStrS (AsciiSSId, Profile->SSId, SSID_STORAGE_SIZE);
|
|
InsertTailList (&Nic->ProfileList, &Profile->Link);
|
|
Nic->MaxProfileIndex++;
|
|
}
|
|
|
|
FreePool (AsciiSSId);
|
|
|
|
//
|
|
// May receive duplicate networks in scan results, check if it has already
|
|
// been processed.
|
|
//
|
|
if (!Profile->IsAvailable) {
|
|
Profile->IsAvailable = TRUE;
|
|
Profile->SecurityType = SecurityType;
|
|
Profile->AKMSuiteSupported = AKMSuiteSupported;
|
|
Profile->CipherSuiteSupported = CipherSuiteSupported;
|
|
Profile->NetworkQuality = NetworkDescription->NetworkQuality;
|
|
Nic->AvailableCount++;
|
|
|
|
//
|
|
// Copy BSSType and SSId
|
|
//
|
|
CopyMem (&Profile->Network, Network, sizeof (EFI_80211_NETWORK));
|
|
|
|
//
|
|
// Copy AKMSuite list
|
|
//
|
|
if (Network->AKMSuite != NULL) {
|
|
if (Network->AKMSuite->AKMSuiteCount == 0) {
|
|
DataSize = sizeof (EFI_80211_AKM_SUITE_SELECTOR);
|
|
} else {
|
|
DataSize = sizeof (EFI_80211_AKM_SUITE_SELECTOR) + sizeof (EFI_80211_SUITE_SELECTOR)
|
|
* (Network->AKMSuite->AKMSuiteCount - 1);
|
|
}
|
|
|
|
Profile->Network.AKMSuite = (EFI_80211_AKM_SUITE_SELECTOR *)AllocateZeroPool (DataSize);
|
|
if (Profile->Network.AKMSuite == NULL) {
|
|
continue;
|
|
}
|
|
|
|
CopyMem (Profile->Network.AKMSuite, Network->AKMSuite, DataSize);
|
|
}
|
|
|
|
//
|
|
// Copy CipherSuite list
|
|
//
|
|
if (Network->CipherSuite != NULL) {
|
|
if (Network->CipherSuite->CipherSuiteCount == 0) {
|
|
DataSize = sizeof (EFI_80211_CIPHER_SUITE_SELECTOR);
|
|
} else {
|
|
DataSize = sizeof (EFI_80211_CIPHER_SUITE_SELECTOR) + sizeof (EFI_80211_SUITE_SELECTOR)
|
|
* (Network->CipherSuite->CipherSuiteCount - 1);
|
|
}
|
|
|
|
Profile->Network.CipherSuite = (EFI_80211_CIPHER_SUITE_SELECTOR *)AllocateZeroPool (DataSize);
|
|
if (Profile->Network.CipherSuite == NULL) {
|
|
continue;
|
|
}
|
|
|
|
CopyMem (Profile->Network.CipherSuite, Network->CipherSuite, DataSize);
|
|
}
|
|
} else {
|
|
//
|
|
// A duplicate network, update signal quality
|
|
//
|
|
if (Profile->NetworkQuality < NetworkDescription->NetworkQuality) {
|
|
Profile->NetworkQuality = NetworkDescription->NetworkQuality;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
gBS->SignalEvent (Nic->Private->NetworkListRefreshEvent);
|
|
|
|
//
|
|
// The current connected network should always be available until disconnection
|
|
// happens in Wifi FW layer, even when it is not in this time's scan result.
|
|
//
|
|
if ((Nic->ConnectState == WifiMgrConnectedToAp) && (Nic->CurrentOperateNetwork != NULL)) {
|
|
if (!Nic->CurrentOperateNetwork->IsAvailable) {
|
|
Nic->CurrentOperateNetwork->IsAvailable = TRUE;
|
|
Nic->AvailableCount++;
|
|
}
|
|
}
|
|
|
|
WifiMgrFreeToken (ConfigToken);
|
|
}
|
|
|
|
/**
|
|
Start scan operation, and send out a token to collect available networks.
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_ALREADY_STARTED A former scan operation is already ongoing.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
@retval Other Errors Return errors when getting networks from low layer.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrStartScan (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
|
|
EFI_80211_GET_NETWORKS_TOKEN *GetNetworksToken;
|
|
UINT32 HiddenSSIdIndex;
|
|
UINT32 HiddenSSIdCount;
|
|
EFI_80211_SSID *HiddenSSIdList;
|
|
WIFI_HIDDEN_NETWORK_DATA *HiddenNetwork;
|
|
LIST_ENTRY *Entry;
|
|
|
|
if ((Nic == NULL) || (Nic->Wmp == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Nic->ScanState == WifiMgrScanning) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
Nic->ScanState = WifiMgrScanning;
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
Status = EFI_SUCCESS;
|
|
HiddenSSIdList = NULL;
|
|
HiddenSSIdCount = Nic->Private->HiddenNetworkCount;
|
|
HiddenSSIdIndex = 0;
|
|
|
|
//
|
|
// create a new get network token
|
|
//
|
|
ConfigToken = AllocateZeroPool (sizeof (WIFI_MGR_MAC_CONFIG_TOKEN));
|
|
if (ConfigToken == NULL) {
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ConfigToken->Type = TokenTypeGetNetworksToken;
|
|
ConfigToken->Nic = Nic;
|
|
ConfigToken->Token.GetNetworksToken = AllocateZeroPool (sizeof (EFI_80211_GET_NETWORKS_TOKEN));
|
|
if (ConfigToken->Token.GetNetworksToken == NULL) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
GetNetworksToken = ConfigToken->Token.GetNetworksToken;
|
|
|
|
//
|
|
// There are some hidden networks to scan, add them into scan list
|
|
//
|
|
if (HiddenSSIdCount > 0) {
|
|
HiddenSSIdList = AllocateZeroPool (HiddenSSIdCount * sizeof (EFI_80211_SSID));
|
|
if (HiddenSSIdList == NULL) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
HiddenSSIdIndex = 0;
|
|
NET_LIST_FOR_EACH (Entry, &Nic->Private->HiddenNetworkList) {
|
|
HiddenNetwork = NET_LIST_USER_STRUCT_S (
|
|
Entry,
|
|
WIFI_HIDDEN_NETWORK_DATA,
|
|
Link,
|
|
WIFI_MGR_HIDDEN_NETWORK_SIGNATURE
|
|
);
|
|
HiddenSSIdList[HiddenSSIdIndex].SSIdLen = (UINT8)StrLen (HiddenNetwork->SSId);
|
|
UnicodeStrToAsciiStrS (
|
|
HiddenNetwork->SSId,
|
|
(CHAR8 *)HiddenSSIdList[HiddenSSIdIndex].SSId,
|
|
SSID_STORAGE_SIZE
|
|
);
|
|
HiddenSSIdIndex++;
|
|
}
|
|
GetNetworksToken->Data = AllocateZeroPool (
|
|
sizeof (EFI_80211_GET_NETWORKS_DATA) +
|
|
(HiddenSSIdCount - 1) * sizeof (EFI_80211_SSID)
|
|
);
|
|
if (GetNetworksToken->Data == NULL) {
|
|
FreePool (HiddenSSIdList);
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
GetNetworksToken->Data->NumOfSSID = HiddenSSIdCount;
|
|
CopyMem (GetNetworksToken->Data->SSIDList, HiddenSSIdList, HiddenSSIdCount * sizeof (EFI_80211_SSID));
|
|
FreePool (HiddenSSIdList);
|
|
} else {
|
|
GetNetworksToken->Data = AllocateZeroPool (sizeof (EFI_80211_GET_NETWORKS_DATA));
|
|
if (GetNetworksToken->Data == NULL) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
GetNetworksToken->Data->NumOfSSID = 0;
|
|
}
|
|
|
|
//
|
|
// Create a handle when scan process ends
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
WifiMgrOnScanFinished,
|
|
ConfigToken,
|
|
&GetNetworksToken->Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Start scan ...
|
|
//
|
|
Status = Nic->Wmp->GetNetworks (Nic->Wmp, GetNetworksToken);
|
|
if (EFI_ERROR (Status)) {
|
|
Nic->ScanState = WifiMgrScanFinished;
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Configure password to supplicant before connecting to a secured network.
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
@param[in] Profile The target network to be connected.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
@retval EFI_NOT_FOUND No valid password is found to configure.
|
|
@retval Other Errors Returned errors when setting data to supplicant.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrConfigPassword (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic,
|
|
IN WIFI_MGR_NETWORK_PROFILE *Profile
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SUPPLICANT_PROTOCOL *Supplicant;
|
|
EFI_80211_SSID SSId;
|
|
UINT8 *AsciiPassword;
|
|
|
|
if ((Nic == NULL) || (Nic->Supplicant == NULL) || (Profile == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Supplicant = Nic->Supplicant;
|
|
//
|
|
// Set SSId to supplicant
|
|
//
|
|
SSId.SSIdLen = Profile->Network.SSId.SSIdLen;
|
|
CopyMem (SSId.SSId, Profile->Network.SSId.SSId, sizeof (Profile->Network.SSId.SSId));
|
|
Status = Supplicant->SetData (
|
|
Supplicant,
|
|
EfiSupplicant80211TargetSSIDName,
|
|
(VOID *)&SSId,
|
|
sizeof (EFI_80211_SSID)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set password to supplicant
|
|
//
|
|
if (StrLen (Profile->Password) < PASSWORD_MIN_LEN) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (StrLen (Profile->Password) >= PASSWORD_STORAGE_SIZE) {
|
|
ASSERT (EFI_INVALID_PARAMETER);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AsciiPassword = AllocateZeroPool ((StrLen (Profile->Password) + 1) * sizeof (CHAR8));
|
|
if (AsciiPassword == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = UnicodeStrToAsciiStrS (Profile->Password, (CHAR8 *)AsciiPassword, (StrLen (Profile->Password) + 1));
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = Supplicant->SetData (
|
|
Supplicant,
|
|
EfiSupplicant80211PskPassword,
|
|
AsciiPassword,
|
|
(StrLen (Profile->Password) + 1) * sizeof (CHAR8)
|
|
);
|
|
}
|
|
|
|
ZeroMem (AsciiPassword, AsciiStrLen ((CHAR8 *)AsciiPassword) + 1);
|
|
FreePool (AsciiPassword);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Conduct EAP configuration to supplicant before connecting to a EAP network.
|
|
Current WiFi Connection Manager only supports three kinds of EAP networks:
|
|
1). EAP-TLS (Two-Way Authentication is required in our implementation)
|
|
2). EAP-TTLS/MSCHAPv2 (One-Way Authentication is required in our implementation)
|
|
3). PEAPv0/MSCHAPv2 (One-Way Authentication is required in our implementation)
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
@param[in] Profile The target network to be connected.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval EFI_UNSUPPORTED The expected EAP method is not supported.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
@retval Other Errors Returned errors when setting data to supplicant.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrConfigEap (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic,
|
|
IN WIFI_MGR_NETWORK_PROFILE *Profile
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EDKII_WIFI_PROFILE_SYNC_PROTOCOL *WiFiProfileSyncProtocol;
|
|
EFI_EAP_CONFIGURATION_PROTOCOL *EapConfig;
|
|
EFI_EAP_TYPE EapAuthMethod;
|
|
EFI_EAP_TYPE EapSecondAuthMethod;
|
|
EFI_EAP_TYPE *AuthMethodList;
|
|
CHAR8 *Identity;
|
|
UINTN IdentitySize;
|
|
CHAR16 *Password;
|
|
UINTN PasswordSize;
|
|
UINTN EncryptPasswordLen;
|
|
CHAR8 *AsciiEncryptPassword;
|
|
UINTN AuthMethodListSize;
|
|
UINTN Index;
|
|
|
|
if ((Nic == NULL) || (Nic->EapConfig == NULL) || (Profile == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EapConfig = Nic->EapConfig;
|
|
|
|
if (Profile->EapAuthMethod >= EAP_AUTH_METHOD_MAX) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EapAuthMethod = mEapAuthMethod[Profile->EapAuthMethod];
|
|
|
|
if (EapAuthMethod != EFI_EAP_TYPE_EAPTLS) {
|
|
if (Profile->EapSecondAuthMethod >= EAP_SEAUTH_METHOD_MAX) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EapSecondAuthMethod = mEapSecondAuthMethod[Profile->EapSecondAuthMethod];
|
|
}
|
|
|
|
//
|
|
// The first time to get Supported Auth Method list, return the size.
|
|
//
|
|
AuthMethodListSize = 0;
|
|
AuthMethodList = NULL;
|
|
Status = EapConfig->GetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_ATTRIBUTE,
|
|
EfiEapConfigEapSupportedAuthMethod,
|
|
(VOID *)AuthMethodList,
|
|
&AuthMethodListSize
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
//
|
|
// No Supported Eap Auth Method
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
} else if (Status != EFI_BUFFER_TOO_SMALL) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// The second time to get Supported Auth Method list, return the list.
|
|
// In current design, only EAPTLS, TTLS and PEAP are supported
|
|
//
|
|
AuthMethodList = (EFI_EAP_TYPE *)AllocateZeroPool (AuthMethodListSize);
|
|
if (AuthMethodList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = EapConfig->GetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_ATTRIBUTE,
|
|
EfiEapConfigEapSupportedAuthMethod,
|
|
(VOID *)AuthMethodList,
|
|
&AuthMethodListSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (AuthMethodList);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check if EapAuthMethod is in supported Auth Method list, if found, skip the loop.
|
|
//
|
|
for (Index = 0; Index < AuthMethodListSize / sizeof (EFI_EAP_TYPE); Index++) {
|
|
if (EapAuthMethod == AuthMethodList[Index]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index == AuthMethodListSize / sizeof (EFI_EAP_TYPE)) {
|
|
FreePool (AuthMethodList);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
FreePool (AuthMethodList);
|
|
|
|
//
|
|
// Set Identity to Eap peer, Mandatory field for PEAP and TTLS
|
|
//
|
|
if (StrLen (Profile->EapIdentity) > 0) {
|
|
Status = gBS->LocateProtocol (&gEdkiiWiFiProfileSyncProtocolGuid, NULL, (VOID **)&WiFiProfileSyncProtocol);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Max size of EapIdentity ::= sizeof (CHAR16) * sizeof (Profile->EapIdentity) ::= 2 * EAP_IDENTITY_SIZE
|
|
//
|
|
IdentitySize = sizeof (CHAR8) * (AsciiStrnLenS ((CHAR8 *)Profile->EapIdentity, sizeof (CHAR16) * sizeof (Profile->EapIdentity)) + 1);
|
|
} else {
|
|
IdentitySize = sizeof (CHAR8) * (StrLen (Profile->EapIdentity) + 1);
|
|
}
|
|
|
|
Identity = AllocateZeroPool (IdentitySize);
|
|
if (Identity == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// The size of Identity from Username may equal
|
|
// to the max size of EapIdentity(EAP_IDENTITY_SIZE*2=128 bytes),
|
|
// so here only valid characters except NULL characters are copied.
|
|
//
|
|
CopyMem (Identity, &Profile->EapIdentity, IdentitySize - 1);
|
|
} else {
|
|
UnicodeStrToAsciiStrS (Profile->EapIdentity, Identity, IdentitySize);
|
|
}
|
|
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_IDENTITY,
|
|
EfiEapConfigIdentityString,
|
|
(VOID *)Identity,
|
|
IdentitySize - 1
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (Identity);
|
|
return Status;
|
|
}
|
|
|
|
FreePool (Identity);
|
|
} else {
|
|
if (EapAuthMethod != EFI_EAP_TYPE_EAPTLS) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set Auth Method to Eap peer, Mandatory field
|
|
//
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_ATTRIBUTE,
|
|
EfiEapConfigEapAuthMethod,
|
|
(VOID *)&EapAuthMethod,
|
|
sizeof (EapAuthMethod)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if ((EapAuthMethod == EFI_EAP_TYPE_TTLS) || (EapAuthMethod == EFI_EAP_TYPE_PEAP)) {
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EapAuthMethod,
|
|
EfiEapConfigEap2ndAuthMethod,
|
|
(VOID *)&EapSecondAuthMethod,
|
|
sizeof (EapSecondAuthMethod)
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set Password to Eap peer
|
|
//
|
|
if (StrLen (Profile->EapPassword) < PASSWORD_MIN_LEN) {
|
|
DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Error: No Eap Password for Network: %s.\n", Profile->SSId));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
PasswordSize = sizeof (CHAR16) * (StrLen (Profile->EapPassword) + 1);
|
|
Password = AllocateZeroPool (PasswordSize);
|
|
if (Password == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
StrCpyS (Password, PasswordSize, Profile->EapPassword);
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_MSCHAPV2,
|
|
EfiEapConfigEapMSChapV2Password,
|
|
(VOID *)Password,
|
|
PasswordSize
|
|
);
|
|
ZeroMem (Password, PasswordSize);
|
|
FreePool (Password);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If CA cert is required, set it to Eap peer
|
|
//
|
|
if (Profile->CACertData != NULL) {
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EapAuthMethod,
|
|
EfiEapConfigEapTlsCACert,
|
|
Profile->CACertData,
|
|
Profile->CACertSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
} else {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else if (EapAuthMethod == EFI_EAP_TYPE_EAPTLS) {
|
|
//
|
|
// Set CA cert to Eap peer
|
|
//
|
|
if (Profile->CACertData == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_EAPTLS,
|
|
EfiEapConfigEapTlsCACert,
|
|
Profile->CACertData,
|
|
Profile->CACertSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set Client cert to Eap peer
|
|
//
|
|
if (Profile->ClientCertData == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_EAPTLS,
|
|
EfiEapConfigEapTlsClientCert,
|
|
Profile->ClientCertData,
|
|
Profile->ClientCertSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set Private key to Eap peer
|
|
//
|
|
if (Profile->PrivateKeyData == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Error: No Private Key for Network: %s.\n", Profile->SSId));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_EAPTLS,
|
|
EfiEapConfigEapTlsClientPrivateKeyFile,
|
|
Profile->PrivateKeyData,
|
|
Profile->PrivateKeyDataSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (StrLen (Profile->PrivateKeyPassword) > 0) {
|
|
EncryptPasswordLen = StrLen (Profile->PrivateKeyPassword);
|
|
AsciiEncryptPassword = AllocateZeroPool (EncryptPasswordLen + 1);
|
|
if (AsciiEncryptPassword == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
UnicodeStrToAsciiStrS (Profile->PrivateKeyPassword, AsciiEncryptPassword, EncryptPasswordLen + 1);
|
|
Status = EapConfig->SetData (
|
|
EapConfig,
|
|
EFI_EAP_TYPE_EAPTLS,
|
|
EfiEapConfigEapTlsClientPrivateKeyFilePassword,
|
|
(VOID *)AsciiEncryptPassword,
|
|
EncryptPasswordLen + 1
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (AsciiEncryptPassword, EncryptPasswordLen + 1);
|
|
FreePool (AsciiEncryptPassword);
|
|
return Status;
|
|
}
|
|
|
|
ZeroMem (AsciiEncryptPassword, EncryptPasswordLen + 1);
|
|
FreePool (AsciiEncryptPassword);
|
|
}
|
|
} else {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get current link state from low layer.
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
@param[out] LinkState The pointer to buffer to retrieve link state.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval EFI_UNSUPPORTED Adapter information protocol is not supported.
|
|
@retval Other Errors Returned errors when retrieving link state from low layer.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrGetLinkState (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic,
|
|
OUT EFI_ADAPTER_INFO_MEDIA_STATE *LinkState
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
UINTN DataSize;
|
|
EFI_ADAPTER_INFO_MEDIA_STATE *UndiState;
|
|
EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
|
|
|
|
if ((Nic == NULL) || (LinkState == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
Status = gBS->OpenProtocol (
|
|
Nic->ControllerHandle,
|
|
&gEfiAdapterInformationProtocolGuid,
|
|
(VOID **)&Aip,
|
|
Nic->DriverHandle,
|
|
Nic->ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = Aip->GetInformation (
|
|
Aip,
|
|
&gEfiAdapterInfoMediaStateGuid,
|
|
(VOID **)&UndiState,
|
|
&DataSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
CopyMem (LinkState, UndiState, sizeof (EFI_ADAPTER_INFO_MEDIA_STATE));
|
|
FreePool (UndiState);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Prepare configuration work before connecting to the target network.
|
|
For WPA2 Personal networks, password should be checked; and for EAP networks, parameters
|
|
are different for different networks.
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
@param[in] Profile The target network to be connected.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_UNSUPPORTED This network is not supported.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrPrepareConnection (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic,
|
|
IN WIFI_MGR_NETWORK_PROFILE *Profile
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 SecurityType;
|
|
BOOLEAN AKMSuiteSupported;
|
|
BOOLEAN CipherSuiteSupported;
|
|
|
|
if ((Profile == NULL) || (Nic == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = WifiMgrCheckRSN (
|
|
Profile->Network.AKMSuite,
|
|
Profile->Network.CipherSuite,
|
|
Nic,
|
|
&SecurityType,
|
|
&AKMSuiteSupported,
|
|
&CipherSuiteSupported
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (AKMSuiteSupported && CipherSuiteSupported) {
|
|
switch (SecurityType) {
|
|
case SECURITY_TYPE_WPA2_PERSONAL:
|
|
case SECURITY_TYPE_WPA3_PERSONAL:
|
|
|
|
Status = WifiMgrConfigPassword (Nic, Profile);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_NOT_FOUND) {
|
|
if (Nic->OneTimeConnectRequest) {
|
|
WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Invalid Password!");
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
break;
|
|
|
|
case SECURITY_TYPE_WPA2_ENTERPRISE:
|
|
case SECURITY_TYPE_WPA3_ENTERPRISE:
|
|
|
|
Status = WifiMgrConfigEap (Nic, Profile);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_INVALID_PARAMETER) {
|
|
if (Nic->OneTimeConnectRequest) {
|
|
WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Invalid Configuration!");
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
break;
|
|
|
|
case SECURITY_TYPE_NONE:
|
|
break;
|
|
|
|
default:
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
} else {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Will reset NiC data, get profile from profile sync driver, and send for
|
|
another connection attempt.This function should not be called more than
|
|
3 times.
|
|
|
|
@param[in] WiFiProfileSyncProtocol The target network profile to connect.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval other Operation failure.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ConnectionRetry (
|
|
IN EDKII_WIFI_PROFILE_SYNC_PROTOCOL *WiFiProfileSyncProtocol
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
WIFI_MGR_DEVICE_DATA *Nic;
|
|
EFI_WIRELESS_MAC_CONNECTION_II_PROTOCOL *Wmp;
|
|
EFI_SUPPLICANT_PROTOCOL *Supplicant;
|
|
EFI_EAP_CONFIGURATION_PROTOCOL *EapConfig;
|
|
|
|
Nic = NULL;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiWiFi2ProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Wmp
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiSupplicantProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Supplicant
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Supplicant = NULL;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiEapConfigurationProtocolGuid,
|
|
NULL,
|
|
(VOID **)&EapConfig
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
EapConfig = NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize Nic device data
|
|
//
|
|
Nic = AllocateZeroPool (sizeof (WIFI_MGR_DEVICE_DATA));
|
|
if (Nic == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
Nic->Signature = WIFI_MGR_DEVICE_DATA_SIGNATURE;
|
|
Nic->Private = mPrivate;
|
|
Nic->Wmp = Wmp;
|
|
Nic->Supplicant = Supplicant;
|
|
Nic->EapConfig = EapConfig;
|
|
Nic->UserSelectedProfile = NULL;
|
|
Nic->OneTimeScanRequest = FALSE;
|
|
|
|
if (Nic->Supplicant != NULL) {
|
|
Status = WifiMgrGetSupportedSuites (Nic);
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
InitializeListHead (&Nic->ProfileList);
|
|
|
|
Nic->ConnectPendingNetwork = (WIFI_MGR_NETWORK_PROFILE *)AllocateZeroPool (sizeof (WIFI_MGR_NETWORK_PROFILE));
|
|
if (Nic->ConnectPendingNetwork == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Failed to allocate memory for ConnectPendingNetwork\n"));
|
|
goto ERROR;
|
|
}
|
|
|
|
Status = WiFiProfileSyncProtocol->GetProfile (Nic->ConnectPendingNetwork, Nic->MacAddress);
|
|
if (!EFI_ERROR (Status) && (Nic->ConnectPendingNetwork != NULL)) {
|
|
Status = WifiMgrConnectToNetwork (Nic, Nic->ConnectPendingNetwork);
|
|
if (!EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Failed to get WiFi profile with status %r\n", Status));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Failed to get Supported suites with status %r\n", Status));
|
|
}
|
|
|
|
if (Nic->ConnectPendingNetwork != NULL) {
|
|
if (Nic->ConnectPendingNetwork->Network.AKMSuite != NULL) {
|
|
FreePool (Nic->ConnectPendingNetwork->Network.AKMSuite);
|
|
}
|
|
|
|
if (Nic->ConnectPendingNetwork->Network.CipherSuite != NULL) {
|
|
FreePool (Nic->ConnectPendingNetwork->Network.CipherSuite);
|
|
}
|
|
|
|
FreePool (Nic->ConnectPendingNetwork);
|
|
}
|
|
|
|
ERROR:
|
|
if (Nic->Supplicant != NULL) {
|
|
if (Nic->SupportedSuites.SupportedAKMSuites != NULL) {
|
|
FreePool (Nic->SupportedSuites.SupportedAKMSuites);
|
|
}
|
|
|
|
if (Nic->SupportedSuites.SupportedSwCipherSuites != NULL) {
|
|
FreePool (Nic->SupportedSuites.SupportedSwCipherSuites);
|
|
}
|
|
|
|
if (Nic->SupportedSuites.SupportedHwCipherSuites != NULL) {
|
|
FreePool (Nic->SupportedSuites.SupportedHwCipherSuites);
|
|
}
|
|
}
|
|
|
|
FreePool (Nic);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The callback function for connect operation.
|
|
|
|
ASSERT when errors occur in config token.
|
|
|
|
@param[in] Event The Connect token receive event.
|
|
@param[in] Context The context of the connect token.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
WifiMgrOnConnectFinished (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
|
|
WIFI_MGR_NETWORK_PROFILE *ConnectedProfile;
|
|
UINT8 SecurityType;
|
|
UINT8 SSIdLen;
|
|
CHAR8 *AsciiSSId;
|
|
EDKII_WIFI_PROFILE_SYNC_PROTOCOL *WiFiProfileSyncProtocol;
|
|
|
|
ASSERT (Context != NULL);
|
|
|
|
ConnectedProfile = NULL;
|
|
ConfigToken = (WIFI_MGR_MAC_CONFIG_TOKEN *)Context;
|
|
ASSERT (ConfigToken->Nic != NULL);
|
|
|
|
ConfigToken->Nic->ConnectState = WifiMgrDisconnected;
|
|
ASSERT (ConfigToken->Type == TokenTypeConnectNetworkToken);
|
|
|
|
ASSERT (ConfigToken->Token.ConnectNetworkToken != NULL);
|
|
|
|
Status = gBS->LocateProtocol (&gEdkiiWiFiProfileSyncProtocolGuid, NULL, (VOID **)&WiFiProfileSyncProtocol);
|
|
if (!EFI_ERROR (Status)) {
|
|
WiFiProfileSyncProtocol->SetConnectState (ConfigToken->Token.ConnectNetworkToken->ResultCode);
|
|
if ((mWifiConnectionCount < MAX_WIFI_CONNETION_ATTEMPTS) &&
|
|
(ConfigToken->Token.ConnectNetworkToken->ResultCode != ConnectSuccess))
|
|
{
|
|
mWifiConnectionCount++;
|
|
gBS->CloseEvent (Event);
|
|
Status = ConnectionRetry (WiFiProfileSyncProtocol);
|
|
if (!EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
WiFiProfileSyncProtocol->SetConnectState (Status);
|
|
}
|
|
}
|
|
|
|
if (ConfigToken->Token.ConnectNetworkToken->Status != EFI_SUCCESS) {
|
|
if (ConfigToken->Nic->OneTimeConnectRequest) {
|
|
//
|
|
// Only update message for user triggered connection
|
|
//
|
|
if (ConfigToken->Token.ConnectNetworkToken->Status == EFI_ACCESS_DENIED) {
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed: Permission Denied!");
|
|
} else {
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed!");
|
|
}
|
|
|
|
ConfigToken->Nic->OneTimeConnectRequest = FALSE;
|
|
}
|
|
|
|
ConfigToken->Nic->CurrentOperateNetwork = NULL;
|
|
return;
|
|
}
|
|
|
|
if (ConfigToken->Token.ConnectNetworkToken->ResultCode != ConnectSuccess) {
|
|
if (ConfigToken->Nic->OneTimeConnectRequest) {
|
|
if (ConfigToken->Token.ConnectNetworkToken->ResultCode == ConnectFailedReasonUnspecified) {
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed: Wrong Password or Unexpected Error!");
|
|
} else {
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed!");
|
|
}
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if ((ConfigToken->Token.ConnectNetworkToken->Data == NULL) ||
|
|
(ConfigToken->Token.ConnectNetworkToken->Data->Network == NULL))
|
|
{
|
|
//
|
|
// An unexpected error occurs, tell low layer to perform a disconnect
|
|
//
|
|
ConfigToken->Nic->HasDisconnectPendingNetwork = TRUE;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// A correct connect token received, terminate the connection process
|
|
//
|
|
Status = WifiMgrCheckRSN (
|
|
ConfigToken->Token.ConnectNetworkToken->Data->Network->AKMSuite,
|
|
ConfigToken->Token.ConnectNetworkToken->Data->Network->CipherSuite,
|
|
ConfigToken->Nic,
|
|
&SecurityType,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
SecurityType = SECURITY_TYPE_UNKNOWN;
|
|
}
|
|
|
|
SSIdLen = ConfigToken->Token.ConnectNetworkToken->Data->Network->SSId.SSIdLen;
|
|
AsciiSSId = (CHAR8 *)AllocateZeroPool (sizeof (CHAR8) * (SSIdLen + 1));
|
|
if (AsciiSSId == NULL) {
|
|
ConfigToken->Nic->HasDisconnectPendingNetwork = TRUE;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
|
|
goto Exit;
|
|
}
|
|
|
|
CopyMem (AsciiSSId, ConfigToken->Token.ConnectNetworkToken->Data->Network->SSId.SSId, SSIdLen);
|
|
*(AsciiSSId + SSIdLen) = '\0';
|
|
|
|
ConnectedProfile = WifiMgrGetProfileByAsciiSSId (AsciiSSId, SecurityType, &ConfigToken->Nic->ProfileList);
|
|
FreePool (AsciiSSId);
|
|
if (ConnectedProfile == NULL) {
|
|
ConfigToken->Nic->HasDisconnectPendingNetwork = TRUE;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
|
|
goto Exit;
|
|
}
|
|
|
|
ConfigToken->Nic->ConnectState = WifiMgrConnectedToAp;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, TRUE, NULL);
|
|
|
|
Exit:
|
|
|
|
if (ConfigToken->Nic->ConnectState == WifiMgrDisconnected) {
|
|
ConfigToken->Nic->CurrentOperateNetwork = NULL;
|
|
}
|
|
|
|
ConfigToken->Nic->OneTimeConnectRequest = FALSE;
|
|
WifiMgrFreeToken (ConfigToken);
|
|
}
|
|
|
|
/**
|
|
Start connect operation, and send out a token to connect to a target network.
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
@param[in] Profile The target network to be connected.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_ALREADY_STARTED Already in "connected" state, need to perform a disconnect
|
|
operation first.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
@retval Other Errors Return errors when connecting network on low layer.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrConnectToNetwork (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic,
|
|
IN WIFI_MGR_NETWORK_PROFILE *Profile
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
EFI_ADAPTER_INFO_MEDIA_STATE LinkState;
|
|
WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
|
|
EFI_80211_CONNECT_NETWORK_TOKEN *ConnectToken;
|
|
|
|
if ((Nic == NULL) || (Nic->Wmp == NULL) || (Profile == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = WifiMgrGetLinkState (Nic, &LinkState);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (LinkState.MediaState == EFI_SUCCESS) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
Status = WifiMgrPrepareConnection (Nic, Profile);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Create a new connect token
|
|
//
|
|
ConfigToken = AllocateZeroPool (sizeof (WIFI_MGR_MAC_CONFIG_TOKEN));
|
|
if (ConfigToken == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
ConfigToken->Type = TokenTypeConnectNetworkToken;
|
|
ConfigToken->Nic = Nic;
|
|
ConfigToken->Token.ConnectNetworkToken = AllocateZeroPool (sizeof (EFI_80211_CONNECT_NETWORK_TOKEN));
|
|
if (ConfigToken->Token.ConnectNetworkToken == NULL) {
|
|
goto Exit;
|
|
}
|
|
|
|
ConnectToken = ConfigToken->Token.ConnectNetworkToken;
|
|
ConnectToken->Data = AllocateZeroPool (sizeof (EFI_80211_CONNECT_NETWORK_DATA));
|
|
if (ConnectToken->Data == NULL) {
|
|
goto Exit;
|
|
}
|
|
|
|
ConnectToken->Data->Network = AllocateZeroPool (sizeof (EFI_80211_NETWORK));
|
|
if (ConnectToken->Data->Network == NULL) {
|
|
goto Exit;
|
|
}
|
|
|
|
CopyMem (ConnectToken->Data->Network, &Profile->Network, sizeof (EFI_80211_NETWORK));
|
|
|
|
//
|
|
// Add event handle and start to connect
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
WifiMgrOnConnectFinished,
|
|
ConfigToken,
|
|
&ConnectToken->Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
Nic->ConnectState = WifiMgrConnectingToAp;
|
|
Nic->CurrentOperateNetwork = Profile;
|
|
WifiMgrUpdateConnectMessage (Nic, FALSE, NULL);
|
|
|
|
//
|
|
// Start Connecting ...
|
|
//
|
|
Status = Nic->Wmp->ConnectNetwork (Nic->Wmp, ConnectToken);
|
|
|
|
//
|
|
// Erase secrets after connection is triggered
|
|
//
|
|
WifiMgrCleanProfileSecrets (Profile);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_ALREADY_STARTED) {
|
|
Nic->ConnectState = WifiMgrConnectedToAp;
|
|
WifiMgrUpdateConnectMessage (Nic, TRUE, NULL);
|
|
} else {
|
|
Nic->ConnectState = WifiMgrDisconnected;
|
|
Nic->CurrentOperateNetwork = NULL;
|
|
|
|
if (Nic->OneTimeConnectRequest) {
|
|
if (Status == EFI_NOT_FOUND) {
|
|
WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Not Available!");
|
|
} else {
|
|
WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Unexpected Error!");
|
|
}
|
|
}
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
DEBUG ((DEBUG_INFO, "[WiFi Connection Manager] WifiMgrConnectToNetwork: %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The callback function for disconnect operation.
|
|
|
|
ASSERT when errors occur in config token.
|
|
|
|
@param[in] Event The Disconnect token receive event.
|
|
@param[in] Context The context of the Disconnect token.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
WifiMgrOnDisconnectFinished (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
|
|
|
|
ASSERT (Context != NULL);
|
|
|
|
ConfigToken = (WIFI_MGR_MAC_CONFIG_TOKEN *)Context;
|
|
ASSERT (ConfigToken->Nic != NULL);
|
|
ASSERT (ConfigToken->Type == TokenTypeDisconnectNetworkToken);
|
|
|
|
ASSERT (ConfigToken->Token.DisconnectNetworkToken != NULL);
|
|
if (ConfigToken->Token.DisconnectNetworkToken->Status != EFI_SUCCESS) {
|
|
ConfigToken->Nic->ConnectState = WifiMgrConnectedToAp;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
|
|
ConfigToken->Nic->OneTimeDisconnectRequest = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
ConfigToken->Nic->ConnectState = WifiMgrDisconnected;
|
|
ConfigToken->Nic->CurrentOperateNetwork = NULL;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, TRUE, NULL);
|
|
ConfigToken->Nic->OneTimeDisconnectRequest = FALSE;
|
|
|
|
//
|
|
// Disconnected network may not be in network list now, trigger a scan again!
|
|
//
|
|
ConfigToken->Nic->OneTimeScanRequest = TRUE;
|
|
|
|
Exit:
|
|
WifiMgrFreeToken (ConfigToken);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Start disconnect operation, and send out a token to disconnect from current connected
|
|
network.
|
|
|
|
@param[in] Nic Pointer to the device data of the selected NIC.
|
|
|
|
@retval EFI_SUCCESS The operation is completed.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
@retval Other Errors Return errors when disconnecting a network on low layer.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WifiMgrDisconnectToNetwork (
|
|
IN WIFI_MGR_DEVICE_DATA *Nic
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
|
|
EFI_80211_DISCONNECT_NETWORK_TOKEN *DisconnectToken;
|
|
|
|
if (Nic == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
Status = EFI_SUCCESS;
|
|
ConfigToken = AllocateZeroPool (sizeof (WIFI_MGR_MAC_CONFIG_TOKEN));
|
|
if (ConfigToken == NULL) {
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ConfigToken->Type = TokenTypeDisconnectNetworkToken;
|
|
ConfigToken->Nic = Nic;
|
|
ConfigToken->Token.DisconnectNetworkToken = AllocateZeroPool (sizeof (EFI_80211_DISCONNECT_NETWORK_TOKEN));
|
|
if (ConfigToken->Token.DisconnectNetworkToken == NULL) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
DisconnectToken = ConfigToken->Token.DisconnectNetworkToken;
|
|
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
WifiMgrOnDisconnectFinished,
|
|
ConfigToken,
|
|
&DisconnectToken->Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
WifiMgrFreeToken (ConfigToken);
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
Nic->ConnectState = WifiMgrDisconnectingToAp;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
|
|
|
|
Status = Nic->Wmp->DisconnectNetwork (Nic->Wmp, DisconnectToken);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_NOT_FOUND) {
|
|
Nic->ConnectState = WifiMgrDisconnected;
|
|
Nic->CurrentOperateNetwork = NULL;
|
|
|
|
//
|
|
// This network is not in network list now, trigger a scan again!
|
|
//
|
|
Nic->OneTimeScanRequest = TRUE;
|
|
|
|
//
|
|
// State has been changed from Connected to Disconnected
|
|
//
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, TRUE, NULL);
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
if (Nic->OneTimeDisconnectRequest) {
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Disconnect Failed: Unexpected Error!");
|
|
}
|
|
|
|
Nic->ConnectState = WifiMgrConnectedToAp;
|
|
WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
|
|
}
|
|
|
|
WifiMgrFreeToken (ConfigToken);
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The state machine of the connection manager, periodically check the state and
|
|
perform a corresponding operation.
|
|
|
|
@param[in] Event The timer event to be triggered.
|
|
@param[in] Context The context of the Nic device data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
WifiMgrOnTimerTick (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
WIFI_MGR_DEVICE_DATA *Nic;
|
|
EFI_STATUS Status;
|
|
EFI_ADAPTER_INFO_MEDIA_STATE LinkState;
|
|
WIFI_MGR_NETWORK_PROFILE *Profile;
|
|
|
|
if (Context == NULL) {
|
|
return;
|
|
}
|
|
|
|
Nic = (WIFI_MGR_DEVICE_DATA *)Context;
|
|
NET_CHECK_SIGNATURE (Nic, WIFI_MGR_DEVICE_DATA_SIGNATURE);
|
|
|
|
Status = WifiMgrGetLinkState (Nic, &LinkState);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "[WiFi Connection Manager] Error: Failed to get link state!\n"));
|
|
return;
|
|
}
|
|
|
|
if (Nic->LastLinkState.MediaState != LinkState.MediaState) {
|
|
if ((Nic->LastLinkState.MediaState == EFI_SUCCESS) && (LinkState.MediaState == EFI_NO_MEDIA)) {
|
|
Nic->HasDisconnectPendingNetwork = TRUE;
|
|
}
|
|
|
|
Nic->LastLinkState.MediaState = LinkState.MediaState;
|
|
}
|
|
|
|
Nic->ScanTickTime++;
|
|
if ((((Nic->ScanTickTime > WIFI_SCAN_FREQUENCY) && (Nic->ConnectState != WifiMgrConnectedToAp)) ||
|
|
Nic->OneTimeScanRequest) && (Nic->ScanState == WifiMgrScanFinished))
|
|
{
|
|
Nic->OneTimeScanRequest = FALSE;
|
|
Nic->ScanTickTime = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "[WiFi Connection Manager] Scan is triggered.\n"));
|
|
WifiMgrStartScan (Nic);
|
|
}
|
|
|
|
if ((Nic->AvailableCount > 0) && (Nic->ScanState == WifiMgrScanFinished)) {
|
|
switch (Nic->ConnectState) {
|
|
case WifiMgrDisconnected:
|
|
|
|
if (Nic->HasDisconnectPendingNetwork) {
|
|
Nic->HasDisconnectPendingNetwork = FALSE;
|
|
}
|
|
|
|
if (Nic->ConnectPendingNetwork != NULL) {
|
|
Profile = Nic->ConnectPendingNetwork;
|
|
Status = WifiMgrConnectToNetwork (Nic, Profile);
|
|
Nic->ConnectPendingNetwork = NULL;
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Some error happened, don't wait for a return connect token!
|
|
//
|
|
Nic->OneTimeConnectRequest = FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case WifiMgrConnectingToAp:
|
|
break;
|
|
|
|
case WifiMgrDisconnectingToAp:
|
|
break;
|
|
|
|
case WifiMgrConnectedToAp:
|
|
|
|
if ((Nic->ConnectPendingNetwork != NULL) || Nic->HasDisconnectPendingNetwork) {
|
|
Status = WifiMgrDisconnectToNetwork (Nic);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Some error happened, don't wait for a return disconnect token!
|
|
//
|
|
Nic->OneTimeDisconnectRequest = FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|