summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c1285
1 files changed, 1285 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c b/src/VBox/Devices/EFI/Firmware/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c
new file mode 100644
index 00000000..a326ff16
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c
@@ -0,0 +1,1285 @@
+/** @file
+ The Mac Connection2 Protocol adapter functions for WiFi Connection Manager.
+
+ Copyright (c) 2019, 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
+};
+
+/**
+ 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;
+ }
+ AsciiPassword = AllocateZeroPool ((StrLen(Profile->Password) + 1) * sizeof (UINT8));
+ if (AsciiPassword == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UnicodeStrToAsciiStrS (Profile->Password, (CHAR8 *) AsciiPassword, PASSWORD_STORAGE_SIZE);
+ Status = Supplicant->SetData (Supplicant, EfiSupplicant80211PskPassword,
+ AsciiPassword, (StrLen(Profile->Password) + 1) * sizeof (UINT8));
+ 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;
+ 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) {
+
+ IdentitySize = sizeof(CHAR8) * (StrLen(Profile->EapIdentity) + 1);
+ Identity = AllocateZeroPool (IdentitySize);
+ if (Identity == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ 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:
+
+ 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:
+
+ 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;
+}
+
+/**
+ 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;
+
+ 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);
+ 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;
+ }
+ }
+}