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