1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.wifi; 17 18 import android.annotation.NonNull; 19 import android.net.wifi.ScanResult; 20 import android.net.wifi.WifiConfiguration; 21 22 import com.android.server.wifi.util.ScanResultUtil; 23 24 import java.util.Objects; 25 26 /** 27 * Class to store the info needed to match a scan result to the provided network configuration. 28 */ 29 public class ScanResultMatchInfo { 30 /** 31 * SSID of the network. 32 */ 33 public String networkSsid; 34 /** 35 * Security Type of the network. 36 */ 37 public @WifiConfiguration.SecurityType int networkType; 38 /** 39 * Special flag for PSK-SAE in transition mode 40 */ 41 public boolean pskSaeInTransitionMode; 42 /** 43 * Special flag for OWE in transition mode 44 */ 45 public boolean oweInTransitionMode; 46 47 /** 48 * True if created from a scan result 49 */ 50 private boolean mFromScanResult = false; 51 /** 52 * Fetch network type from network configuration. 53 */ getNetworkType(WifiConfiguration config)54 private static @WifiConfiguration.SecurityType int getNetworkType(WifiConfiguration config) { 55 if (WifiConfigurationUtil.isConfigForSaeNetwork(config)) { 56 return WifiConfiguration.SECURITY_TYPE_SAE; 57 } else if (WifiConfigurationUtil.isConfigForPskNetwork(config)) { 58 return WifiConfiguration.SECURITY_TYPE_PSK; 59 } else if (WifiConfigurationUtil.isConfigForWapiPskNetwork(config)) { 60 return WifiConfiguration.SECURITY_TYPE_WAPI_PSK; 61 } else if (WifiConfigurationUtil.isConfigForWapiCertNetwork(config)) { 62 return WifiConfiguration.SECURITY_TYPE_WAPI_CERT; 63 } else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) { 64 return WifiConfiguration.SECURITY_TYPE_EAP; 65 } else if (WifiConfigurationUtil.isConfigForEapSuiteBNetwork(config)) { 66 return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B; 67 } else if (WifiConfigurationUtil.isConfigForWepNetwork(config)) { 68 return WifiConfiguration.SECURITY_TYPE_WEP; 69 } else if (WifiConfigurationUtil.isConfigForOweNetwork(config)) { 70 return WifiConfiguration.SECURITY_TYPE_OWE; 71 } else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) { 72 return WifiConfiguration.SECURITY_TYPE_OPEN; 73 } 74 throw new IllegalArgumentException("Invalid WifiConfiguration: " + config); 75 } 76 77 /** 78 * Get the ScanResultMatchInfo for the given WifiConfiguration 79 */ fromWifiConfiguration(WifiConfiguration config)80 public static ScanResultMatchInfo fromWifiConfiguration(WifiConfiguration config) { 81 ScanResultMatchInfo info = new ScanResultMatchInfo(); 82 info.networkSsid = config.SSID; 83 info.networkType = getNetworkType(config); 84 return info; 85 } 86 87 /** 88 * Fetch network type from scan result. 89 */ getNetworkType(ScanResult scanResult)90 private static @WifiConfiguration.SecurityType int getNetworkType(ScanResult scanResult) { 91 if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)) { 92 return WifiConfiguration.SECURITY_TYPE_SAE; 93 } else if (ScanResultUtil.isScanResultForWapiPskNetwork(scanResult)) { 94 return WifiConfiguration.SECURITY_TYPE_WAPI_PSK; 95 } else if (ScanResultUtil.isScanResultForWapiCertNetwork(scanResult)) { 96 return WifiConfiguration.SECURITY_TYPE_WAPI_CERT; 97 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) { 98 return WifiConfiguration.SECURITY_TYPE_PSK; 99 } else if (ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) { 100 return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B; 101 } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) { 102 return WifiConfiguration.SECURITY_TYPE_EAP; 103 } else if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) { 104 return WifiConfiguration.SECURITY_TYPE_WEP; 105 } else if (ScanResultUtil.isScanResultForOweNetwork(scanResult)) { 106 return WifiConfiguration.SECURITY_TYPE_OWE; 107 } else if (ScanResultUtil.isScanResultForOpenNetwork(scanResult)) { 108 return WifiConfiguration.SECURITY_TYPE_OPEN; 109 } else { 110 throw new IllegalArgumentException("Invalid ScanResult: " + scanResult); 111 } 112 } 113 114 /** 115 * Get the ScanResultMatchInfo for the given ScanResult 116 */ fromScanResult(ScanResult scanResult)117 public static ScanResultMatchInfo fromScanResult(ScanResult scanResult) { 118 ScanResultMatchInfo info = new ScanResultMatchInfo(); 119 // Scan result ssid's are not quoted, hence add quotes. 120 // TODO: This matching algo works only if the scan result contains a string SSID. 121 // However, according to our public documentation ths {@link WifiConfiguration#SSID} can 122 // either have a hex string or quoted ASCII string SSID. 123 info.networkSsid = ScanResultUtil.createQuotedSSID(scanResult.SSID); 124 info.networkType = getNetworkType(scanResult); 125 info.oweInTransitionMode = false; 126 info.pskSaeInTransitionMode = false; 127 info.mFromScanResult = true; 128 if (info.networkType == WifiConfiguration.SECURITY_TYPE_SAE) { 129 // Note that scan result util will always choose the highest security protocol. 130 info.pskSaeInTransitionMode = 131 ScanResultUtil.isScanResultForPskSaeTransitionNetwork(scanResult); 132 } else if (info.networkType == WifiConfiguration.SECURITY_TYPE_OWE) { 133 // Note that scan result util will always choose OWE. 134 info.oweInTransitionMode = 135 ScanResultUtil.isScanResultForOweTransitionNetwork(scanResult); 136 } 137 return info; 138 } 139 140 /** 141 * Checks for equality of network type. 142 */ networkTypeEquals(@onNull ScanResultMatchInfo other, boolean saeAutoUpgradeEnabled)143 public boolean networkTypeEquals(@NonNull ScanResultMatchInfo other, 144 boolean saeAutoUpgradeEnabled) { 145 boolean networkTypeEquals; 146 // Detect <SSID, PSK+SAE> scan result and say it is equal to <SSID, PSK> configuration 147 if (other.pskSaeInTransitionMode && networkType == WifiConfiguration.SECURITY_TYPE_PSK 148 || (pskSaeInTransitionMode 149 && other.networkType == WifiConfiguration.SECURITY_TYPE_PSK)) { 150 networkTypeEquals = true; 151 } else if ((networkType == WifiConfiguration.SECURITY_TYPE_OPEN 152 && other.oweInTransitionMode) || (oweInTransitionMode 153 && other.networkType == WifiConfiguration.SECURITY_TYPE_OPEN)) { 154 // Special case we treat Enhanced Open and Open as equals. This is done to support the 155 // case where a saved network is Open but we found an OWE in transition network. 156 networkTypeEquals = true; 157 } else if ((saeAutoUpgradeEnabled) 158 && ((mFromScanResult && networkType == WifiConfiguration.SECURITY_TYPE_SAE 159 && other.networkType == WifiConfiguration.SECURITY_TYPE_PSK) 160 || (other.mFromScanResult 161 && other.networkType == WifiConfiguration.SECURITY_TYPE_SAE 162 && networkType == WifiConfiguration.SECURITY_TYPE_PSK))) { 163 // Allow upgrading WPA2 PSK connections to WPA3 SAE AP 164 networkTypeEquals = true; 165 } else { 166 networkTypeEquals = networkType == other.networkType; 167 } 168 return networkTypeEquals; 169 } 170 171 @Override equals(Object otherObj)172 public boolean equals(Object otherObj) { 173 return matchForNetworkSelection(otherObj, false); 174 } 175 176 /** 177 * Match two ScanResultMatchInfo objects while considering configuration in overlays 178 * 179 * @param otherObj Other object to compare against 180 * @param saeAutoUpgradeEnabled A boolean that indicates if WPA3 auto upgrade feature is enabled 181 * @return true if objects are equal for network selection purposes, false otherwise 182 */ matchForNetworkSelection(Object otherObj, boolean saeAutoUpgradeEnabled)183 public boolean matchForNetworkSelection(Object otherObj, boolean saeAutoUpgradeEnabled) { 184 if (this == otherObj) { 185 return true; 186 } else if (!(otherObj instanceof ScanResultMatchInfo)) { 187 return false; 188 } 189 ScanResultMatchInfo other = (ScanResultMatchInfo) otherObj; 190 if (!Objects.equals(networkSsid, other.networkSsid)) { 191 return false; 192 } 193 return networkTypeEquals(other, saeAutoUpgradeEnabled); 194 } 195 196 @Override hashCode()197 public int hashCode() { 198 return Objects.hash(networkSsid); 199 } 200 201 @Override toString()202 public String toString() { 203 return "ScanResultMatchInfo: SSID: " + networkSsid + ", type: " + networkType 204 + ", WPA3 in transition mode: " + pskSaeInTransitionMode 205 + ", OWE in transition mode: " + oweInTransitionMode + ", from scan result: " 206 + mFromScanResult; 207 } 208 } 209