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