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