| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.server.wifi; |
| |
| import android.annotation.NonNull; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.WifiConfiguration; |
| |
| import com.android.server.wifi.util.ScanResultUtil; |
| |
| import java.util.Objects; |
| |
| /** |
| * Class to store the info needed to match a scan result to the provided network configuration. |
| */ |
| public class ScanResultMatchInfo { |
| /** |
| * SSID of the network. |
| */ |
| public String networkSsid; |
| /** |
| * Security Type of the network. |
| */ |
| public @WifiConfiguration.SecurityType int networkType; |
| /** |
| * Special flag for PSK-SAE in transition mode |
| */ |
| public boolean pskSaeInTransitionMode; |
| /** |
| * Special flag for OWE in transition mode |
| */ |
| public boolean oweInTransitionMode; |
| |
| /** |
| * True if created from a scan result |
| */ |
| private boolean mFromScanResult = false; |
| /** |
| * Fetch network type from network configuration. |
| */ |
| private static @WifiConfiguration.SecurityType int getNetworkType(WifiConfiguration config) { |
| if (WifiConfigurationUtil.isConfigForSaeNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_SAE; |
| } else if (WifiConfigurationUtil.isConfigForPskNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_PSK; |
| } else if (WifiConfigurationUtil.isConfigForWapiPskNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_WAPI_PSK; |
| } else if (WifiConfigurationUtil.isConfigForWapiCertNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_WAPI_CERT; |
| } else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_EAP; |
| } else if (WifiConfigurationUtil.isConfigForEapSuiteBNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B; |
| } else if (WifiConfigurationUtil.isConfigForWepNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_WEP; |
| } else if (WifiConfigurationUtil.isConfigForOweNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_OWE; |
| } else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) { |
| return WifiConfiguration.SECURITY_TYPE_OPEN; |
| } |
| throw new IllegalArgumentException("Invalid WifiConfiguration: " + config); |
| } |
| |
| /** |
| * Get the ScanResultMatchInfo for the given WifiConfiguration |
| */ |
| public static ScanResultMatchInfo fromWifiConfiguration(WifiConfiguration config) { |
| ScanResultMatchInfo info = new ScanResultMatchInfo(); |
| info.networkSsid = config.SSID; |
| info.networkType = getNetworkType(config); |
| return info; |
| } |
| |
| /** |
| * Fetch network type from scan result. |
| */ |
| private static @WifiConfiguration.SecurityType int getNetworkType(ScanResult scanResult) { |
| if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_SAE; |
| } else if (ScanResultUtil.isScanResultForWapiPskNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_WAPI_PSK; |
| } else if (ScanResultUtil.isScanResultForWapiCertNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_WAPI_CERT; |
| } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_PSK; |
| } else if (ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B; |
| } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_EAP; |
| } else if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_WEP; |
| } else if (ScanResultUtil.isScanResultForOweNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_OWE; |
| } else if (ScanResultUtil.isScanResultForOpenNetwork(scanResult)) { |
| return WifiConfiguration.SECURITY_TYPE_OPEN; |
| } else { |
| throw new IllegalArgumentException("Invalid ScanResult: " + scanResult); |
| } |
| } |
| |
| /** |
| * Get the ScanResultMatchInfo for the given ScanResult |
| */ |
| public static ScanResultMatchInfo fromScanResult(ScanResult scanResult) { |
| ScanResultMatchInfo info = new ScanResultMatchInfo(); |
| // Scan result ssid's are not quoted, hence add quotes. |
| // TODO: This matching algo works only if the scan result contains a string SSID. |
| // However, according to our public documentation ths {@link WifiConfiguration#SSID} can |
| // either have a hex string or quoted ASCII string SSID. |
| info.networkSsid = ScanResultUtil.createQuotedSSID(scanResult.SSID); |
| info.networkType = getNetworkType(scanResult); |
| info.oweInTransitionMode = false; |
| info.pskSaeInTransitionMode = false; |
| info.mFromScanResult = true; |
| if (info.networkType == WifiConfiguration.SECURITY_TYPE_SAE) { |
| // Note that scan result util will always choose the highest security protocol. |
| info.pskSaeInTransitionMode = |
| ScanResultUtil.isScanResultForPskSaeTransitionNetwork(scanResult); |
| } else if (info.networkType == WifiConfiguration.SECURITY_TYPE_OWE) { |
| // Note that scan result util will always choose OWE. |
| info.oweInTransitionMode = |
| ScanResultUtil.isScanResultForOweTransitionNetwork(scanResult); |
| } |
| return info; |
| } |
| |
| /** |
| * Checks for equality of network type. |
| */ |
| public boolean networkTypeEquals(@NonNull ScanResultMatchInfo other, |
| boolean saeAutoUpgradeEnabled) { |
| boolean networkTypeEquals; |
| // Detect <SSID, PSK+SAE> scan result and say it is equal to <SSID, PSK> configuration |
| if (other.pskSaeInTransitionMode && networkType == WifiConfiguration.SECURITY_TYPE_PSK |
| || (pskSaeInTransitionMode |
| && other.networkType == WifiConfiguration.SECURITY_TYPE_PSK)) { |
| networkTypeEquals = true; |
| } else if ((networkType == WifiConfiguration.SECURITY_TYPE_OPEN |
| && other.oweInTransitionMode) || (oweInTransitionMode |
| && other.networkType == WifiConfiguration.SECURITY_TYPE_OPEN)) { |
| // Special case we treat Enhanced Open and Open as equals. This is done to support the |
| // case where a saved network is Open but we found an OWE in transition network. |
| networkTypeEquals = true; |
| } else if ((saeAutoUpgradeEnabled) |
| && ((mFromScanResult && networkType == WifiConfiguration.SECURITY_TYPE_SAE |
| && other.networkType == WifiConfiguration.SECURITY_TYPE_PSK) |
| || (other.mFromScanResult |
| && other.networkType == WifiConfiguration.SECURITY_TYPE_SAE |
| && networkType == WifiConfiguration.SECURITY_TYPE_PSK))) { |
| // Allow upgrading WPA2 PSK connections to WPA3 SAE AP |
| networkTypeEquals = true; |
| } else { |
| networkTypeEquals = networkType == other.networkType; |
| } |
| return networkTypeEquals; |
| } |
| |
| @Override |
| public boolean equals(Object otherObj) { |
| return matchForNetworkSelection(otherObj, false); |
| } |
| |
| /** |
| * Match two ScanResultMatchInfo objects while considering configuration in overlays |
| * |
| * @param otherObj Other object to compare against |
| * @param saeAutoUpgradeEnabled A boolean that indicates if WPA3 auto upgrade feature is enabled |
| * @return true if objects are equal for network selection purposes, false otherwise |
| */ |
| public boolean matchForNetworkSelection(Object otherObj, boolean saeAutoUpgradeEnabled) { |
| if (this == otherObj) { |
| return true; |
| } else if (!(otherObj instanceof ScanResultMatchInfo)) { |
| return false; |
| } |
| ScanResultMatchInfo other = (ScanResultMatchInfo) otherObj; |
| if (!Objects.equals(networkSsid, other.networkSsid)) { |
| return false; |
| } |
| return networkTypeEquals(other, saeAutoUpgradeEnabled); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(networkSsid); |
| } |
| |
| @Override |
| public String toString() { |
| return "ScanResultMatchInfo: SSID: " + networkSsid + ", type: " + networkType |
| + ", WPA3 in transition mode: " + pskSaeInTransitionMode |
| + ", OWE in transition mode: " + oweInTransitionMode + ", from scan result: " |
| + mFromScanResult; |
| } |
| } |