| /** @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; | |
| } | |
| } | |
| } |