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.annotation.Nullable; 20 import android.net.wifi.ScanResult; 21 import android.net.wifi.SecurityParams; 22 import android.net.wifi.WifiConfiguration; 23 import android.net.wifi.WifiSsid; 24 import android.net.wifi.util.ScanResultUtil; 25 26 import java.util.ArrayList; 27 import java.util.List; 28 import java.util.Objects; 29 30 /** 31 * Class to store the info needed to match a scan result to the provided network configuration. 32 */ 33 public class ScanResultMatchInfo { 34 /** 35 * SSID of the network. 36 */ 37 public String networkSsid; 38 /** 39 * Security params list. 40 */ 41 public List<SecurityParams> securityParamsList = new ArrayList<>(); 42 43 /** 44 * True if created from a scan result 45 */ 46 private boolean mFromScanResult = false; 47 48 /** 49 * Get the ScanResultMatchInfo for the given WifiConfiguration 50 */ fromWifiConfiguration(WifiConfiguration config)51 public static ScanResultMatchInfo fromWifiConfiguration(WifiConfiguration config) { 52 ScanResultMatchInfo info = new ScanResultMatchInfo(); 53 info.networkSsid = config.SSID; 54 info.securityParamsList = config.getSecurityParamsList(); 55 return info; 56 } 57 58 /** 59 * Get the ScanResultMatchInfo for the given ScanResult 60 */ fromScanResult(ScanResult scanResult)61 public static ScanResultMatchInfo fromScanResult(ScanResult scanResult) { 62 ScanResultMatchInfo info = new ScanResultMatchInfo(); 63 WifiSsid wifiSsid = scanResult.getWifiSsid(); 64 if (wifiSsid != null) { 65 info.networkSsid = wifiSsid.toString(); 66 } else { 67 info.networkSsid = "\"" + scanResult.SSID + "\""; 68 } 69 info.securityParamsList = 70 ScanResultUtil.generateSecurityParamsListFromScanResult(scanResult); 71 info.mFromScanResult = true; 72 return info; 73 } 74 75 /** 76 * Check if an auto-upgraded security parameters configuration is allowed by the overlay 77 * configurations for WPA3-Personal (SAE) and Enhanced Open (OWE). 78 * 79 * @param securityParams Security parameters object 80 * @return true if allowed, false if not allowed 81 */ isAutoUpgradeSecurityParamsAllowed(SecurityParams securityParams)82 private static boolean isAutoUpgradeSecurityParamsAllowed(SecurityParams securityParams) { 83 WifiGlobals wifiGlobals = WifiInjector.getInstance().getWifiGlobals(); 84 // In mixed security network environments, we need to filter out APs with the stronger 85 // security type when the current network supports the weaker security type, and the 86 // stronger security type was added by auto-upgrade, and 87 // auto-upgrade feature is disabled. 88 if (securityParams.getSecurityType() == WifiConfiguration.SECURITY_TYPE_SAE 89 && securityParams.isAddedByAutoUpgrade() 90 && !wifiGlobals.isWpa3SaeUpgradeEnabled()) { 91 return false; 92 } 93 if (securityParams.getSecurityType() == WifiConfiguration.SECURITY_TYPE_OWE 94 && securityParams.isAddedByAutoUpgrade() 95 && !wifiGlobals.isOweUpgradeEnabled()) { 96 return false; 97 } 98 return true; 99 } 100 101 /** 102 * The matching algorithm is that the type with a bigger index in the allowed 103 * params list has the higher priority. We try to match each type from the end of 104 * the allowed params list against the params in the scan result params list. 105 * 106 * There are three cases which will skip the match: 107 * 1. the security type is different. 108 * 2. the params is disabled, ex. disabled by Transition Disable Indication. 109 * 3. The params is added by the auto-upgrade mechanism, but the corresponding 110 * feature is not enabled. 111 */ findBestMatchingSecurityParams( List<SecurityParams> allowedParamsList, List<SecurityParams> scanResultParamsList)112 private static @Nullable SecurityParams findBestMatchingSecurityParams( 113 List<SecurityParams> allowedParamsList, 114 List<SecurityParams> scanResultParamsList) { 115 if (null == allowedParamsList) return null; 116 if (null == scanResultParamsList) return null; 117 for (int i = allowedParamsList.size() - 1; i >= 0; i--) { 118 SecurityParams allowedParams = allowedParamsList.get(i); 119 if (!WifiConfigurationUtil.isSecurityParamsValid(allowedParams) 120 || !isAutoUpgradeSecurityParamsAllowed(allowedParams)) { 121 continue; 122 } 123 for (SecurityParams scanResultParams: scanResultParamsList) { 124 if (!allowedParams.isSecurityType(scanResultParams.getSecurityType())) { 125 continue; 126 } 127 return allowedParams; 128 } 129 } 130 return null; 131 } 132 133 /** 134 * Get the best-matching security type between ScanResult and WifiConifiguration. 135 */ getBestMatchingSecurityParams( WifiConfiguration config, ScanResult scanResult)136 public static @Nullable SecurityParams getBestMatchingSecurityParams( 137 WifiConfiguration config, 138 ScanResult scanResult) { 139 if (null == config || null == scanResult) return null; 140 141 return findBestMatchingSecurityParams( 142 config.getSecurityParamsList(), 143 ScanResultUtil.generateSecurityParamsListFromScanResult(scanResult)); 144 } 145 146 /** 147 * Get the best-matching security type between ScanResult and WifiConifiguration. 148 */ getBestMatchingSecurityParams( WifiConfiguration config, List<SecurityParams> scanResultParamsList)149 public static @Nullable SecurityParams getBestMatchingSecurityParams( 150 WifiConfiguration config, 151 List<SecurityParams> scanResultParamsList) { 152 if (null == config || null == scanResultParamsList) return null; 153 154 return findBestMatchingSecurityParams( 155 config.getSecurityParamsList(), 156 scanResultParamsList); 157 } 158 getDefaultSecurityParams()159 public @Nullable SecurityParams getDefaultSecurityParams() { 160 return securityParamsList.isEmpty() ? null : securityParamsList.get(0); 161 } 162 getFirstAvailableSecurityParams()163 public @Nullable SecurityParams getFirstAvailableSecurityParams() { 164 return securityParamsList.stream() 165 .filter(WifiConfigurationUtil::isSecurityParamsValid) 166 .findFirst() 167 .orElse(null); 168 } 169 170 /** 171 * Checks for equality of network type. 172 */ networkTypeEquals(@onNull ScanResultMatchInfo other)173 public boolean networkTypeEquals(@NonNull ScanResultMatchInfo other) { 174 if (null == securityParamsList || null == other.securityParamsList) return false; 175 176 // If both are from the same sources, do normal comparison. 177 if (mFromScanResult == other.mFromScanResult) { 178 return securityParamsList.equals(other.securityParamsList); 179 } 180 181 final List<SecurityParams> allowedParamsList = mFromScanResult 182 ? other.securityParamsList : securityParamsList; 183 final List<SecurityParams> scanResultParamsList = mFromScanResult 184 ? securityParamsList : other.securityParamsList; 185 186 return null != findBestMatchingSecurityParams( 187 allowedParamsList, 188 scanResultParamsList); 189 } 190 191 @Override equals(Object otherObj)192 public boolean equals(Object otherObj) { 193 if (this == otherObj) { 194 return true; 195 } else if (!(otherObj instanceof ScanResultMatchInfo)) { 196 return false; 197 } 198 ScanResultMatchInfo other = (ScanResultMatchInfo) otherObj; 199 if (mFromScanResult == other.mFromScanResult) { 200 return Objects.equals(networkSsid, other.networkSsid) 201 && securityParamsList.equals(other.securityParamsList); 202 } 203 return null != matchForNetworkSelection(other); 204 } 205 206 /** 207 * Match two ScanResultMatchInfo objects while considering configuration in overlays 208 * 209 * @param other Other object to compare against 210 * @return return best matching security params, null if no matching one. 211 */ matchForNetworkSelection(ScanResultMatchInfo other)212 public SecurityParams matchForNetworkSelection(ScanResultMatchInfo other) { 213 if (!Objects.equals(networkSsid, other.networkSsid)) return null; 214 if (null == securityParamsList) return null; 215 if (null == other.securityParamsList) return null; 216 217 final List<SecurityParams> allowedParamsList = mFromScanResult 218 ? other.securityParamsList : securityParamsList; 219 final List<SecurityParams> scanResultParamsList = mFromScanResult 220 ? securityParamsList : other.securityParamsList; 221 222 return findBestMatchingSecurityParams( 223 allowedParamsList, 224 scanResultParamsList); 225 } 226 227 /** Check whether this matchinfo contains the type or not. */ isSecurityType(@ifiConfiguration.SecurityType int securityType)228 public boolean isSecurityType(@WifiConfiguration.SecurityType int securityType) { 229 return securityParamsList.stream().anyMatch(p -> p.isSecurityType(securityType)); 230 } 231 232 @Override hashCode()233 public int hashCode() { 234 return Objects.hash(networkSsid); 235 } 236 237 @Override toString()238 public String toString() { 239 StringBuffer sbuf = new StringBuffer(); 240 sbuf.append("ScanResultMatchInfo: SSID: ").append(networkSsid); 241 sbuf.append(", from scan result: ").append(mFromScanResult); 242 sbuf.append(", SecurityParams List:"); 243 securityParamsList.stream() 244 .forEach(params -> sbuf.append(params.toString())); 245 return sbuf.toString(); 246 } 247 } 248