CloverBootloader/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.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->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;
}
}
}