1 /*
2  * Copyright (C) 2016 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 
17 package com.android.server.wifi;
18 
19 import android.annotation.NonNull;
20 import android.net.wifi.ScanResult;
21 import android.net.wifi.WifiConfiguration;
22 import android.telephony.TelephonyManager;
23 import android.util.LocalLog;
24 import android.util.Pair;
25 
26 import com.android.server.wifi.hotspot2.PasspointNetworkNominateHelper;
27 import com.android.server.wifi.util.WifiPermissionsUtil;
28 
29 import java.util.List;
30 
31 /**
32  * This class is the WifiNetworkSelector.NetworkNominator implementation for
33  * saved networks.
34  */
35 public class SavedNetworkNominator implements WifiNetworkSelector.NetworkNominator {
36     private static final String NAME = "SavedNetworkNominator";
37     private final WifiConfigManager mWifiConfigManager;
38     private final LocalLog mLocalLog;
39     private final WifiCarrierInfoManager mWifiCarrierInfoManager;
40     private final PasspointNetworkNominateHelper mPasspointNetworkNominateHelper;
41     private final WifiPermissionsUtil mWifiPermissionsUtil;
42     private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
43 
SavedNetworkNominator(WifiConfigManager configManager, PasspointNetworkNominateHelper nominateHelper, LocalLog localLog, WifiCarrierInfoManager wifiCarrierInfoManager, WifiPermissionsUtil wifiPermissionsUtil, WifiNetworkSuggestionsManager wifiNetworkSuggestionsManager)44     SavedNetworkNominator(WifiConfigManager configManager,
45             PasspointNetworkNominateHelper nominateHelper, LocalLog localLog,
46             WifiCarrierInfoManager wifiCarrierInfoManager,
47             WifiPermissionsUtil wifiPermissionsUtil,
48             WifiNetworkSuggestionsManager wifiNetworkSuggestionsManager) {
49         mWifiConfigManager = configManager;
50         mPasspointNetworkNominateHelper = nominateHelper;
51         mLocalLog = localLog;
52         mWifiCarrierInfoManager = wifiCarrierInfoManager;
53         mWifiPermissionsUtil = wifiPermissionsUtil;
54         mWifiNetworkSuggestionsManager = wifiNetworkSuggestionsManager;
55     }
56 
localLog(String log)57     private void localLog(String log) {
58         mLocalLog.log(log);
59     }
60 
61     /**
62      * Get the Nominator type.
63      */
64     @Override
getId()65     public @NominatorId int getId() {
66         return NOMINATOR_ID_SAVED;
67     }
68 
69     /**
70      * Get the Nominator name.
71      */
72     @Override
getName()73     public String getName() {
74         return NAME;
75     }
76 
77     /**
78      * Update the Nominator.
79      */
80     @Override
update(List<ScanDetail> scanDetails)81     public void update(List<ScanDetail> scanDetails) {
82         // Update the matching profiles into WifiConfigManager, help displaying Passpoint networks
83         // in Wifi Picker
84         mPasspointNetworkNominateHelper.getPasspointNetworkCandidates(scanDetails, false);
85     }
86 
87     /**
88      * Run through all scanDetails and nominate all connectable network as candidates.
89      *
90      */
91     @Override
nominateNetworks(List<ScanDetail> scanDetails, boolean untrustedNetworkAllowed , boolean oemPaidNetworkAllowed , boolean oemPrivateNetworkAllowed , @NonNull OnConnectableListener onConnectableListener)92     public void nominateNetworks(List<ScanDetail> scanDetails,
93                     boolean untrustedNetworkAllowed /* unused */,
94                     boolean oemPaidNetworkAllowed /* unused */,
95                     boolean oemPrivateNetworkAllowed /* unused */,
96             @NonNull OnConnectableListener onConnectableListener) {
97         findMatchedSavedNetworks(scanDetails, onConnectableListener);
98         findMatchedPasspointNetworks(scanDetails, onConnectableListener);
99     }
100 
findMatchedSavedNetworks(List<ScanDetail> scanDetails, OnConnectableListener onConnectableListener)101     private void findMatchedSavedNetworks(List<ScanDetail> scanDetails,
102             OnConnectableListener onConnectableListener) {
103         for (ScanDetail scanDetail : scanDetails) {
104             ScanResult scanResult = scanDetail.getScanResult();
105 
106             // One ScanResult can be associated with more than one network, hence we calculate all
107             // the scores and use the highest one as the ScanResult's score.
108             WifiConfiguration network =
109                     mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail);
110 
111             if (network == null) {
112                 continue;
113             }
114 
115             /**
116              * Ignore Passpoint and Ephemeral networks. They are configured networks,
117              * but without being persisted to the storage. They are nominated by
118              * {@link PasspointNetworkNominator} and {@link ScoredNetworkNominator}
119              * respectively.
120              */
121             if (network.isPasspoint() || network.isEphemeral()) {
122                 continue;
123             }
124 
125             // Ignore networks that the user has disallowed auto-join for.
126             if (!network.allowAutojoin) {
127                 localLog("Ignoring auto join disabled SSID: " + network.SSID);
128                 continue;
129             }
130 
131             WifiConfiguration.NetworkSelectionStatus status =
132                     network.getNetworkSelectionStatus();
133             status.setSeenInLastQualifiedNetworkSelection(true);
134 
135             if (mWifiConfigManager.isNonCarrierMergedNetworkTemporarilyDisabled(network)) {
136                 localLog("Ignoring non-carrier-merged SSID: " + network.SSID);
137                 continue;
138             }
139             if (mWifiConfigManager.isNetworkTemporarilyDisabledByUser(network.SSID)) {
140                 localLog("Ignoring user disabled SSID: " + network.SSID);
141                 continue;
142             }
143 
144             if (!status.isNetworkEnabled()) {
145                 localLog("Ignoring network selection disabled SSID: " + network.SSID);
146                 continue;
147             }
148             if (network.BSSID != null &&  !network.BSSID.equals("any")
149                     && !network.BSSID.equals(scanResult.BSSID)) {
150                 // App has specified the only BSSID to connect for this
151                 // configuration. So only the matching ScanResult can be a candidate.
152                 localLog("Network " + WifiNetworkSelector.toNetworkString(network)
153                         + " has specified BSSID " + network.BSSID + ". Skip "
154                         + scanResult.BSSID);
155                 continue;
156             }
157             if (isNetworkSimBasedCredential(network) && !isSimBasedNetworkAbleToAutoJoin(network)) {
158                 localLog("Ignoring SIM auto join disabled SSID: " + network.SSID);
159                 continue;
160             }
161 
162             // If the network is marked to use external scores, or is an open network with
163             // curate saved open networks enabled, do not consider it for network selection.
164             if (network.useExternalScores) {
165                 localLog("Network " + WifiNetworkSelector.toNetworkString(network)
166                         + " has external score.");
167                 continue;
168             }
169 
170             if (mWifiNetworkSuggestionsManager
171                     .shouldBeIgnoredBySecureSuggestionFromSameCarrier(network,
172                             scanDetails)) {
173                 localLog("Open Network " + WifiNetworkSelector.toNetworkString(network)
174                         + " has a secure network suggestion from same carrier.");
175                 continue;
176             }
177 
178             onConnectableListener.onConnectable(scanDetail,
179                     mWifiConfigManager.getConfiguredNetwork(network.networkId));
180         }
181     }
182 
findMatchedPasspointNetworks(List<ScanDetail> scanDetails, OnConnectableListener onConnectableListener)183     private void findMatchedPasspointNetworks(List<ScanDetail> scanDetails,
184             OnConnectableListener onConnectableListener) {
185         List<Pair<ScanDetail, WifiConfiguration>> candidates =
186                 mPasspointNetworkNominateHelper.getPasspointNetworkCandidates(scanDetails, false);
187         for (Pair<ScanDetail, WifiConfiguration> candidate : candidates) {
188             WifiConfiguration config = candidate.second;
189             if (!config.allowAutojoin) {
190                 continue;
191             }
192             if (isNetworkSimBasedCredential(config) && !isSimBasedNetworkAbleToAutoJoin(config)) {
193                 continue;
194             }
195             onConnectableListener.onConnectable(candidate.first, config);
196         }
197     }
198 
isSimBasedNetworkAbleToAutoJoin(WifiConfiguration network)199     private boolean isSimBasedNetworkAbleToAutoJoin(WifiConfiguration network) {
200         int carrierId = network.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID
201                 ? mWifiCarrierInfoManager.getDefaultDataSimCarrierId() : network.carrierId;
202         int subId = mWifiCarrierInfoManager.getMatchingSubId(carrierId);
203         // Ignore security type is EAP SIM/AKA/AKA' when SIM is not present.
204         if (!mWifiCarrierInfoManager.isSimReady(subId)) {
205             localLog("No SIM card is good for Network "
206                     + WifiNetworkSelector.toNetworkString(network));
207             return false;
208         }
209         // Ignore IMSI info not available or protection exemption pending network.
210         if (mWifiCarrierInfoManager.requiresImsiEncryption(subId)) {
211             if (!mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(subId)) {
212                 localLog("Imsi protection required but not available for Network "
213                         + WifiNetworkSelector.toNetworkString(network));
214                 return false;
215             }
216         } else if (isImsiProtectionApprovalNeeded(network.creatorUid, carrierId)) {
217             localLog("Imsi protection exemption needed for Network "
218                     + WifiNetworkSelector.toNetworkString(network));
219             return false;
220         }
221         // Ignore metered network with non-data Sim.
222         if (WifiConfiguration.isMetered(network, null)
223                 && mWifiCarrierInfoManager.isCarrierNetworkFromNonDefaultDataSim(network)) {
224             localLog("No default SIM is used for metered Network: "
225                     + WifiNetworkSelector.toNetworkString(network));
226             return false;
227         }
228         return true;
229     }
230 
isNetworkSimBasedCredential(WifiConfiguration network)231     private boolean isNetworkSimBasedCredential(WifiConfiguration network) {
232         return network != null && network.enterpriseConfig != null
233                 && network.enterpriseConfig.isAuthenticationSimBased();
234     }
235 
isImsiProtectionApprovalNeeded(int creatorUid, int carrierId)236     private boolean isImsiProtectionApprovalNeeded(int creatorUid, int carrierId) {
237         // User saved network got exemption.
238         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(creatorUid)
239                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(creatorUid)) {
240             return false;
241         }
242         if (mWifiCarrierInfoManager.hasUserApprovedImsiPrivacyExemptionForCarrier(carrierId)) {
243             return false;
244         }
245         mWifiCarrierInfoManager.sendImsiProtectionExemptionNotificationIfRequired(carrierId);
246         return true;
247     }
248 }
249