WifiConfigStore.java revision 50bb8f65526b16ca8a354fd485d2ed7a343e97ae
1/* 2 * Copyright (C) 2010 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 17package com.android.server.wifi; 18 19import android.app.AppGlobals; 20import android.app.admin.DeviceAdminInfo; 21import android.app.admin.DevicePolicyManagerInternal; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.ApplicationInfo; 25import android.content.pm.PackageManager; 26import android.content.pm.PackageManager.NameNotFoundException; 27import android.net.IpConfiguration; 28import android.net.IpConfiguration.IpAssignment; 29import android.net.IpConfiguration.ProxySettings; 30import android.net.LinkAddress; 31import android.net.NetworkInfo.DetailedState; 32import android.net.ProxyInfo; 33import android.net.RouteInfo; 34import android.net.StaticIpConfiguration; 35import android.net.wifi.WifiConfiguration; 36import android.net.wifi.WifiConfiguration.KeyMgmt; 37import android.net.wifi.WifiConfiguration.Status; 38 39import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 40 41import android.net.wifi.WifiEnterpriseConfig; 42import android.net.wifi.WifiManager; 43import android.net.wifi.WifiSsid; 44import android.net.wifi.WpsInfo; 45import android.net.wifi.WpsResult; 46import android.net.wifi.ScanResult; 47import android.net.wifi.WifiInfo; 48import android.os.Environment; 49import android.os.FileObserver; 50import android.os.Process; 51import android.os.RemoteException; 52import android.os.SystemClock; 53import android.os.UserHandle; 54import android.provider.Settings; 55import android.security.Credentials; 56import android.security.KeyChain; 57import android.security.KeyStore; 58import android.telephony.SubscriptionManager; 59import android.telephony.TelephonyManager; 60import android.text.TextUtils; 61import android.util.LocalLog; 62import android.util.Log; 63import android.util.SparseArray; 64 65import com.android.server.LocalServices; 66import com.android.server.net.DelayedDiskWrite; 67import com.android.server.net.IpConfigStore; 68import com.android.internal.R; 69import com.android.server.wifi.anqp.ANQPElement; 70import com.android.server.wifi.anqp.Constants; 71import com.android.server.wifi.hotspot2.ANQPData; 72import com.android.server.wifi.hotspot2.AnqpCache; 73import com.android.server.wifi.hotspot2.Chronograph; 74import com.android.server.wifi.hotspot2.NetworkDetail; 75import com.android.server.wifi.hotspot2.PasspointMatch; 76import com.android.server.wifi.hotspot2.PasspointMatchInfo; 77import com.android.server.wifi.hotspot2.SupplicantBridge; 78import com.android.server.wifi.hotspot2.Utils; 79import com.android.server.wifi.hotspot2.omadm.MOManager; 80import com.android.server.wifi.hotspot2.pps.Credential; 81import com.android.server.wifi.hotspot2.pps.HomeSP; 82 83import java.io.BufferedReader; 84import java.io.BufferedInputStream; 85import java.io.DataInputStream; 86import java.io.DataOutputStream; 87import java.io.EOFException; 88import java.io.File; 89import java.io.FileDescriptor; 90import java.io.FileInputStream; 91import java.io.FileNotFoundException; 92import java.io.FileReader; 93import java.io.IOException; 94import java.io.PrintWriter; 95import java.math.BigInteger; 96import java.nio.charset.Charset; 97import java.nio.charset.StandardCharsets; 98import java.security.PrivateKey; 99import java.security.cert.Certificate; 100import java.security.cert.CertificateException; 101import java.text.SimpleDateFormat; 102import java.text.DateFormat; 103import java.util.concurrent.atomic.AtomicBoolean; 104import java.util.concurrent.atomic.AtomicInteger; 105import java.util.regex.Matcher; 106import java.util.regex.Pattern; 107import java.util.*; 108import java.util.zip.Checksum; 109import java.util.zip.CRC32; 110 111 112/** 113 * This class provides the API to manage configured 114 * wifi networks. The API is not thread safe is being 115 * used only from WifiStateMachine. 116 * 117 * It deals with the following 118 * - Add/update/remove a WifiConfiguration 119 * The configuration contains two types of information. 120 * = IP and proxy configuration that is handled by WifiConfigStore and 121 * is saved to disk on any change. 122 * 123 * The format of configuration file is as follows: 124 * <version> 125 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 126 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 127 * .. 128 * 129 * (key, value) pairs for a given network are grouped together and can 130 * be in any order. A EOS at the end of a set of (key, value) pairs 131 * indicates that the next set of (key, value) pairs are for a new 132 * network. A network is identified by a unique ID_KEY. If there is no 133 * ID_KEY in the (key, value) pairs, the data is discarded. 134 * 135 * An invalid version on read would result in discarding the contents of 136 * the file. On the next write, the latest version is written to file. 137 * 138 * Any failures during read or write to the configuration file are ignored 139 * without reporting to the user since the likelihood of these errors are 140 * low and the impact on connectivity is low. 141 * 142 * = SSID & security details that is pushed to the supplicant. 143 * supplicant saves these details to the disk on calling 144 * saveConfigCommand(). 145 * 146 * We have two kinds of APIs exposed: 147 * > public API calls that provide fine grained control 148 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 149 * removeNetwork(). For these calls, the config is not persisted 150 * to the disk. (TODO: deprecate these calls in WifiManager) 151 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 152 * These calls persist the supplicant config to disk. 153 * 154 * - Maintain a list of configured networks for quick access 155 * 156 */ 157public class WifiConfigStore extends IpConfigStore { 158 159 private Context mContext; 160 private static final String TAG = "WifiConfigStore"; 161 private static final boolean DBG = true; 162 private static boolean VDBG = false; 163 private static boolean VVDBG = false; 164 165 private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf"; 166 private static final String PPS_FILE = "/data/misc/wifi/PerProviderSubscription.conf"; 167 168 /* configured networks with network id as the key */ 169 private HashMap<Integer, WifiConfiguration> mConfiguredNetworks = 170 new HashMap<Integer, WifiConfiguration>(); 171 172 /* A network id is a unique identifier for a network configured in the 173 * supplicant. Network ids are generated when the supplicant reads 174 * the configuration file at start and can thus change for networks. 175 * We store the IP configuration for networks along with a unique id 176 * that is generated from SSID and security type of the network. A mapping 177 * from the generated unique id to network id of the network is needed to 178 * map supplicant config to IP configuration. */ 179 private HashMap<Integer, Integer> mNetworkIds = 180 new HashMap<Integer, Integer>(); 181 182 183 /* Stores a map from NetworkId to HomeSP - homeSP being a specification of 184 * passpoint network. This helps tie the triplet { WifiConfiguration, NetworkId, HomeSP } 185 * which should be used in conjunction with each other 186 */ 187 private HashMap<Integer, HomeSP> mConfiguredHomeSPs = new HashMap<Integer, HomeSP>(); 188 189 190 static class ScanDetailCache { 191 private WifiConfiguration mConfig; 192 private HashMap<String, ScanDetail> mMap; 193 194 ScanDetailCache(WifiConfiguration config) { 195 mConfig = config; 196 mMap = new HashMap(); 197 } 198 199 void put(ScanDetail scanDetail) { 200 mMap.put(scanDetail.getBSSIDString(), scanDetail); 201 } 202 203 ScanResult get(String bssid) { 204 ScanDetail scanDetail = getScanDetail(bssid); 205 return scanDetail == null ? null : scanDetail.getScanResult(); 206 } 207 208 ScanDetail getScanDetail(String bssid) { 209 return mMap.get(bssid); 210 } 211 212 void remove(String bssid) { 213 mMap.remove(bssid); 214 } 215 216 int size() { 217 return mMap.size(); 218 } 219 220 boolean isEmpty() { 221 return size() == 0; 222 } 223 224 ScanDetail getFirst() { 225 Iterator<ScanDetail> it = mMap.values().iterator(); 226 return it.hasNext() ? it.next() : null; 227 } 228 229 Collection<String> keySet() { 230 return mMap.keySet(); 231 } 232 233 Collection<ScanDetail> values() { 234 return mMap.values(); 235 } 236 237 public void trim(int num) { 238 int currentSize = mMap.size(); 239 if (currentSize <= num) { 240 return; // Nothing to trim 241 } 242 ArrayList<ScanDetail> list = new ArrayList<ScanDetail>(mMap.values()); 243 if (list.size() != 0) { 244 // Sort by descending timestamp 245 Collections.sort(list, new Comparator() { 246 public int compare(Object o1, Object o2) { 247 ScanDetail a = (ScanDetail)o1; 248 ScanDetail b = (ScanDetail)o2; 249 if (a.getSeen() > b.getSeen()) { 250 return 1; 251 } 252 if (a.getSeen() < b.getSeen()) { 253 return -1; 254 } 255 return a.getBSSIDString().compareTo(b.getBSSIDString()); 256 } 257 }); 258 } 259 for (int i = 0; i < currentSize - num ; i++) { 260 // Remove oldest results from scan cache 261 ScanDetail result = list.get(i); 262 mMap.remove(result.getBSSIDString()); 263 } 264 } 265 266 /* @hide */ 267 private ArrayList<ScanDetail> sort() { 268 ArrayList<ScanDetail> list = new ArrayList<ScanDetail>(mMap.values()); 269 if (list.size() != 0) { 270 Collections.sort(list, new Comparator() { 271 public int compare(Object o1, Object o2) { 272 ScanResult a = ((ScanDetail)o1).getScanResult(); 273 ScanResult b = ((ScanDetail)o2).getScanResult(); 274 if (a.numIpConfigFailures > b.numIpConfigFailures) { 275 return 1; 276 } 277 if (a.numIpConfigFailures < b.numIpConfigFailures) { 278 return -1; 279 } 280 if (a.seen > b.seen) { 281 return -1; 282 } 283 if (a.seen < b.seen) { 284 return 1; 285 } 286 if (a.level > b.level) { 287 return -1; 288 } 289 if (a.level < b.level) { 290 return 1; 291 } 292 return a.BSSID.compareTo(b.BSSID); 293 } 294 }); 295 } 296 return list; 297 } 298 299 public WifiConfiguration.Visibility getVisibility(long age) { 300 WifiConfiguration.Visibility status = new WifiConfiguration.Visibility(); 301 302 long now_ms = System.currentTimeMillis(); 303 for(ScanDetail scanDetail : values()) { 304 ScanResult result = scanDetail.getScanResult(); 305 if (scanDetail.getSeen() == 0) 306 continue; 307 308 if (result.is5GHz()) { 309 //strictly speaking: [4915, 5825] 310 //number of known BSSID on 5GHz band 311 status.num5 = status.num5 + 1; 312 } else if (result.is24GHz()) { 313 //strictly speaking: [2412, 2482] 314 //number of known BSSID on 2.4Ghz band 315 status.num24 = status.num24 + 1; 316 } 317 318 if ((now_ms - result.seen) > age) continue; 319 320 if (result.is5GHz()) { 321 if (result.level > status.rssi5) { 322 status.rssi5 = result.level; 323 status.age5 = result.seen; 324 status.BSSID5 = result.BSSID; 325 } 326 } else if (result.is24GHz()) { 327 if (result.level > status.rssi24) { 328 status.rssi24 = result.level; 329 status.age24 = result.seen; 330 status.BSSID24 = result.BSSID; 331 } 332 } 333 } 334 335 return status; 336 } 337 338 339 340 @Override 341 public String toString() { 342 StringBuilder sbuf = new StringBuilder(); 343 sbuf.append("Scan Cache: ").append('\n'); 344 345 ArrayList<ScanDetail> list = sort(); 346 long now_ms = System.currentTimeMillis(); 347 if (list.size() > 0) { 348 for (ScanDetail scanDetail : list) { 349 ScanResult result = scanDetail.getScanResult(); 350 long milli = now_ms - scanDetail.getSeen(); 351 long ageSec = 0; 352 long ageMin = 0; 353 long ageHour = 0; 354 long ageMilli = 0; 355 long ageDay = 0; 356 if (now_ms > scanDetail.getSeen() && scanDetail.getSeen() > 0) { 357 ageMilli = milli % 1000; 358 ageSec = (milli / 1000) % 60; 359 ageMin = (milli / (60*1000)) % 60; 360 ageHour = (milli / (60*60*1000)) % 24; 361 ageDay = (milli / (24*60*60*1000)); 362 } 363 sbuf.append("{").append(result.BSSID).append(",").append(result.frequency); 364 sbuf.append(",").append(String.format("%3d", result.level)); 365 if (result.autoJoinStatus > 0) { 366 sbuf.append(",st=").append(result.autoJoinStatus); 367 } 368 if (ageSec > 0 || ageMilli > 0) { 369 sbuf.append(String.format(",%4d.%02d.%02d.%02d.%03dms", ageDay, 370 ageHour, ageMin, ageSec, ageMilli)); 371 } 372 if (result.numIpConfigFailures > 0) { 373 sbuf.append(",ipfail="); 374 sbuf.append(result.numIpConfigFailures); 375 } 376 sbuf.append("} "); 377 } 378 sbuf.append('\n'); 379 } 380 381 return sbuf.toString(); 382 } 383 384 } 385 386 387 /* Stores a map of NetworkId to ScanCache */ 388 private HashMap<Integer, ScanDetailCache> mScanDetailCaches; 389 390 /** 391 * Framework keeps a list of (the CRC32 hashes of) all SSIDs that where deleted by user, 392 * so as, framework knows not to re-add those SSIDs automatically to the Saved networks 393 */ 394 private Set<Long> mDeletedSSIDs = new HashSet<Long>(); 395 396 /** 397 * Framework keeps a list of ephemeral SSIDs that where deleted by user, 398 * so as, framework knows not to autojoin again those SSIDs based on scorer input. 399 * The list is never cleared up. 400 * 401 * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. 402 */ 403 public Set<String> mDeletedEphemeralSSIDs = new HashSet<String>(); 404 405 /* Tracks the highest priority of configured networks */ 406 private int mLastPriority = -1; 407 408 private static final String ipConfigFile = Environment.getDataDirectory() + 409 "/misc/wifi/ipconfig.txt"; 410 411 private static final String networkHistoryConfigFile = Environment.getDataDirectory() + 412 "/misc/wifi/networkHistory.txt"; 413 414 private static final String autoJoinConfigFile = Environment.getDataDirectory() + 415 "/misc/wifi/autojoinconfig.txt"; 416 417 /* Network History Keys */ 418 private static final String SSID_KEY = "SSID: "; 419 private static final String CONFIG_KEY = "CONFIG: "; 420 private static final String CHOICE_KEY = "CHOICE: "; 421 private static final String LINK_KEY = "LINK: "; 422 private static final String BSSID_KEY = "BSSID: "; 423 private static final String BSSID_KEY_END = "/BSSID: "; 424 private static final String RSSI_KEY = "RSSI: "; 425 private static final String FREQ_KEY = "FREQ: "; 426 private static final String DATE_KEY = "DATE: "; 427 private static final String MILLI_KEY = "MILLI: "; 428 private static final String BLACKLIST_MILLI_KEY = "BLACKLIST_MILLI: "; 429 private static final String NETWORK_ID_KEY = "ID: "; 430 private static final String PRIORITY_KEY = "PRIORITY: "; 431 private static final String DEFAULT_GW_KEY = "DEFAULT_GW: "; 432 private static final String AUTH_KEY = "AUTH: "; 433 private static final String SEPARATOR_KEY = "\n"; 434 private static final String STATUS_KEY = "AUTO_JOIN_STATUS: "; 435 private static final String BSSID_STATUS_KEY = "BSSID_STATUS: "; 436 private static final String SELF_ADDED_KEY = "SELF_ADDED: "; 437 private static final String FAILURE_KEY = "FAILURE: "; 438 private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD: "; 439 private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION: "; 440 private static final String CREATOR_UID_KEY = "CREATOR_UID_KEY: "; 441 private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY: "; 442 private static final String UPDATE_UID_KEY = "UPDATE_UID: "; 443 private static final String CREATOR_NAME_KEY = "CREATOR_NAME: "; 444 private static final String UPDATE_NAME_KEY = "UPDATE_NAME: "; 445 private static final String USER_APPROVED_KEY = "USER_APPROVED: "; 446 private static final String SUPPLICANT_STATUS_KEY = "SUP_STATUS: "; 447 private static final String SUPPLICANT_DISABLE_REASON_KEY = "SUP_DIS_REASON: "; 448 private static final String FQDN_KEY = "FQDN: "; 449 private static final String NUM_CONNECTION_FAILURES_KEY = "CONNECT_FAILURES: "; 450 private static final String NUM_IP_CONFIG_FAILURES_KEY = "IP_CONFIG_FAILURES: "; 451 private static final String NUM_AUTH_FAILURES_KEY = "AUTH_FAILURES: "; 452 private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE: "; 453 private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH: "; 454 private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS: "; 455 private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS : "; 456 private static final String EPHEMERAL_KEY = "EPHEMERAL: "; 457 private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION: "; 458 private static final String DELETED_CRC32_KEY = "DELETED_CRC32: "; 459 private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL: "; 460 461 private static final String JOIN_ATTEMPT_BOOST_KEY = "JOIN_ATTEMPT_BOOST: "; 462 private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY 463 = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G: "; 464 private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY 465 = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G: "; 466 private static final String THRESHOLD_UNBLACKLIST_HARD_5G_KEY 467 = "THRESHOLD_UNBLACKLIST_HARD_5G: "; 468 private static final String THRESHOLD_UNBLACKLIST_SOFT_5G_KEY 469 = "THRESHOLD_UNBLACKLIST_SOFT_5G: "; 470 private static final String THRESHOLD_UNBLACKLIST_HARD_24G_KEY 471 = "THRESHOLD_UNBLACKLIST_HARD_24G: "; 472 private static final String THRESHOLD_UNBLACKLIST_SOFT_24G_KEY 473 = "THRESHOLD_UNBLACKLIST_SOFT_24G: "; 474 private static final String THRESHOLD_GOOD_RSSI_5_KEY 475 = "THRESHOLD_GOOD_RSSI_5: "; 476 private static final String THRESHOLD_LOW_RSSI_5_KEY 477 = "THRESHOLD_LOW_RSSI_5: "; 478 private static final String THRESHOLD_BAD_RSSI_5_KEY 479 = "THRESHOLD_BAD_RSSI_5: "; 480 private static final String THRESHOLD_GOOD_RSSI_24_KEY 481 = "THRESHOLD_GOOD_RSSI_24: "; 482 private static final String THRESHOLD_LOW_RSSI_24_KEY 483 = "THRESHOLD_LOW_RSSI_24: "; 484 private static final String THRESHOLD_BAD_RSSI_24_KEY 485 = "THRESHOLD_BAD_RSSI_24: "; 486 487 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY 488 = "THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING: "; 489 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY 490 = "THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING: "; 491 492 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY 493 = "THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS: "; 494 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY 495 = "THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS: "; 496 497 private static final String THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY 498 = "THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS: "; 499 private static final String THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY 500 = "THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS: "; 501 502 private static final String MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY 503 = "MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS: "; 504 private static final String MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY 505 = "MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS: "; 506 507 private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW_KEY = 508 "A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW: "; 509 private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY = 510 "A_BAND_PREFERENCE_RSSI_THRESHOLD: "; 511 private static final String G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY = 512 "G_BAND_PREFERENCE_RSSI_THRESHOLD: "; 513 514 private static final String ENABLE_AUTOJOIN_WHILE_ASSOCIATED_KEY 515 = "ENABLE_AUTOJOIN_WHILE_ASSOCIATED: "; 516 517 private static final String ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY 518 = "ASSOCIATED_PARTIAL_SCAN_PERIOD: "; 519 private static final String ASSOCIATED_FULL_SCAN_BACKOFF_KEY 520 = "ASSOCIATED_FULL_SCAN_BACKOFF_PERIOD: "; 521 private static final String ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY 522 = "ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED: "; 523 private static final String ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS_KEY 524 = "ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS: "; 525 526 private static final String ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY 527 = "ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED: "; 528 529 // The three below configurations are mainly for power stats and CPU usage tracking 530 // allowing to incrementally disable framework features 531 private static final String ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED_KEY 532 = "ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED: "; 533 private static final String ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY 534 = "ENABLE_AUTO_JOIN_WHILE_ASSOCIATED: "; 535 private static final String ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY 536 = "ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED: "; 537 private static final String ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY 538 = "ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY: "; 539 540 private static final String idStringVarName = "id_str"; 541 542 // The Wifi verbose log is provided as a way to persist the verbose logging settings 543 // for testing purpose. 544 // It is not intended for normal use. 545 private static final String WIFI_VERBOSE_LOGS_KEY 546 = "WIFI_VERBOSE_LOGS: "; 547 548 // As we keep deleted PSK WifiConfiguration for a while, the PSK of 549 // those deleted WifiConfiguration is set to this random unused PSK 550 private static final String DELETED_CONFIG_PSK = "Mjkd86jEMGn79KhKll298Uu7-deleted"; 551 552 public int maxTxPacketForFullScans = 8; 553 public int maxRxPacketForFullScans = 16; 554 555 public int maxTxPacketForPartialScans = 40; 556 public int maxRxPacketForPartialScans = 80; 557 558 public int associatedFullScanMaxIntervalMilli = 300000; 559 560 // Sane value for roam blacklisting (not switching to a network if already associated) 561 // 2 days 562 public int networkSwitchingBlackListPeriodMilli = 2 * 24 * 60 * 60 * 1000; 563 564 public int bandPreferenceBoostFactor5 = 5; // Boost by 5 dB per dB above threshold 565 public int bandPreferencePenaltyFactor5 = 2; // Penalize by 2 dB per dB below threshold 566 567 public int badLinkSpeed24 = 6; 568 public int badLinkSpeed5 = 12; 569 public int goodLinkSpeed24 = 24; 570 public int goodLinkSpeed5 = 36; 571 572 public int maxAuthErrorsToBlacklist = 4; 573 public int maxConnectionErrorsToBlacklist = 4; 574 public int wifiConfigBlacklistMinTimeMilli = 1000 * 60 * 5; 575 576 // How long a disconnected config remain considered as the last user selection 577 public int wifiConfigLastSelectionHysteresis = 1000 * 60 * 3; 578 579 // Boost RSSI values of associated networks 580 public int associatedHysteresisHigh = +14; 581 public int associatedHysteresisLow = +8; 582 583 boolean showNetworks = true; // TODO set this back to false, used for debugging 17516271 584 585 public boolean roamOnAny = false; 586 public boolean onlyLinkSameCredentialConfigurations = true; 587 588 public boolean enableLinkDebouncing = true; 589 public boolean enable5GHzPreference = true; 590 public boolean enableWifiCellularHandoverUserTriggeredAdjustment = true; 591 592 public int currentNetworkBoost = 25; 593 public int scanResultRssiLevelPatchUp = -85; 594 595 public static final int maxNumScanCacheEntries = 128; 596 597 598 public final AtomicBoolean enableAutoJoinWhenAssociated = new AtomicBoolean(true); 599 public final AtomicBoolean enableFullBandScanWhenAssociated = new AtomicBoolean(true); 600 public final AtomicBoolean enableAutoJoinScanWhenAssociated = new AtomicBoolean(true); 601 public final AtomicBoolean enableChipWakeUpWhenAssociated = new AtomicBoolean(true); 602 public final AtomicBoolean enableRssiPollWhenAssociated = new AtomicBoolean(true); 603 public final AtomicInteger thresholdInitialAutoJoinAttemptMin5RSSI = new AtomicInteger(WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5); 604 public final AtomicInteger thresholdInitialAutoJoinAttemptMin24RSSI = new AtomicInteger(WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24); 605 public final AtomicInteger thresholdUnblacklistThreshold5Hard = new AtomicInteger(); 606 public final AtomicInteger thresholdUnblacklistThreshold5Soft = new AtomicInteger(); 607 public final AtomicInteger thresholdUnblacklistThreshold24Hard = new AtomicInteger(); 608 public final AtomicInteger thresholdUnblacklistThreshold24Soft = new AtomicInteger(); 609 public final AtomicInteger thresholdGoodRssi5 = new AtomicInteger(WifiConfiguration.GOOD_RSSI_5); 610 public final AtomicInteger thresholdLowRssi5 = new AtomicInteger(WifiConfiguration.LOW_RSSI_5); 611 public final AtomicInteger thresholdBadRssi5 = new AtomicInteger(WifiConfiguration.BAD_RSSI_5); 612 public final AtomicInteger thresholdGoodRssi24 = new AtomicInteger(WifiConfiguration.GOOD_RSSI_24); 613 public final AtomicInteger thresholdLowRssi24 = new AtomicInteger(WifiConfiguration.LOW_RSSI_24); 614 public final AtomicInteger thresholdBadRssi24 = new AtomicInteger(WifiConfiguration.BAD_RSSI_24); 615 public final AtomicInteger maxTxPacketForNetworkSwitching = new AtomicInteger(40); 616 public final AtomicInteger maxRxPacketForNetworkSwitching = new AtomicInteger(80); 617 public final AtomicInteger enableVerboseLogging = new AtomicInteger(0); 618 public final AtomicInteger bandPreferenceBoostThreshold5 = new AtomicInteger(WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD); 619 public final AtomicInteger associatedPartialScanPeriodMilli = new AtomicInteger(); 620 public final AtomicInteger associatedFullScanBackoff = new AtomicInteger(12); // Will be divided by 8 by WifiStateMachine 621 public final AtomicInteger bandPreferencePenaltyThreshold5 = new AtomicInteger(WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD); 622 public final AtomicInteger alwaysEnableScansWhileAssociated = new AtomicInteger(0); 623 public final AtomicInteger maxNumPassiveChannelsForPartialScans = new AtomicInteger(2); 624 public final AtomicInteger maxNumActiveChannelsForPartialScans = new AtomicInteger(6); 625 626 private static final Map<String, Object> sKeyMap = new HashMap<>(); 627 628 /** 629 * Regex pattern for extracting a connect choice. 630 * Matches a strings like the following: 631 * <configKey>=([0:9]+) 632 */ 633 private static Pattern mConnectChoice = 634 Pattern.compile("(.*)=([0-9]+)"); 635 636 637 /* Enterprise configuration keys */ 638 /** 639 * In old configurations, the "private_key" field was used. However, newer 640 * configurations use the key_id field with the engine_id set to "keystore". 641 * If this field is found in the configuration, the migration code is 642 * triggered. 643 */ 644 public static final String OLD_PRIVATE_KEY_NAME = "private_key"; 645 646 /** 647 * This represents an empty value of an enterprise field. 648 * NULL is used at wpa_supplicant to indicate an empty value 649 */ 650 static final String EMPTY_VALUE = "NULL"; 651 652 // Internal use only 653 private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { 654 WifiEnterpriseConfig.EAP_KEY, WifiEnterpriseConfig.PHASE2_KEY, 655 WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.ANON_IDENTITY_KEY, 656 WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY, 657 WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY, 658 WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY, 659 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY }; 660 661 662 /** 663 * If Connectivity Service has triggered an unwanted network disconnect 664 */ 665 public long lastUnwantedNetworkDisconnectTimestamp = 0; 666 667 /** 668 * The maximum number of times we will retry a connection to an access point 669 * for which we have failed in acquiring an IP address from DHCP. A value of 670 * N means that we will make N+1 connection attempts in all. 671 * <p> 672 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 673 * value if a Settings value is not present. 674 */ 675 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 676 677 678 private final LocalLog mLocalLog; 679 private final WpaConfigFileObserver mFileObserver; 680 681 private WifiNative mWifiNative; 682 private final KeyStore mKeyStore = KeyStore.getInstance(); 683 684 /** 685 * The lastSelectedConfiguration is used to remember which network 686 * was selected last by the user. 687 * The connection to this network may not be successful, as well 688 * the selection (i.e. network priority) might not be persisted. 689 * WiFi state machine is the only object that sets this variable. 690 */ 691 private String lastSelectedConfiguration = null; 692 693 private final AnqpCache mAnqpCache; 694 private final SupplicantBridge mSupplicantBridge; 695 private final List<String> mImsis; 696 697 WifiConfigStore(Context c, WifiNative wn) { 698 mContext = c; 699 mWifiNative = wn; 700 701 // A map for value setting in readAutoJoinConfig() - replacing the replicated code. 702 sKeyMap.put(ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY, enableAutoJoinWhenAssociated); 703 sKeyMap.put(ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY, enableFullBandScanWhenAssociated); 704 sKeyMap.put(ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED_KEY, enableAutoJoinScanWhenAssociated); 705 sKeyMap.put(ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY, enableChipWakeUpWhenAssociated); 706 sKeyMap.put(ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY, enableRssiPollWhenAssociated); 707 sKeyMap.put(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY, thresholdInitialAutoJoinAttemptMin5RSSI); 708 sKeyMap.put(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY, thresholdInitialAutoJoinAttemptMin24RSSI); 709 sKeyMap.put(THRESHOLD_UNBLACKLIST_HARD_5G_KEY, thresholdUnblacklistThreshold5Hard); 710 sKeyMap.put(THRESHOLD_UNBLACKLIST_SOFT_5G_KEY, thresholdUnblacklistThreshold5Soft); 711 sKeyMap.put(THRESHOLD_UNBLACKLIST_HARD_24G_KEY, thresholdUnblacklistThreshold24Hard); 712 sKeyMap.put(THRESHOLD_UNBLACKLIST_SOFT_24G_KEY, thresholdUnblacklistThreshold24Soft); 713 sKeyMap.put(THRESHOLD_GOOD_RSSI_5_KEY, thresholdGoodRssi5); 714 sKeyMap.put(THRESHOLD_LOW_RSSI_5_KEY, thresholdLowRssi5); 715 sKeyMap.put(THRESHOLD_BAD_RSSI_5_KEY, thresholdBadRssi5); 716 sKeyMap.put(THRESHOLD_GOOD_RSSI_24_KEY, thresholdGoodRssi24); 717 sKeyMap.put(THRESHOLD_LOW_RSSI_24_KEY, thresholdLowRssi24); 718 sKeyMap.put(THRESHOLD_BAD_RSSI_24_KEY, thresholdBadRssi24); 719 sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY, maxTxPacketForNetworkSwitching); 720 sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY, maxRxPacketForNetworkSwitching); 721 sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY, maxTxPacketForNetworkSwitching); 722 sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY, maxRxPacketForNetworkSwitching); 723 sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY, maxTxPacketForNetworkSwitching); 724 sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY, maxRxPacketForNetworkSwitching); 725 sKeyMap.put(WIFI_VERBOSE_LOGS_KEY, enableVerboseLogging); 726 sKeyMap.put(A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, bandPreferenceBoostThreshold5); 727 sKeyMap.put(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY, associatedPartialScanPeriodMilli); 728 sKeyMap.put(ASSOCIATED_FULL_SCAN_BACKOFF_KEY, associatedFullScanBackoff); 729 sKeyMap.put(G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, bandPreferencePenaltyThreshold5); 730 sKeyMap.put(ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY, alwaysEnableScansWhileAssociated); 731 sKeyMap.put(MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, maxNumPassiveChannelsForPartialScans); 732 sKeyMap.put(MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, maxNumActiveChannelsForPartialScans); 733 734 if (showNetworks) { 735 mLocalLog = mWifiNative.getLocalLog(); 736 mFileObserver = new WpaConfigFileObserver(); 737 mFileObserver.startWatching(); 738 } else { 739 mLocalLog = null; 740 mFileObserver = null; 741 } 742 743 associatedPartialScanPeriodMilli.set(mContext.getResources().getInteger( 744 R.integer.config_wifi_framework_associated_scan_interval)); 745 loge("associatedPartialScanPeriodMilli set to " + associatedPartialScanPeriodMilli); 746 747 onlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean( 748 R.bool.config_wifi_only_link_same_credential_configurations); 749 maxNumActiveChannelsForPartialScans.set(mContext.getResources().getInteger( 750 R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels)); 751 maxNumPassiveChannelsForPartialScans.set(mContext.getResources().getInteger( 752 R.integer.config_wifi_framework_associated_partial_scan_max_num_passive_channels)); 753 associatedFullScanMaxIntervalMilli = mContext.getResources().getInteger( 754 R.integer.config_wifi_framework_associated_full_scan_max_interval); 755 associatedFullScanBackoff.set(mContext.getResources().getInteger( 756 R.integer.config_wifi_framework_associated_full_scan_backoff)); 757 enableLinkDebouncing = mContext.getResources().getBoolean( 758 R.bool.config_wifi_enable_disconnection_debounce); 759 760 enable5GHzPreference = mContext.getResources().getBoolean( 761 R.bool.config_wifi_enable_5GHz_preference); 762 763 bandPreferenceBoostFactor5 = mContext.getResources().getInteger( 764 R.integer.config_wifi_framework_5GHz_preference_boost_factor); 765 bandPreferencePenaltyFactor5 = mContext.getResources().getInteger( 766 R.integer.config_wifi_framework_5GHz_preference_penalty_factor); 767 768 bandPreferencePenaltyThreshold5.set(mContext.getResources().getInteger( 769 R.integer.config_wifi_framework_5GHz_preference_penalty_threshold)); 770 bandPreferenceBoostThreshold5.set(mContext.getResources().getInteger( 771 R.integer.config_wifi_framework_5GHz_preference_boost_threshold)); 772 773 associatedHysteresisHigh = mContext.getResources().getInteger( 774 R.integer.config_wifi_framework_current_association_hysteresis_high); 775 associatedHysteresisLow = mContext.getResources().getInteger( 776 R.integer.config_wifi_framework_current_association_hysteresis_low); 777 778 thresholdBadRssi5.set(mContext.getResources().getInteger( 779 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz)); 780 thresholdLowRssi5.set(mContext.getResources().getInteger( 781 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz)); 782 thresholdGoodRssi5.set(mContext.getResources().getInteger( 783 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz)); 784 thresholdBadRssi24.set(mContext.getResources().getInteger( 785 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz)); 786 thresholdLowRssi24.set(mContext.getResources().getInteger( 787 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz)); 788 thresholdGoodRssi24.set(mContext.getResources().getInteger( 789 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)); 790 791 enableWifiCellularHandoverUserTriggeredAdjustment = mContext.getResources().getBoolean( 792 R.bool.config_wifi_framework_cellular_handover_enable_user_triggered_adjustment); 793 794 badLinkSpeed24 = mContext.getResources().getInteger( 795 R.integer.config_wifi_framework_wifi_score_bad_link_speed_24); 796 badLinkSpeed5 = mContext.getResources().getInteger( 797 R.integer.config_wifi_framework_wifi_score_bad_link_speed_5); 798 goodLinkSpeed24 = mContext.getResources().getInteger( 799 R.integer.config_wifi_framework_wifi_score_good_link_speed_24); 800 goodLinkSpeed5 = mContext.getResources().getInteger( 801 R.integer.config_wifi_framework_wifi_score_good_link_speed_5); 802 803 maxAuthErrorsToBlacklist = mContext.getResources().getInteger( 804 R.integer.config_wifi_framework_max_auth_errors_to_blacklist); 805 maxConnectionErrorsToBlacklist = mContext.getResources().getInteger( 806 R.integer.config_wifi_framework_max_connection_errors_to_blacklist); 807 wifiConfigBlacklistMinTimeMilli = mContext.getResources().getInteger( 808 R.integer.config_wifi_framework_network_black_list_min_time_milli); 809 810 811 enableAutoJoinScanWhenAssociated.set(mContext.getResources().getBoolean( 812 R.bool.config_wifi_framework_enable_associated_autojoin_scan)); 813 814 enableAutoJoinWhenAssociated.set(mContext.getResources().getBoolean( 815 R.bool.config_wifi_framework_enable_associated_network_selection)); 816 817 currentNetworkBoost = mContext.getResources().getInteger( 818 R.integer.config_wifi_framework_current_network_boost); 819 820 scanResultRssiLevelPatchUp = mContext.getResources().getInteger( 821 R.integer.config_wifi_framework_scan_result_rssi_level_patchup_value); 822 823 networkSwitchingBlackListPeriodMilli = mContext.getResources().getInteger( 824 R.integer.config_wifi_network_switching_blacklist_time); 825 826 Chronograph chronograph = new Chronograph(); 827 mAnqpCache = new AnqpCache(chronograph); 828 mSupplicantBridge = new SupplicantBridge(mWifiNative, this); 829 mScanDetailCaches = new HashMap(); 830 831 TelephonyManager tm = TelephonyManager.from(mContext); 832 SubscriptionManager sub = SubscriptionManager.from(mContext); 833 834 mImsis = new ArrayList<>(); 835 for (int subId : sub.getActiveSubscriptionIdList()) { 836 mImsis.add(tm.getSubscriberId(subId)); 837 } 838 Log.d("HS2J", "Active IMSIs " + mImsis); 839 } 840 841 void enableVerboseLogging(int verbose) { 842 enableVerboseLogging.set(verbose); 843 if (verbose > 0) { 844 VDBG = true; 845 showNetworks = true; 846 } else { 847 VDBG = false; 848 } 849 if (verbose > 1) { 850 VVDBG = true; 851 } else { 852 VVDBG = false; 853 } 854 } 855 856 class WpaConfigFileObserver extends FileObserver { 857 858 public WpaConfigFileObserver() { 859 super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE); 860 } 861 862 @Override 863 public void onEvent(int event, String path) { 864 if (event == CLOSE_WRITE) { 865 File file = new File(SUPPLICANT_CONFIG_FILE); 866 if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length()); 867 } 868 } 869 } 870 871 872 /** 873 * Fetch the list of configured networks 874 * and enable all stored networks in supplicant. 875 */ 876 void loadAndEnableAllNetworks() { 877 if (DBG) log("Loading config and enabling all networks "); 878 loadConfiguredNetworks(); 879 enableAllNetworks(); 880 } 881 882 int getConfiguredNetworksSize() { 883 return mConfiguredNetworks.size(); 884 } 885 886 private List<WifiConfiguration> getConfiguredNetworks(Map<String, String> pskMap) { 887 List<WifiConfiguration> networks = new ArrayList<>(); 888 for(WifiConfiguration config : mConfiguredNetworks.values()) { 889 WifiConfiguration newConfig = new WifiConfiguration(config); 890 // When updating this condition, update WifiStateMachine's CONNECT_NETWORK handler to 891 // correctly handle updating existing configs that are filtered out here. 892 if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || config.ephemeral) { 893 // Do not enumerate and return this configuration to any one, 894 // for instance WiFi Picker. 895 // instead treat it as unknown. the configuration can still be retrieved 896 // directly by the key or networkId 897 continue; 898 } 899 900 if (pskMap != null && config.allowedKeyManagement != null 901 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 902 && pskMap.containsKey(config.SSID)) { 903 newConfig.preSharedKey = pskMap.get(config.SSID); 904 } 905 networks.add(newConfig); 906 } 907 return networks; 908 } 909 910 /** 911 * Fetch the list of currently configured networks 912 * @return List of networks 913 */ 914 List<WifiConfiguration> getConfiguredNetworks() { 915 return getConfiguredNetworks(null); 916 } 917 918 /** 919 * Fetch the list of currently configured networks, filled with real preSharedKeys 920 * @return List of networks 921 */ 922 List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 923 Map<String, String> pskMap = getCredentialsBySsidMap(); 924 return getConfiguredNetworks(pskMap); 925 } 926 927 /** 928 * Find matching network for this scanResult 929 */ 930 WifiConfiguration getMatchingConfig(ScanResult scanResult) { 931 932 for (Map.Entry entry : mScanDetailCaches.entrySet()) { 933 Integer netId = (Integer) entry.getKey(); 934 ScanDetailCache cache = (ScanDetailCache) entry.getValue(); 935 WifiConfiguration config = getWifiConfiguration(netId); 936 if (config == null) 937 continue; 938 if (cache.get(scanResult.BSSID) != null) { 939 return config; 940 } 941 } 942 943 return null; 944 } 945 946 /** 947 * Fetch the preSharedKeys for all networks. 948 * @return a map from Ssid to preSharedKey. 949 */ 950 private Map<String, String> getCredentialsBySsidMap() { 951 return readNetworkVariablesFromSupplicantFile("psk"); 952 } 953 954 int getConfiguredNetworkSize() { 955 if (mConfiguredNetworks == null) 956 return 0; 957 return mConfiguredNetworks.size(); 958 } 959 960 /** 961 * Fetch the list of currently configured networks that were recently seen 962 * 963 * @return List of networks 964 */ 965 List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) { 966 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 967 968 for (WifiConfiguration config : mConfiguredNetworks.values()) { 969 if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || config.ephemeral) { 970 // Do not enumerate and return this configuration to any one, 971 // instead treat it as unknown. the configuration can still be retrieved 972 // directly by the key or networkId 973 continue; 974 } 975 976 // Calculate the RSSI for scan results that are more recent than milli 977 ScanDetailCache cache = getScanDetailCache(config); 978 if (cache == null) { 979 continue; 980 } 981 config.setVisibility(cache.getVisibility(milli)); 982 if (config.visibility == null) { 983 continue; 984 } 985 if (config.visibility.rssi5 == WifiConfiguration.INVALID_RSSI && 986 config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { 987 continue; 988 } 989 if (copy) { 990 networks.add(new WifiConfiguration(config)); 991 } else { 992 networks.add(config); 993 } 994 } 995 return networks; 996 } 997 998 /** 999 * Update the configuration and BSSID with latest RSSI value. 1000 */ 1001 void updateConfiguration(WifiInfo info) { 1002 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 1003 if (config != null && getScanDetailCache(config) != null) { 1004 ScanDetail scanDetail = getScanDetailCache(config).getScanDetail(info.getBSSID()); 1005 if (scanDetail != null) { 1006 ScanResult result = scanDetail.getScanResult(); 1007 long previousSeen = result.seen; 1008 int previousRssi = result.level; 1009 1010 // Update the scan result 1011 scanDetail.setSeen(); 1012 result.level = info.getRssi(); 1013 1014 // Average the RSSI value 1015 result.averageRssi(previousRssi, previousSeen, 1016 WifiAutoJoinController.mScanResultMaximumAge); 1017 if (VDBG) { 1018 loge("updateConfiguration freq=" + result.frequency 1019 + " BSSID=" + result.BSSID 1020 + " RSSI=" + result.level 1021 + " " + config.configKey()); 1022 } 1023 } 1024 } 1025 } 1026 1027 /** 1028 * get the Wificonfiguration for this netId 1029 * 1030 * @return Wificonfiguration 1031 */ 1032 WifiConfiguration getWifiConfiguration(int netId) { 1033 if (mConfiguredNetworks == null) 1034 return null; 1035 return mConfiguredNetworks.get(netId); 1036 } 1037 1038 /** 1039 * Get the Wificonfiguration for this key 1040 * @return Wificonfiguration 1041 */ 1042 WifiConfiguration getWifiConfiguration(String key) { 1043 if (key == null) 1044 return null; 1045 int hash = key.hashCode(); 1046 if (mNetworkIds == null) 1047 return null; 1048 Integer n = mNetworkIds.get(hash); 1049 if (n == null) 1050 return null; 1051 int netId = n.intValue(); 1052 return getWifiConfiguration(netId); 1053 } 1054 1055 /** 1056 * Enable all networks and save config. This will be a no-op if the list 1057 * of configured networks indicates all networks as being enabled 1058 */ 1059 void enableAllNetworks() { 1060 long now = System.currentTimeMillis(); 1061 boolean networkEnabledStateChanged = false; 1062 1063 for(WifiConfiguration config : mConfiguredNetworks.values()) { 1064 1065 if(config != null && config.status == Status.DISABLED && !config.ephemeral 1066 && (config.autoJoinStatus 1067 <= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) { 1068 1069 // Wait for 5 minutes before reenabling config that have known, repeated connection 1070 // or DHCP failures 1071 if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE 1072 || config.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT 1073 || config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) { 1074 if (config.blackListTimestamp != 0 1075 && now > config.blackListTimestamp 1076 && (now - config.blackListTimestamp) < wifiConfigBlacklistMinTimeMilli) { 1077 continue; 1078 } 1079 } 1080 1081 if(mWifiNative.enableNetwork(config.networkId, false)) { 1082 networkEnabledStateChanged = true; 1083 config.status = Status.ENABLED; 1084 1085 // Reset the blacklist condition 1086 config.numConnectionFailures = 0; 1087 config.numIpConfigFailures = 0; 1088 config.numAuthFailures = 0; 1089 1090 // Reenable the wifi configuration 1091 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 1092 } else { 1093 loge("Enable network failed on " + config.networkId); 1094 } 1095 } 1096 } 1097 1098 if (networkEnabledStateChanged) { 1099 mWifiNative.saveConfig(); 1100 sendConfiguredNetworksChangedBroadcast(); 1101 } 1102 } 1103 1104 private boolean setNetworkPriorityNative(int netId, int priority) { 1105 return mWifiNative.setNetworkVariable(netId, 1106 WifiConfiguration.priorityVarName, Integer.toString(priority)); 1107 } 1108 1109 private boolean setSSIDNative(int netId, String ssid) { 1110 return mWifiNative.setNetworkVariable(netId, WifiConfiguration.ssidVarName, 1111 encodeSSID(ssid)); 1112 } 1113 1114 /** 1115 * Selects the specified network for connection. This involves 1116 * updating the priority of all the networks and enabling the given 1117 * network while disabling others. 1118 * 1119 * Selecting a network will leave the other networks disabled and 1120 * a call to enableAllNetworks() needs to be issued upon a connection 1121 * or a failure event from supplicant 1122 * 1123 * @param netId network to select for connection 1124 * @return false if the network id is invalid 1125 */ 1126 boolean selectNetwork(WifiConfiguration config, boolean updatePriorities) { 1127 if (VDBG) localLog("selectNetwork", config.networkId); 1128 if (config.networkId == INVALID_NETWORK_ID) return false; 1129 1130 // Reset the priority of each network at start or if it goes too high. 1131 boolean saveNetworkHistory = updatePriorities; 1132 if (mLastPriority == -1 || mLastPriority > 1000000) { 1133 for(WifiConfiguration config2 : mConfiguredNetworks.values()) { 1134 if (updatePriorities) { 1135 if (config2.networkId != INVALID_NETWORK_ID) { 1136 config2.priority = 0; 1137 setNetworkPriorityNative(config2.networkId, config.priority); 1138 } 1139 } 1140 if (config2.dirty) { 1141 saveNetworkHistory = true; 1142 } 1143 } 1144 mLastPriority = 0; 1145 } 1146 1147 // Set to the highest priority and save the configuration. 1148 if (updatePriorities) { 1149 config.priority = ++mLastPriority; 1150 setNetworkPriorityNative(config.networkId, config.priority); 1151 } 1152 1153 if (config.isPasspoint()) { 1154 /* need to slap on the SSID of selected bssid to work */ 1155 if (getScanDetailCache(config).size() != 0) { 1156 ScanDetail result = getScanDetailCache(config).getFirst(); 1157 if (result == null) { 1158 loge("Could not find scan result for " + config.BSSID); 1159 } else { 1160 log("Setting SSID for " + config.networkId + " to" + result.getSSID()); 1161 setSSIDNative(config.networkId, result.getSSID()); 1162 } 1163 1164 } else { 1165 loge("Could not find bssid for " + config); 1166 } 1167 } 1168 1169 if (updatePriorities) 1170 mWifiNative.saveConfig(); 1171 else 1172 mWifiNative.selectNetwork(config.networkId); 1173 1174 if (saveNetworkHistory) { 1175 /* TODO: we should remove this from here; selectNetwork * 1176 * shouldn't have this side effect of saving data */ 1177 writeKnownNetworkHistory(false); 1178 } 1179 1180 /* Enable the given network while disabling all other networks */ 1181 enableNetworkWithoutBroadcast(config.networkId, true); 1182 1183 /* Avoid saving the config & sending a broadcast to prevent settings 1184 * from displaying a disabled list of networks */ 1185 return true; 1186 } 1187 1188 /** 1189 * Add/update the specified configuration and save config 1190 * 1191 * @param config WifiConfiguration to be saved 1192 * @return network update result 1193 */ 1194 NetworkUpdateResult saveNetwork(WifiConfiguration config, int uid) { 1195 WifiConfiguration conf; 1196 1197 // A new network cannot have null SSID 1198 if (config == null || (config.networkId == INVALID_NETWORK_ID && 1199 config.SSID == null)) { 1200 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1201 } 1202 if (VDBG) localLog("WifiConfigStore: saveNetwork netId", config.networkId); 1203 if (VDBG) { 1204 loge("WifiConfigStore saveNetwork, size=" + mConfiguredNetworks.size() 1205 + " SSID=" + config.SSID 1206 + " Uid=" + Integer.toString(config.creatorUid) 1207 + "/" + Integer.toString(config.lastUpdateUid)); 1208 } 1209 1210 if (mDeletedEphemeralSSIDs.remove(config.SSID)) { 1211 if (VDBG) { 1212 loge("WifiConfigStore: removed from ephemeral blacklist: " + config.SSID); 1213 } 1214 // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call 1215 // below, since we're creating/modifying a config. 1216 } 1217 1218 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 1219 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 1220 int netId = result.getNetworkId(); 1221 1222 if (VDBG) localLog("WifiConfigStore: saveNetwork got it back netId=", netId); 1223 1224 /* enable a new network */ 1225 if (newNetwork && netId != INVALID_NETWORK_ID) { 1226 if (VDBG) localLog("WifiConfigStore: will enable netId=", netId); 1227 1228 mWifiNative.enableNetwork(netId, false); 1229 conf = mConfiguredNetworks.get(netId); 1230 if (conf != null) 1231 conf.status = Status.ENABLED; 1232 } 1233 1234 conf = mConfiguredNetworks.get(netId); 1235 if (conf != null) { 1236 if (conf.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) { 1237 if (VDBG) localLog("WifiConfigStore: re-enabling: " + conf.SSID); 1238 1239 // reenable autojoin, since new information has been provided 1240 conf.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 1241 enableNetworkWithoutBroadcast(conf.networkId, false); 1242 } 1243 if (VDBG) { 1244 loge("WifiConfigStore: saveNetwork got config back netId=" 1245 + Integer.toString(netId) 1246 + " uid=" + Integer.toString(config.creatorUid)); 1247 } 1248 } 1249 1250 mWifiNative.saveConfig(); 1251 sendConfiguredNetworksChangedBroadcast(conf, result.isNewNetwork() ? 1252 WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1253 return result; 1254 } 1255 1256 /** 1257 * Firmware is roaming away from this BSSID, and this BSSID was on 5GHz, and it's RSSI was good, 1258 * this means we have a situation where we would want to remain on this BSSID but firmware 1259 * is not successful at it. 1260 * This situation is observed on a small number of Access Points, b/17960587 1261 * In that situation, blacklist this BSSID really hard so as framework will not attempt to 1262 * roam to it for the next 8 hours. We do not to keep flipping between 2.4 and 5GHz band.. 1263 * TODO: review the blacklisting strategy so as to make it softer and adaptive 1264 * @param info 1265 */ 1266 void driverRoamedFrom(WifiInfo info) { 1267 if (info != null 1268 && info.getBSSID() != null 1269 && ScanResult.is5GHz(info.getFrequency()) 1270 && info.getRssi() > (bandPreferenceBoostThreshold5.get() + 3)) { 1271 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 1272 if (config != null) { 1273 if (getScanDetailCache(config) != null) { 1274 ScanResult result = getScanDetailCache(config).get(info.getBSSID()); 1275 if (result != null) { 1276 result.setAutoJoinStatus(ScanResult.AUTO_ROAM_DISABLED + 1); 1277 } 1278 } 1279 } 1280 } 1281 } 1282 1283 void noteRoamingFailure(WifiConfiguration config, int reason) { 1284 if (config == null) return; 1285 config.lastRoamingFailure = System.currentTimeMillis(); 1286 config.roamingFailureBlackListTimeMilli 1287 = 2 * (config.roamingFailureBlackListTimeMilli + 1000); 1288 if (config.roamingFailureBlackListTimeMilli 1289 > networkSwitchingBlackListPeriodMilli) { 1290 config.roamingFailureBlackListTimeMilli = 1291 networkSwitchingBlackListPeriodMilli; 1292 } 1293 config.lastRoamingFailureReason = reason; 1294 } 1295 1296 void saveWifiConfigBSSID(WifiConfiguration config) { 1297 // Sanity check the config is valid 1298 if (config == null || (config.networkId == INVALID_NETWORK_ID && 1299 config.SSID == null)) { 1300 return; 1301 } 1302 1303 // If an app specified a BSSID then dont over-write it 1304 if (config.BSSID != null && config.BSSID != "any") { 1305 return; 1306 } 1307 1308 // If autojoin specified a BSSID then write it in the network block 1309 if (config.autoJoinBSSID != null) { 1310 loge("saveWifiConfigBSSID Setting BSSID for " + config.configKey() 1311 + " to " + config.autoJoinBSSID); 1312 if (!mWifiNative.setNetworkVariable( 1313 config.networkId, 1314 WifiConfiguration.bssidVarName, 1315 config.autoJoinBSSID)) { 1316 loge("failed to set BSSID: " + config.autoJoinBSSID); 1317 } else if (config.autoJoinBSSID.equals("any")) { 1318 // Paranoia, we just want to make sure that we restore the config to normal 1319 mWifiNative.saveConfig(); 1320 } 1321 } 1322 } 1323 1324 1325 void updateStatus(int netId, DetailedState state) { 1326 if (netId != INVALID_NETWORK_ID) { 1327 WifiConfiguration config = mConfiguredNetworks.get(netId); 1328 if (config == null) return; 1329 switch (state) { 1330 case CONNECTED: 1331 config.status = Status.CURRENT; 1332 //we successfully connected, hence remove the blacklist 1333 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 1334 break; 1335 case DISCONNECTED: 1336 //If network is already disabled, keep the status 1337 if (config.status == Status.CURRENT) { 1338 config.status = Status.ENABLED; 1339 } 1340 break; 1341 default: 1342 //do nothing, retain the existing state 1343 break; 1344 } 1345 } 1346 } 1347 1348 1349 /** 1350 * Disable an ephemeral SSID for the purpose of auto-joining thru scored. 1351 * This SSID will never be scored anymore. 1352 * The only way to "un-disable it" is if the user create a network for that SSID and then 1353 * forget it. 1354 * 1355 * @param SSID caller must ensure that the SSID passed thru this API match 1356 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 1357 * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can 1358 * disconnect if this is the current network. 1359 */ 1360 WifiConfiguration disableEphemeralNetwork(String SSID) { 1361 if (SSID == null) { 1362 return null; 1363 } 1364 1365 WifiConfiguration foundConfig = null; 1366 1367 mDeletedEphemeralSSIDs.add(SSID); 1368 loge("Forget ephemeral SSID " + SSID + " num=" + mDeletedEphemeralSSIDs.size()); 1369 1370 for (WifiConfiguration config : mConfiguredNetworks.values()) { 1371 if (SSID.equals(config.SSID) && config.ephemeral) { 1372 loge("Found ephemeral config in disableEphemeralNetwork: " + config.networkId); 1373 foundConfig = config; 1374 } 1375 } 1376 1377 // Force a write, because the mDeletedEphemeralSSIDs list has changed even though the 1378 // configurations may not have. 1379 writeKnownNetworkHistory(true); 1380 1381 return foundConfig; 1382 } 1383 1384 /** 1385 * Forget the specified network and save config 1386 * 1387 * @param netId network to forget 1388 * @return {@code true} if it succeeds, {@code false} otherwise 1389 */ 1390 boolean forgetNetwork(int netId) { 1391 if (showNetworks) localLog("forgetNetwork", netId); 1392 1393 boolean remove = removeConfigAndSendBroadcastIfNeeded(netId); 1394 if (!remove) { 1395 //success but we dont want to remove the network from supplicant conf file 1396 return true; 1397 } 1398 if (mWifiNative.removeNetwork(netId)) { 1399 mWifiNative.saveConfig(); 1400 return true; 1401 } else { 1402 loge("Failed to remove network " + netId); 1403 return false; 1404 } 1405 } 1406 1407 /** 1408 * Add/update a network. Note that there is no saveConfig operation. 1409 * This function is retained for compatibility with the public 1410 * API. The more powerful saveNetwork() is used by the 1411 * state machine 1412 * 1413 * @param config wifi configuration to add/update 1414 * @return network Id 1415 */ 1416 int addOrUpdateNetwork(WifiConfiguration config, int uid) { 1417 if (showNetworks) localLog("addOrUpdateNetwork id=", config.networkId); 1418 //adding unconditional message to chase b/15111865 1419 Log.e(TAG, " key=" + config.configKey() + " netId=" + Integer.toString(config.networkId) 1420 + " uid=" + Integer.toString(config.creatorUid) 1421 + "/" + Integer.toString(config.lastUpdateUid)); 1422 1423 if (config.isPasspoint()) { 1424 /* create a temporary SSID with providerFriendlyName */ 1425 Long csum = getChecksum(config.FQDN); 1426 config.SSID = csum.toString(); 1427 } 1428 1429 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 1430 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 1431 WifiConfiguration conf = mConfiguredNetworks.get(result.getNetworkId()); 1432 if (conf != null) { 1433 sendConfiguredNetworksChangedBroadcast(conf, 1434 result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : 1435 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1436 } 1437 } 1438 1439 return result.getNetworkId(); 1440 } 1441 1442 /** 1443 * Remove a network. Note that there is no saveConfig operation. 1444 * This function is retained for compatibility with the public 1445 * API. The more powerful forgetNetwork() is used by the 1446 * state machine for network removal 1447 * 1448 * @param netId network to be removed 1449 * @return {@code true} if it succeeds, {@code false} otherwise 1450 */ 1451 boolean removeNetwork(int netId) { 1452 if (showNetworks) localLog("removeNetwork", netId); 1453 boolean ret = mWifiNative.removeNetwork(netId); 1454 if (ret) { 1455 removeConfigAndSendBroadcastIfNeeded(netId); 1456 } 1457 return ret; 1458 } 1459 1460 1461 static private Long getChecksum(String source) { 1462 Checksum csum = new CRC32(); 1463 csum.update(source.getBytes(), 0, source.getBytes().length); 1464 return csum.getValue(); 1465 } 1466 1467 private boolean removeConfigAndSendBroadcastIfNeeded(int netId) { 1468 WifiConfiguration config = mConfiguredNetworks.get(netId); 1469 if (config != null) { 1470 if (VDBG) { 1471 loge("removeNetwork " + Integer.toString(netId) + " key=" + 1472 config.configKey() + " config.id=" + Integer.toString(config.networkId)); 1473 } 1474 1475 // cancel the last user choice 1476 if (config.configKey().equals(lastSelectedConfiguration)) { 1477 lastSelectedConfiguration = null; 1478 } 1479 1480 // Remove any associated keys 1481 if (config.enterpriseConfig != null) { 1482 removeKeys(config.enterpriseConfig); 1483 } 1484 1485 if (config.selfAdded || config.linkedConfigurations != null 1486 || config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 1487 if (!TextUtils.isEmpty(config.SSID)) { 1488 /* Remember that we deleted this PSK SSID */ 1489 if (config.SSID != null) { 1490 Long csum = getChecksum(config.SSID); 1491 mDeletedSSIDs.add(csum); 1492 loge("removeNetwork " + Integer.toString(netId) 1493 + " key=" + config.configKey() 1494 + " config.id=" + Integer.toString(config.networkId) 1495 + " crc=" + csum); 1496 } else { 1497 loge("removeNetwork " + Integer.toString(netId) 1498 + " key=" + config.configKey() 1499 + " config.id=" + Integer.toString(config.networkId)); 1500 } 1501 } 1502 } 1503 1504 mConfiguredNetworks.remove(netId); 1505 mNetworkIds.remove(configKey(config)); 1506 mScanDetailCaches.remove(netId); 1507 1508 writeIpAndProxyConfigurations(); 1509 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 1510 writeKnownNetworkHistory(true); 1511 } 1512 return true; 1513 } 1514 1515 /* 1516 * Remove all networks associated with an application 1517 * 1518 * @param packageName name of the package of networks to remove 1519 * @return {@code true} if all networks removed successfully, {@code false} otherwise 1520 */ 1521 boolean removeNetworksForApp(ApplicationInfo app) { 1522 if (app == null || app.packageName == null) { 1523 return false; 1524 } 1525 1526 boolean success = true; 1527 1528 WifiConfiguration [] copiedConfigs = 1529 mConfiguredNetworks.values().toArray(new WifiConfiguration[0]); 1530 for (WifiConfiguration config : copiedConfigs) { 1531 if (app.uid != config.creatorUid || !app.packageName.equals(config.creatorName)) { 1532 continue; 1533 } 1534 if (showNetworks) { 1535 localLog("Removing network " + config.SSID 1536 + ", application \"" + app.packageName + "\" uninstalled" 1537 + " from user " + UserHandle.getUserId(app.uid)); 1538 } 1539 success &= removeNetwork(config.networkId); 1540 } 1541 1542 mWifiNative.saveConfig(); 1543 1544 return success; 1545 } 1546 1547 boolean removeNetworksForUser(int userId) { 1548 boolean success = true; 1549 1550 WifiConfiguration[] copiedConfigs = 1551 mConfiguredNetworks.values().toArray(new WifiConfiguration[0]); 1552 for (WifiConfiguration config : copiedConfigs) { 1553 if (userId != UserHandle.getUserId(config.creatorUid)) { 1554 continue; 1555 } 1556 success &= removeNetwork(config.networkId); 1557 if (showNetworks) { 1558 localLog("Removing network " + config.SSID 1559 + ", user " + userId + " removed"); 1560 } 1561 } 1562 1563 return success; 1564 } 1565 1566 /** 1567 * Enable a network. Note that there is no saveConfig operation. 1568 * This function is retained for compatibility with the public 1569 * API. The more powerful selectNetwork()/saveNetwork() is used by the 1570 * state machine for connecting to a network 1571 * 1572 * @param netId network to be enabled 1573 * @return {@code true} if it succeeds, {@code false} otherwise 1574 */ 1575 boolean enableNetwork(int netId, boolean disableOthers) { 1576 boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); 1577 if (disableOthers) { 1578 if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId); 1579 sendConfiguredNetworksChangedBroadcast(); 1580 } else { 1581 if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId); 1582 WifiConfiguration enabledNetwork = null; 1583 synchronized(mConfiguredNetworks) { 1584 enabledNetwork = mConfiguredNetworks.get(netId); 1585 } 1586 // check just in case the network was removed by someone else. 1587 if (enabledNetwork != null) { 1588 sendConfiguredNetworksChangedBroadcast(enabledNetwork, 1589 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1590 } 1591 } 1592 return ret; 1593 } 1594 1595 boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { 1596 boolean ret = mWifiNative.enableNetwork(netId, disableOthers); 1597 1598 WifiConfiguration config = mConfiguredNetworks.get(netId); 1599 if (config != null) config.status = Status.ENABLED; 1600 1601 if (disableOthers) { 1602 markAllNetworksDisabledExcept(netId); 1603 } 1604 return ret; 1605 } 1606 1607 void disableAllNetworks() { 1608 if (VDBG) localLog("disableAllNetworks"); 1609 boolean networkDisabled = false; 1610 for(WifiConfiguration config : mConfiguredNetworks.values()) { 1611 if(config != null && config.status != Status.DISABLED) { 1612 if(mWifiNative.disableNetwork(config.networkId)) { 1613 networkDisabled = true; 1614 config.status = Status.DISABLED; 1615 } else { 1616 loge("Disable network failed on " + config.networkId); 1617 } 1618 } 1619 } 1620 1621 if (networkDisabled) { 1622 sendConfiguredNetworksChangedBroadcast(); 1623 } 1624 } 1625 /** 1626 * Disable a network. Note that there is no saveConfig operation. 1627 * @param netId network to be disabled 1628 * @return {@code true} if it succeeds, {@code false} otherwise 1629 */ 1630 boolean disableNetwork(int netId) { 1631 return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); 1632 } 1633 1634 /** 1635 * Disable a network. Note that there is no saveConfig operation. 1636 * @param netId network to be disabled 1637 * @param reason reason code network was disabled 1638 * @return {@code true} if it succeeds, {@code false} otherwise 1639 */ 1640 boolean disableNetwork(int netId, int reason) { 1641 if (VDBG) localLog("disableNetwork", netId); 1642 boolean ret = mWifiNative.disableNetwork(netId); 1643 WifiConfiguration network = null; 1644 WifiConfiguration config = mConfiguredNetworks.get(netId); 1645 1646 if (VDBG) { 1647 if (config != null) { 1648 loge("disableNetwork netId=" + Integer.toString(netId) 1649 + " SSID=" + config.SSID 1650 + " disabled=" + (config.status == Status.DISABLED) 1651 + " reason=" + Integer.toString(config.disableReason)); 1652 } 1653 } 1654 /* Only change the reason if the network was not previously disabled 1655 /* and the reason is not DISABLED_BY_WIFI_MANAGER, that is, if a 3rd party 1656 * set its configuration as disabled, then leave it disabled */ 1657 if (config != null) { 1658 if (config.status != Status.DISABLED 1659 && config.disableReason != WifiConfiguration.DISABLED_BY_WIFI_MANAGER) { 1660 config.status = Status.DISABLED; 1661 config.disableReason = reason; 1662 network = config; 1663 } 1664 if (reason == WifiConfiguration.DISABLED_BY_WIFI_MANAGER) { 1665 // Make sure autojoin wont reenable this configuration without further user 1666 // intervention 1667 config.status = Status.DISABLED; 1668 config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_DISABLED_USER_ACTION; 1669 } 1670 } 1671 if (network != null) { 1672 sendConfiguredNetworksChangedBroadcast(network, 1673 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1674 } 1675 return ret; 1676 } 1677 1678 /** 1679 * Save the configured networks in supplicant to disk 1680 * @return {@code true} if it succeeds, {@code false} otherwise 1681 */ 1682 boolean saveConfig() { 1683 return mWifiNative.saveConfig(); 1684 } 1685 1686 /** 1687 * Start WPS pin method configuration with pin obtained 1688 * from the access point 1689 * @param config WPS configuration 1690 * @return Wps result containing status and pin 1691 */ 1692 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 1693 WpsResult result = new WpsResult(); 1694 if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { 1695 /* WPS leaves all networks disabled */ 1696 markAllNetworksDisabled(); 1697 result.status = WpsResult.Status.SUCCESS; 1698 } else { 1699 loge("Failed to start WPS pin method configuration"); 1700 result.status = WpsResult.Status.FAILURE; 1701 } 1702 return result; 1703 } 1704 1705 /** 1706 * Start WPS pin method configuration with pin obtained 1707 * from the device 1708 * @return WpsResult indicating status and pin 1709 */ 1710 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 1711 WpsResult result = new WpsResult(); 1712 result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); 1713 /* WPS leaves all networks disabled */ 1714 if (!TextUtils.isEmpty(result.pin)) { 1715 markAllNetworksDisabled(); 1716 result.status = WpsResult.Status.SUCCESS; 1717 } else { 1718 loge("Failed to start WPS pin method configuration"); 1719 result.status = WpsResult.Status.FAILURE; 1720 } 1721 return result; 1722 } 1723 1724 /** 1725 * Start WPS push button configuration 1726 * @param config WPS configuration 1727 * @return WpsResult indicating status and pin 1728 */ 1729 WpsResult startWpsPbc(WpsInfo config) { 1730 WpsResult result = new WpsResult(); 1731 if (mWifiNative.startWpsPbc(config.BSSID)) { 1732 /* WPS leaves all networks disabled */ 1733 markAllNetworksDisabled(); 1734 result.status = WpsResult.Status.SUCCESS; 1735 } else { 1736 loge("Failed to start WPS push button configuration"); 1737 result.status = WpsResult.Status.FAILURE; 1738 } 1739 return result; 1740 } 1741 1742 /** 1743 * Fetch the static IP configuration for a given network id 1744 */ 1745 StaticIpConfiguration getStaticIpConfiguration(int netId) { 1746 WifiConfiguration config = mConfiguredNetworks.get(netId); 1747 if (config != null) { 1748 return config.getStaticIpConfiguration(); 1749 } 1750 return null; 1751 } 1752 1753 /** 1754 * Set the static IP configuration for a given network id 1755 */ 1756 void setStaticIpConfiguration(int netId, StaticIpConfiguration staticIpConfiguration) { 1757 WifiConfiguration config = mConfiguredNetworks.get(netId); 1758 if (config != null) { 1759 config.setStaticIpConfiguration(staticIpConfiguration); 1760 } 1761 } 1762 1763 /** 1764 * set default GW MAC address 1765 */ 1766 void setDefaultGwMacAddress(int netId, String macAddress) { 1767 WifiConfiguration config = mConfiguredNetworks.get(netId); 1768 if (config != null) { 1769 //update defaultGwMacAddress 1770 config.defaultGwMacAddress = macAddress; 1771 } 1772 } 1773 1774 1775 /** 1776 * Fetch the proxy properties for a given network id 1777 * @param network id 1778 * @return ProxyInfo for the network id 1779 */ 1780 ProxyInfo getProxyProperties(int netId) { 1781 WifiConfiguration config = mConfiguredNetworks.get(netId); 1782 if (config != null) { 1783 return config.getHttpProxy(); 1784 } 1785 return null; 1786 } 1787 1788 /** 1789 * Return if the specified network is using static IP 1790 * @param network id 1791 * @return {@code true} if using static ip for netId 1792 */ 1793 boolean isUsingStaticIp(int netId) { 1794 WifiConfiguration config = mConfiguredNetworks.get(netId); 1795 if (config != null && config.getIpAssignment() == IpAssignment.STATIC) { 1796 return true; 1797 } 1798 return false; 1799 } 1800 1801 /** 1802 * Should be called when a single network configuration is made. 1803 * @param network The network configuration that changed. 1804 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 1805 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 1806 */ 1807 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 1808 int reason) { 1809 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1810 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1811 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 1812 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 1813 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 1814 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1815 } 1816 1817 /** 1818 * Should be called when multiple network configuration changes are made. 1819 */ 1820 private void sendConfiguredNetworksChangedBroadcast() { 1821 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1822 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1823 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 1824 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1825 } 1826 1827 void loadConfiguredNetworks() { 1828 1829 mLastPriority = 0; 1830 1831 mConfiguredNetworks.clear(); 1832 mNetworkIds.clear(); 1833 1834 int last_id = -1; 1835 boolean done = false; 1836 while (!done) { 1837 1838 String listStr = mWifiNative.listNetworks(last_id); 1839 if (listStr == null) 1840 return; 1841 1842 String[] lines = listStr.split("\n"); 1843 1844 if (showNetworks) { 1845 localLog("WifiConfigStore: loadConfiguredNetworks: "); 1846 for (String net : lines) { 1847 localLog(net); 1848 } 1849 } 1850 1851 // Skip the first line, which is a header 1852 for (int i = 1; i < lines.length; i++) { 1853 String[] result = lines[i].split("\t"); 1854 // network-id | ssid | bssid | flags 1855 WifiConfiguration config = new WifiConfiguration(); 1856 try { 1857 config.networkId = Integer.parseInt(result[0]); 1858 last_id = config.networkId; 1859 } catch(NumberFormatException e) { 1860 loge("Failed to read network-id '" + result[0] + "'"); 1861 continue; 1862 } 1863 if (result.length > 3) { 1864 if (result[3].indexOf("[CURRENT]") != -1) 1865 config.status = WifiConfiguration.Status.CURRENT; 1866 else if (result[3].indexOf("[DISABLED]") != -1) 1867 config.status = WifiConfiguration.Status.DISABLED; 1868 else 1869 config.status = WifiConfiguration.Status.ENABLED; 1870 } else { 1871 config.status = WifiConfiguration.Status.ENABLED; 1872 } 1873 1874 readNetworkVariables(config); 1875 1876 Checksum csum = new CRC32(); 1877 if (config.SSID != null) { 1878 csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length); 1879 long d = csum.getValue(); 1880 if (mDeletedSSIDs.contains(d)) { 1881 loge(" got CRC for SSID " + config.SSID + " -> " + d + ", was deleted"); 1882 } 1883 } 1884 1885 if (config.priority > mLastPriority) { 1886 mLastPriority = config.priority; 1887 } 1888 1889 config.setIpAssignment(IpAssignment.DHCP); 1890 config.setProxySettings(ProxySettings.NONE); 1891 1892 if (mNetworkIds.containsKey(configKey(config))) { 1893 // That SSID is already known, just ignore this duplicate entry 1894 if (showNetworks) localLog("discarded duplicate network ", config.networkId); 1895 } else if(config.isValid()){ 1896 mConfiguredNetworks.put(config.networkId, config); 1897 mNetworkIds.put(configKey(config), config.networkId); 1898 if (showNetworks) localLog("loaded configured network", config.networkId); 1899 } else { 1900 if (showNetworks) log("Ignoring loaded configured for network " + config.networkId 1901 + " because config are not valid"); 1902 } 1903 } 1904 1905 done = (lines.length == 1); 1906 } 1907 1908 readPasspointConfig(); 1909 readIpAndProxyConfigurations(); 1910 readNetworkHistory(); 1911 readAutoJoinConfig(); 1912 1913 sendConfiguredNetworksChangedBroadcast(); 1914 1915 if (showNetworks) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks"); 1916 1917 if (mNetworkIds.size() == 0) { 1918 // no networks? Lets log if the wpa_supplicant.conf file contents 1919 BufferedReader reader = null; 1920 try { 1921 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 1922 if (DBG) { 1923 localLog("--- Begin wpa_supplicant.conf Contents ---", true); 1924 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 1925 localLog(line, true); 1926 } 1927 localLog("--- End wpa_supplicant.conf Contents ---", true); 1928 } 1929 } catch (FileNotFoundException e) { 1930 localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e, true); 1931 } catch (IOException e) { 1932 localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e, true); 1933 } finally { 1934 try { 1935 if (reader != null) { 1936 reader.close(); 1937 } 1938 } catch (IOException e) { 1939 // Just ignore the fact that we couldn't close 1940 } 1941 } 1942 } 1943 } 1944 1945 private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) { 1946 Map<String, String> result = new HashMap<>(); 1947 BufferedReader reader = null; 1948 if (VDBG) loge("readNetworkVariablesFromSupplicantFile key=" + key); 1949 1950 try { 1951 reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); 1952 boolean found = false; 1953 String networkSsid = null; 1954 String value = null; 1955 1956 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 1957 1958 if (line.matches("[ \\t]*network=\\{")) { 1959 found = true; 1960 networkSsid = null; 1961 value = null; 1962 } else if (line.matches("[ \\t]*\\}")) { 1963 found = false; 1964 networkSsid = null; 1965 value = null; 1966 } 1967 1968 if (found) { 1969 String trimmedLine = line.trim(); 1970 if (trimmedLine.startsWith("ssid=")) { 1971 networkSsid = trimmedLine.substring(5); 1972 } else if (trimmedLine.startsWith(key + "=")) { 1973 value = trimmedLine.substring(key.length() + 1); 1974 } 1975 1976 if (networkSsid != null && value != null) { 1977 result.put(networkSsid, value); 1978 } 1979 } 1980 } 1981 } catch (FileNotFoundException e) { 1982 if (VDBG) loge("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); 1983 } catch (IOException e) { 1984 if (VDBG) loge("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); 1985 } finally { 1986 try { 1987 if (reader != null) { 1988 reader.close(); 1989 } 1990 } catch (IOException e) { 1991 // Just ignore the fact that we couldn't close 1992 } 1993 } 1994 1995 return result; 1996 } 1997 1998 private String readNetworkVariableFromSupplicantFile(String ssid, String key) { 1999 long start = SystemClock.elapsedRealtimeNanos(); 2000 Map<String, String> data = readNetworkVariablesFromSupplicantFile(key); 2001 long end = SystemClock.elapsedRealtimeNanos(); 2002 2003 if (VDBG) { 2004 loge("readNetworkVariableFromSupplicantFile ssid=[" + ssid + "] key=" + key 2005 + " duration=" + (long)(end - start)); 2006 } 2007 return data.get(ssid); 2008 } 2009 2010 /* Mark all networks except specified netId as disabled */ 2011 private void markAllNetworksDisabledExcept(int netId) { 2012 for(WifiConfiguration config : mConfiguredNetworks.values()) { 2013 if(config != null && config.networkId != netId) { 2014 if (config.status != Status.DISABLED) { 2015 config.status = Status.DISABLED; 2016 config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; 2017 } 2018 } 2019 } 2020 } 2021 2022 private void markAllNetworksDisabled() { 2023 markAllNetworksDisabledExcept(INVALID_NETWORK_ID); 2024 } 2025 2026 boolean needsUnlockedKeyStore() { 2027 2028 // Any network using certificates to authenticate access requires 2029 // unlocked key store; unless the certificates can be stored with 2030 // hardware encryption 2031 2032 for(WifiConfiguration config : mConfiguredNetworks.values()) { 2033 2034 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 2035 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 2036 2037 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 2038 return true; 2039 } 2040 } 2041 } 2042 2043 return false; 2044 } 2045 2046 void readPasspointConfig() { 2047 File file = new File(PPS_FILE); 2048 2049 MOManager moManager; 2050 List<HomeSP> homeSPs; 2051 try { 2052 moManager = new MOManager(file); 2053 homeSPs = moManager.loadAllSPs(); 2054 } catch (IOException e) { 2055 loge("Could not read " + PPS_FILE + " : " + e); 2056 return; 2057 } catch (NullPointerException e) { 2058 loge("Could not read " + PPS_FILE + " : " + e); 2059 return; 2060 } 2061 2062 mConfiguredHomeSPs.clear(); 2063 2064 log("read " + homeSPs.size() + " from " + PPS_FILE); 2065 2066 for (HomeSP homeSp : homeSPs) { 2067 String fqdn = homeSp.getFQDN(); 2068 String chksum = Long.toString(getChecksum(fqdn)); 2069 log("Looking for " + chksum + " for " + fqdn); 2070 for (WifiConfiguration config : mConfiguredNetworks.values()) { 2071 log("Testing " + config.SSID); 2072 2073 String id_str = mWifiNative.getNetworkVariable(config.networkId, idStringVarName); 2074 if (id_str != null && id_str.equals(chksum) && config.enterpriseConfig != null) { 2075 log("Matched " + id_str); 2076 config.FQDN = fqdn; 2077 config.providerFriendlyName = homeSp.getFriendlyName(); 2078 config.roamingConsortiumIds = new HashSet<Long>(); 2079 for (Long roamingConsortium : homeSp.getRoamingConsortiums()) { 2080 config.roamingConsortiumIds.add(roamingConsortium); 2081 } 2082 config.enterpriseConfig.setPlmn(homeSp.getCredential().getImsi()); 2083 config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm()); 2084 mConfiguredHomeSPs.put(config.networkId, homeSp); 2085 } 2086 } 2087 } 2088 2089 log("loaded " + mConfiguredHomeSPs.size() + " passpoint configs"); 2090 } 2091 2092 public void writePasspointConfigs() { 2093 mWriter.write(PPS_FILE, new DelayedDiskWrite.Writer() { 2094 @Override 2095 public void onWriteCalled(DataOutputStream out) throws IOException { 2096 log("saving " + mConfiguredHomeSPs.size() + " in " + PPS_FILE + " ..."); 2097 File file = new File(PPS_FILE); 2098 2099 MOManager moManager; 2100 try { 2101 moManager = new MOManager(file); 2102 moManager.saveAllSps(mConfiguredHomeSPs.values()); 2103 } catch (IOException e) { 2104 loge("Could not write " + PPS_FILE + " : " + e); 2105 } 2106 } 2107 }); 2108 } 2109 2110 public void writeKnownNetworkHistory(boolean force) { 2111 boolean needUpdate = force; 2112 2113 /* Make a copy */ 2114 final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 2115 for (WifiConfiguration config : mConfiguredNetworks.values()) { 2116 networks.add(new WifiConfiguration(config)); 2117 if (config.dirty == true) { 2118 loge(" rewrite network history for " + config.configKey()); 2119 config.dirty = false; 2120 needUpdate = true; 2121 } 2122 } 2123 if (VDBG) { 2124 loge(" writeKnownNetworkHistory() num networks:" + 2125 mConfiguredNetworks.size() + " needWrite=" + needUpdate); 2126 } 2127 if (needUpdate == false) { 2128 return; 2129 } 2130 mWriter.write(networkHistoryConfigFile, new DelayedDiskWrite.Writer() { 2131 public void onWriteCalled(DataOutputStream out) throws IOException { 2132 for (WifiConfiguration config : networks) { 2133 //loge("onWriteCalled write SSID: " + config.SSID); 2134 /* if (config.getLinkProperties() != null) 2135 loge(" lp " + config.getLinkProperties().toString()); 2136 else 2137 loge("attempt config w/o lp"); 2138 */ 2139 2140 if (VDBG) { 2141 int num = 0; 2142 int numlink = 0; 2143 if (config.connectChoices != null) { 2144 num = config.connectChoices.size(); 2145 } 2146 if (config.linkedConfigurations != null) { 2147 numlink = config.linkedConfigurations.size(); 2148 } 2149 loge("saving network history: " + config.configKey() + " gw: " + 2150 config.defaultGwMacAddress + " autojoin-status: " + 2151 config.autoJoinStatus + " ephemeral=" + config.ephemeral 2152 + " choices:" + Integer.toString(num) 2153 + " link:" + Integer.toString(numlink) 2154 + " status:" + Integer.toString(config.status) 2155 + " nid:" + Integer.toString(config.networkId)); 2156 } 2157 2158 if (config.isValid() == false) 2159 continue; 2160 2161 if (config.SSID == null) { 2162 if (VDBG) { 2163 loge("writeKnownNetworkHistory trying to write config with null SSID"); 2164 } 2165 continue; 2166 } 2167 if (VDBG) { 2168 loge("writeKnownNetworkHistory write config " + config.configKey()); 2169 } 2170 out.writeUTF(CONFIG_KEY + config.configKey() + SEPARATOR_KEY); 2171 2172 out.writeUTF(SSID_KEY + config.SSID + SEPARATOR_KEY); 2173 out.writeUTF(FQDN_KEY + config.FQDN + SEPARATOR_KEY); 2174 2175 out.writeUTF(PRIORITY_KEY + Integer.toString(config.priority) + SEPARATOR_KEY); 2176 out.writeUTF(STATUS_KEY + Integer.toString(config.autoJoinStatus) 2177 + SEPARATOR_KEY); 2178 out.writeUTF(SUPPLICANT_STATUS_KEY + Integer.toString(config.status) 2179 + SEPARATOR_KEY); 2180 out.writeUTF(SUPPLICANT_DISABLE_REASON_KEY 2181 + Integer.toString(config.disableReason) 2182 + SEPARATOR_KEY); 2183 out.writeUTF(NETWORK_ID_KEY + Integer.toString(config.networkId) 2184 + SEPARATOR_KEY); 2185 out.writeUTF(SELF_ADDED_KEY + Boolean.toString(config.selfAdded) 2186 + SEPARATOR_KEY); 2187 out.writeUTF(DID_SELF_ADD_KEY + Boolean.toString(config.didSelfAdd) 2188 + SEPARATOR_KEY); 2189 out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY 2190 + Integer.toString(config.numNoInternetAccessReports) 2191 + SEPARATOR_KEY); 2192 out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY 2193 + Boolean.toString(config.validatedInternetAccess) 2194 + SEPARATOR_KEY); 2195 out.writeUTF(EPHEMERAL_KEY 2196 + Boolean.toString(config.ephemeral) 2197 + SEPARATOR_KEY); 2198 if (config.peerWifiConfiguration != null) { 2199 out.writeUTF(PEER_CONFIGURATION_KEY + config.peerWifiConfiguration 2200 + SEPARATOR_KEY); 2201 } 2202 out.writeUTF(NUM_CONNECTION_FAILURES_KEY 2203 + Integer.toString(config.numConnectionFailures) 2204 + SEPARATOR_KEY); 2205 out.writeUTF(NUM_AUTH_FAILURES_KEY 2206 + Integer.toString(config.numAuthFailures) 2207 + SEPARATOR_KEY); 2208 out.writeUTF(NUM_IP_CONFIG_FAILURES_KEY 2209 + Integer.toString(config.numIpConfigFailures) 2210 + SEPARATOR_KEY); 2211 out.writeUTF(SCORER_OVERRIDE_KEY + Integer.toString(config.numScorerOverride) 2212 + SEPARATOR_KEY); 2213 out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY 2214 + Integer.toString(config.numScorerOverrideAndSwitchedNetwork) 2215 + SEPARATOR_KEY); 2216 out.writeUTF(NUM_ASSOCIATION_KEY 2217 + Integer.toString(config.numAssociation) 2218 + SEPARATOR_KEY); 2219 out.writeUTF(JOIN_ATTEMPT_BOOST_KEY 2220 + Integer.toString(config.autoJoinUseAggressiveJoinAttemptThreshold) 2221 + SEPARATOR_KEY); 2222 //out.writeUTF(BLACKLIST_MILLI_KEY + Long.toString(config.blackListTimestamp) 2223 // + SEPARATOR_KEY); 2224 out.writeUTF(CREATOR_UID_KEY + Integer.toString(config.creatorUid) 2225 + SEPARATOR_KEY); 2226 out.writeUTF(CONNECT_UID_KEY + Integer.toString(config.lastConnectUid) 2227 + SEPARATOR_KEY); 2228 out.writeUTF(UPDATE_UID_KEY + Integer.toString(config.lastUpdateUid) 2229 + SEPARATOR_KEY); 2230 out.writeUTF(CREATOR_NAME_KEY + config.creatorName + SEPARATOR_KEY); 2231 out.writeUTF(UPDATE_NAME_KEY + config.lastUpdateName + SEPARATOR_KEY); 2232 out.writeUTF(USER_APPROVED_KEY + Integer.toString(config.userApproved) 2233 + SEPARATOR_KEY); 2234 String allowedKeyManagementString = 2235 makeString(config.allowedKeyManagement, 2236 WifiConfiguration.KeyMgmt.strings); 2237 out.writeUTF(AUTH_KEY + allowedKeyManagementString + SEPARATOR_KEY); 2238 2239 if (config.connectChoices != null) { 2240 for (String key : config.connectChoices.keySet()) { 2241 Integer choice = config.connectChoices.get(key); 2242 out.writeUTF(CHOICE_KEY + key + "=" 2243 + choice.toString() + SEPARATOR_KEY); 2244 } 2245 } 2246 if (config.linkedConfigurations != null) { 2247 loge("writeKnownNetworkHistory write linked " 2248 + config.linkedConfigurations.size()); 2249 2250 for (String key : config.linkedConfigurations.keySet()) { 2251 out.writeUTF(LINK_KEY + key + SEPARATOR_KEY); 2252 } 2253 } 2254 2255 String macAddress = config.defaultGwMacAddress; 2256 if (macAddress != null) { 2257 out.writeUTF(DEFAULT_GW_KEY + macAddress + SEPARATOR_KEY); 2258 } 2259 2260 if (getScanDetailCache(config) != null) { 2261 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 2262 ScanResult result = scanDetail.getScanResult(); 2263 out.writeUTF(BSSID_KEY + result.BSSID + SEPARATOR_KEY); 2264 2265 out.writeUTF(FREQ_KEY + Integer.toString(result.frequency) 2266 + SEPARATOR_KEY); 2267 2268 out.writeUTF(RSSI_KEY + Integer.toString(result.level) 2269 + SEPARATOR_KEY); 2270 2271 out.writeUTF(BSSID_STATUS_KEY 2272 + Integer.toString(result.autoJoinStatus) 2273 + SEPARATOR_KEY); 2274 2275 //if (result.seen != 0) { 2276 // out.writeUTF(MILLI_KEY + Long.toString(result.seen) 2277 // + SEPARATOR_KEY); 2278 //} 2279 out.writeUTF(BSSID_KEY_END + SEPARATOR_KEY); 2280 } 2281 } 2282 if (config.lastFailure != null) { 2283 out.writeUTF(FAILURE_KEY + config.lastFailure + SEPARATOR_KEY); 2284 } 2285 out.writeUTF(SEPARATOR_KEY); 2286 // Add extra blank lines for clarity 2287 out.writeUTF(SEPARATOR_KEY); 2288 out.writeUTF(SEPARATOR_KEY); 2289 } 2290 if (mDeletedSSIDs != null && mDeletedSSIDs.size() > 0) { 2291 for (Long i : mDeletedSSIDs) { 2292 out.writeUTF(DELETED_CRC32_KEY); 2293 out.writeUTF(String.valueOf(i)); 2294 out.writeUTF(SEPARATOR_KEY); 2295 } 2296 } 2297 if (mDeletedEphemeralSSIDs != null && mDeletedEphemeralSSIDs.size() > 0) { 2298 for (String ssid : mDeletedEphemeralSSIDs) { 2299 out.writeUTF(DELETED_EPHEMERAL_KEY); 2300 out.writeUTF(ssid); 2301 out.writeUTF(SEPARATOR_KEY); 2302 } 2303 } 2304 } 2305 }); 2306 } 2307 2308 public void setLastSelectedConfiguration(int netId) { 2309 if (VDBG) { 2310 loge("setLastSelectedConfiguration " + Integer.toString(netId)); 2311 } 2312 if (netId == WifiConfiguration.INVALID_NETWORK_ID) { 2313 lastSelectedConfiguration = null; 2314 } else { 2315 WifiConfiguration selected = getWifiConfiguration(netId); 2316 if (selected == null) { 2317 lastSelectedConfiguration = null; 2318 } else { 2319 lastSelectedConfiguration = selected.configKey(); 2320 selected.numConnectionFailures = 0; 2321 selected.numIpConfigFailures = 0; 2322 selected.numAuthFailures = 0; 2323 selected.numNoInternetAccessReports = 0; 2324 if (VDBG) { 2325 loge("setLastSelectedConfiguration now: " + lastSelectedConfiguration); 2326 } 2327 } 2328 } 2329 } 2330 2331 public String getLastSelectedConfiguration() { 2332 return lastSelectedConfiguration; 2333 } 2334 2335 public boolean isLastSelectedConfiguration(WifiConfiguration config) { 2336 return (lastSelectedConfiguration != null 2337 && config != null 2338 && lastSelectedConfiguration.equals(config.configKey())); 2339 } 2340 2341 private void readNetworkHistory() { 2342 if (showNetworks) { 2343 localLog("readNetworkHistory() path:" + networkHistoryConfigFile); 2344 } 2345 DataInputStream in = null; 2346 try { 2347 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 2348 networkHistoryConfigFile))); 2349 WifiConfiguration config = null; 2350 while (true) { 2351 int id = -1; 2352 String key = in.readUTF(); 2353 String bssid = null; 2354 String ssid = null; 2355 2356 int freq = 0; 2357 int status = 0; 2358 long seen = 0; 2359 int rssi = WifiConfiguration.INVALID_RSSI; 2360 String caps = null; 2361 if (key.startsWith(CONFIG_KEY)) { 2362 2363 if (config != null) { 2364 // After an upgrade count old connections as owned by system 2365 if (config.creatorName == null || config.lastUpdateName == null) { 2366 config.creatorName = 2367 mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID); 2368 config.lastUpdateName = config.creatorName; 2369 2370 if (DBG) Log.e(TAG, "Upgrading network " + config.networkId 2371 + " to " + config.creatorName); 2372 } 2373 2374 config = null; 2375 } 2376 String configKey = key.replace(CONFIG_KEY, ""); 2377 configKey = configKey.replace(SEPARATOR_KEY, ""); 2378 // get the networkId for that config Key 2379 Integer n = mNetworkIds.get(configKey.hashCode()); 2380 // skip reading that configuration data 2381 // since we don't have a corresponding network ID 2382 if (n == null) { 2383 localLog("readNetworkHistory didnt find netid for hash=" 2384 + Integer.toString(configKey.hashCode()) 2385 + " key: " + configKey); 2386 continue; 2387 } 2388 config = mConfiguredNetworks.get(n); 2389 if (config == null) { 2390 localLog("readNetworkHistory didnt find config for netid=" 2391 + n.toString() 2392 + " key: " + configKey); 2393 } 2394 status = 0; 2395 ssid = null; 2396 bssid = null; 2397 freq = 0; 2398 seen = 0; 2399 rssi = WifiConfiguration.INVALID_RSSI; 2400 caps = null; 2401 2402 } else if (config != null) { 2403 if (key.startsWith(SSID_KEY)) { 2404 ssid = key.replace(SSID_KEY, ""); 2405 ssid = ssid.replace(SEPARATOR_KEY, ""); 2406 if (config.SSID != null && !config.SSID.equals(ssid)) { 2407 loge("Error parsing network history file, mismatched SSIDs"); 2408 config = null; //error 2409 ssid = null; 2410 } else { 2411 config.SSID = ssid; 2412 } 2413 } 2414 2415 if (key.startsWith(FQDN_KEY)) { 2416 String fqdn = key.replace(FQDN_KEY, ""); 2417 fqdn = fqdn.replace(SEPARATOR_KEY, ""); 2418 config.FQDN = fqdn; 2419 } 2420 2421 if (key.startsWith(DEFAULT_GW_KEY)) { 2422 String gateway = key.replace(DEFAULT_GW_KEY, ""); 2423 gateway = gateway.replace(SEPARATOR_KEY, ""); 2424 config.defaultGwMacAddress = gateway; 2425 } 2426 2427 if (key.startsWith(STATUS_KEY)) { 2428 String st = key.replace(STATUS_KEY, ""); 2429 st = st.replace(SEPARATOR_KEY, ""); 2430 config.autoJoinStatus = Integer.parseInt(st); 2431 } 2432 2433 if (key.startsWith(SUPPLICANT_DISABLE_REASON_KEY)) { 2434 String reason = key.replace(SUPPLICANT_DISABLE_REASON_KEY, ""); 2435 reason = reason.replace(SEPARATOR_KEY, ""); 2436 config.disableReason = Integer.parseInt(reason); 2437 } 2438 2439 if (key.startsWith(SELF_ADDED_KEY)) { 2440 String selfAdded = key.replace(SELF_ADDED_KEY, ""); 2441 selfAdded = selfAdded.replace(SEPARATOR_KEY, ""); 2442 config.selfAdded = Boolean.parseBoolean(selfAdded); 2443 } 2444 2445 if (key.startsWith(DID_SELF_ADD_KEY)) { 2446 String didSelfAdd = key.replace(DID_SELF_ADD_KEY, ""); 2447 didSelfAdd = didSelfAdd.replace(SEPARATOR_KEY, ""); 2448 config.didSelfAdd = Boolean.parseBoolean(didSelfAdd); 2449 } 2450 2451 if (key.startsWith(NO_INTERNET_ACCESS_REPORTS_KEY)) { 2452 String access = key.replace(NO_INTERNET_ACCESS_REPORTS_KEY, ""); 2453 access = access.replace(SEPARATOR_KEY, ""); 2454 config.numNoInternetAccessReports = Integer.parseInt(access); 2455 } 2456 2457 if (key.startsWith(VALIDATED_INTERNET_ACCESS_KEY)) { 2458 String access = key.replace(VALIDATED_INTERNET_ACCESS_KEY, ""); 2459 access = access.replace(SEPARATOR_KEY, ""); 2460 config.validatedInternetAccess = Boolean.parseBoolean(access); 2461 } 2462 2463 if (key.startsWith(EPHEMERAL_KEY)) { 2464 String access = key.replace(EPHEMERAL_KEY, ""); 2465 access = access.replace(SEPARATOR_KEY, ""); 2466 config.ephemeral = Boolean.parseBoolean(access); 2467 } 2468 2469 if (key.startsWith(CREATOR_UID_KEY)) { 2470 String uid = key.replace(CREATOR_UID_KEY, ""); 2471 uid = uid.replace(SEPARATOR_KEY, ""); 2472 config.creatorUid = Integer.parseInt(uid); 2473 } 2474 2475 if (key.startsWith(BLACKLIST_MILLI_KEY)) { 2476 String milli = key.replace(BLACKLIST_MILLI_KEY, ""); 2477 milli = milli.replace(SEPARATOR_KEY, ""); 2478 config.blackListTimestamp = Long.parseLong(milli); 2479 } 2480 2481 if (key.startsWith(NUM_CONNECTION_FAILURES_KEY)) { 2482 String num = key.replace(NUM_CONNECTION_FAILURES_KEY, ""); 2483 num = num.replace(SEPARATOR_KEY, ""); 2484 config.numConnectionFailures = Integer.parseInt(num); 2485 } 2486 2487 if (key.startsWith(NUM_IP_CONFIG_FAILURES_KEY)) { 2488 String num = key.replace(NUM_IP_CONFIG_FAILURES_KEY, ""); 2489 num = num.replace(SEPARATOR_KEY, ""); 2490 config.numIpConfigFailures = Integer.parseInt(num); 2491 } 2492 2493 if (key.startsWith(NUM_AUTH_FAILURES_KEY)) { 2494 String num = key.replace(NUM_AUTH_FAILURES_KEY, ""); 2495 num = num.replace(SEPARATOR_KEY, ""); 2496 config.numIpConfigFailures = Integer.parseInt(num); 2497 } 2498 2499 if (key.startsWith(SCORER_OVERRIDE_KEY)) { 2500 String num = key.replace(SCORER_OVERRIDE_KEY, ""); 2501 num = num.replace(SEPARATOR_KEY, ""); 2502 config.numScorerOverride = Integer.parseInt(num); 2503 } 2504 2505 if (key.startsWith(SCORER_OVERRIDE_AND_SWITCH_KEY)) { 2506 String num = key.replace(SCORER_OVERRIDE_AND_SWITCH_KEY, ""); 2507 num = num.replace(SEPARATOR_KEY, ""); 2508 config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(num); 2509 } 2510 2511 if (key.startsWith(NUM_ASSOCIATION_KEY)) { 2512 String num = key.replace(NUM_ASSOCIATION_KEY, ""); 2513 num = num.replace(SEPARATOR_KEY, ""); 2514 config.numAssociation = Integer.parseInt(num); 2515 } 2516 2517 if (key.startsWith(JOIN_ATTEMPT_BOOST_KEY)) { 2518 String num = key.replace(JOIN_ATTEMPT_BOOST_KEY, ""); 2519 num = num.replace(SEPARATOR_KEY, ""); 2520 config.autoJoinUseAggressiveJoinAttemptThreshold = Integer.parseInt(num); 2521 } 2522 2523 if (key.startsWith(CONNECT_UID_KEY)) { 2524 String uid = key.replace(CONNECT_UID_KEY, ""); 2525 uid = uid.replace(SEPARATOR_KEY, ""); 2526 config.lastConnectUid = Integer.parseInt(uid); 2527 } 2528 2529 if (key.startsWith(UPDATE_UID_KEY)) { 2530 String uid = key.replace(UPDATE_UID_KEY, ""); 2531 uid = uid.replace(SEPARATOR_KEY, ""); 2532 config.lastUpdateUid = Integer.parseInt(uid); 2533 } 2534 2535 if (key.startsWith(CREATOR_NAME_KEY)) { 2536 String name = key.replace(CREATOR_NAME_KEY, ""); 2537 name = name.replace(SEPARATOR_KEY, ""); 2538 config.creatorName = name; 2539 } 2540 2541 if (key.startsWith(UPDATE_NAME_KEY)) { 2542 String name = key.replace(UPDATE_NAME_KEY, ""); 2543 name = name.replace(SEPARATOR_KEY, ""); 2544 config.lastUpdateName = name; 2545 } 2546 2547 if (key.startsWith(USER_APPROVED_KEY)) { 2548 String userApproved = key.replace(USER_APPROVED_KEY, ""); 2549 userApproved = userApproved.replace(SEPARATOR_KEY, ""); 2550 config.userApproved = Integer.parseInt(userApproved); 2551 } 2552 2553 if (key.startsWith(FAILURE_KEY)) { 2554 config.lastFailure = key.replace(FAILURE_KEY, ""); 2555 config.lastFailure = config.lastFailure.replace(SEPARATOR_KEY, ""); 2556 } 2557 2558 if (key.startsWith(PEER_CONFIGURATION_KEY)) { 2559 config.peerWifiConfiguration = key.replace(PEER_CONFIGURATION_KEY, ""); 2560 config.peerWifiConfiguration = 2561 config.peerWifiConfiguration.replace(SEPARATOR_KEY, ""); 2562 } 2563 2564 if (key.startsWith(CHOICE_KEY)) { 2565 String choiceStr = key.replace(CHOICE_KEY, ""); 2566 choiceStr = choiceStr.replace(SEPARATOR_KEY, ""); 2567 String configKey = ""; 2568 int choice = 0; 2569 Matcher match = mConnectChoice.matcher(choiceStr); 2570 if (!match.find()) { 2571 if (DBG) Log.d(TAG, "WifiConfigStore: connectChoice: " + 2572 " Couldnt match pattern : " + choiceStr); 2573 } else { 2574 configKey = match.group(1); 2575 try { 2576 choice = Integer.parseInt(match.group(2)); 2577 } catch (NumberFormatException e) { 2578 choice = 0; 2579 } 2580 if (choice > 0) { 2581 if (config.connectChoices == null) { 2582 config.connectChoices = new HashMap<String, Integer>(); 2583 } 2584 config.connectChoices.put(configKey, choice); 2585 } 2586 } 2587 } 2588 2589 if (key.startsWith(LINK_KEY)) { 2590 String configKey = key.replace(LINK_KEY, ""); 2591 configKey = configKey.replace(SEPARATOR_KEY, ""); 2592 if (config.linkedConfigurations == null) { 2593 config.linkedConfigurations = new HashMap<String, Integer>(); 2594 } 2595 if (config.linkedConfigurations != null) { 2596 config.linkedConfigurations.put(configKey, -1); 2597 } 2598 } 2599 2600 if (key.startsWith(BSSID_KEY)) { 2601 if (key.startsWith(BSSID_KEY)) { 2602 bssid = key.replace(BSSID_KEY, ""); 2603 bssid = bssid.replace(SEPARATOR_KEY, ""); 2604 freq = 0; 2605 seen = 0; 2606 rssi = WifiConfiguration.INVALID_RSSI; 2607 caps = ""; 2608 status = 0; 2609 } 2610 2611 if (key.startsWith(RSSI_KEY)) { 2612 String lvl = key.replace(RSSI_KEY, ""); 2613 lvl = lvl.replace(SEPARATOR_KEY, ""); 2614 rssi = Integer.parseInt(lvl); 2615 } 2616 2617 if (key.startsWith(BSSID_STATUS_KEY)) { 2618 String st = key.replace(BSSID_STATUS_KEY, ""); 2619 st = st.replace(SEPARATOR_KEY, ""); 2620 status = Integer.parseInt(st); 2621 } 2622 2623 if (key.startsWith(FREQ_KEY)) { 2624 String channel = key.replace(FREQ_KEY, ""); 2625 channel = channel.replace(SEPARATOR_KEY, ""); 2626 freq = Integer.parseInt(channel); 2627 } 2628 2629 if (key.startsWith(DATE_KEY)) { 2630 /* 2631 * when reading the configuration from file we don't update the date 2632 * so as to avoid reading back stale or non-sensical data that would 2633 * depend on network time. 2634 * The date of a WifiConfiguration should only come from actual scan result. 2635 * 2636 String s = key.replace(FREQ_KEY, ""); 2637 seen = Integer.getInteger(s); 2638 */ 2639 } 2640 2641 if (key.startsWith(BSSID_KEY_END)) { 2642 if ((bssid != null) && (ssid != null)) { 2643 2644 if (getScanDetailCache(config) != null) { 2645 WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid); 2646 ScanDetail scanDetail = new ScanDetail(wssid, bssid, 2647 caps, rssi, freq, (long) 0, seen); 2648 getScanDetailCache(config).put(scanDetail); 2649 scanDetail.getScanResult().autoJoinStatus = status; 2650 } 2651 } 2652 } 2653 2654 if (key.startsWith(DELETED_CRC32_KEY)) { 2655 String crc = key.replace(DELETED_CRC32_KEY, ""); 2656 Long c = Long.parseLong(crc); 2657 mDeletedSSIDs.add(c); 2658 } 2659 if (key.startsWith(DELETED_EPHEMERAL_KEY)) { 2660 String s = key.replace(DELETED_EPHEMERAL_KEY, ""); 2661 if (!TextUtils.isEmpty(s)) { 2662 s = s.replace(SEPARATOR_KEY, ""); 2663 mDeletedEphemeralSSIDs.add(s); 2664 } 2665 } 2666 } 2667 } 2668 } 2669 } catch (EOFException ignore) { 2670 if (in != null) { 2671 try { 2672 in.close(); 2673 } catch (Exception e) { 2674 loge("readNetworkHistory: Error reading file" + e); 2675 } 2676 } 2677 } catch (IOException e) { 2678 loge("readNetworkHistory: No config file, revert to default" + e); 2679 } 2680 2681 if(in!=null) { 2682 try { 2683 in.close(); 2684 } catch (Exception e) { 2685 loge("readNetworkHistory: Error closing file" + e); 2686 } 2687 } 2688 } 2689 2690 private void readAutoJoinConfig() { 2691 try (BufferedReader reader = new BufferedReader(new FileReader(autoJoinConfigFile))) { 2692 for (String key = reader.readLine(); key != null; key = reader.readLine()) { 2693 Log.d(TAG, "readAutoJoinConfig line: " + key); 2694 2695 int split = key.indexOf(':'); 2696 if (split < 0) { 2697 continue; 2698 } 2699 2700 String name = key.substring(0, split); 2701 Object reference = sKeyMap.get(name); 2702 if (reference == null) { 2703 continue; 2704 } 2705 2706 try { 2707 int value = Integer.parseInt(key.substring(split+1).trim()); 2708 if (reference.getClass() == AtomicBoolean.class) { 2709 ((AtomicBoolean)reference).set(value != 0); 2710 } 2711 else { 2712 ((AtomicInteger)reference).set(value); 2713 } 2714 Log.d(TAG,"readAutoJoinConfig: " + name + " = " + value); 2715 } 2716 catch (NumberFormatException nfe) { 2717 Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key); 2718 } 2719 } 2720 } catch (IOException e) { 2721 loge("readAutoJoinStatus: Error parsing configuration" + e); 2722 } 2723 } 2724 2725 2726 private void writeIpAndProxyConfigurations() { 2727 final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>(); 2728 for(WifiConfiguration config : mConfiguredNetworks.values()) { 2729 if (!config.ephemeral && config.autoJoinStatus != WifiConfiguration.AUTO_JOIN_DELETED) { 2730 networks.put(configKey(config), config.getIpConfiguration()); 2731 } 2732 } 2733 2734 super.writeIpAndProxyConfigurations(ipConfigFile, networks); 2735 } 2736 2737 private void readIpAndProxyConfigurations() { 2738 SparseArray<IpConfiguration> networks = super.readIpAndProxyConfigurations(ipConfigFile); 2739 2740 if (networks == null || networks.size() == 0) { 2741 // IpConfigStore.readIpAndProxyConfigurations has already logged an error. 2742 return; 2743 } 2744 2745 for (int i = 0; i < networks.size(); i++) { 2746 int id = networks.keyAt(i); 2747 WifiConfiguration config = mConfiguredNetworks.get(mNetworkIds.get(id)); 2748 2749 2750 if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || 2751 config.ephemeral) { 2752 loge("configuration found for missing network, nid=" + id 2753 +", ignored, networks.size=" + Integer.toString(networks.size())); 2754 } else { 2755 config.setIpConfiguration(networks.valueAt(i)); 2756 } 2757 } 2758 } 2759 2760 /* 2761 * Convert string to Hexadecimal before passing to wifi native layer 2762 * In native function "doCommand()" have trouble in converting Unicode character string to UTF8 2763 * conversion to hex is required because SSIDs can have space characters in them; 2764 * and that can confuses the supplicant because it uses space charaters as delimiters 2765 */ 2766 2767 public static String encodeSSID(String str){ 2768 return Utils.toHex(removeDoubleQuotes(str).getBytes(StandardCharsets.UTF_8)); 2769 } 2770 2771 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config, int uid) { 2772 /* 2773 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 2774 * network configuration. Otherwise, the networkId should 2775 * refer to an existing configuration. 2776 */ 2777 2778 if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 2779 2780 int netId = config.networkId; 2781 boolean newNetwork = false; 2782 // networkId of INVALID_NETWORK_ID means we want to create a new network 2783 if (netId == INVALID_NETWORK_ID) { 2784 Integer savedNetId = mNetworkIds.get(configKey(config)); 2785 // Check if either we have a network Id or a WifiConfiguration 2786 // matching the one we are trying to add. 2787 if (savedNetId == null) { 2788 for (WifiConfiguration test : mConfiguredNetworks.values()) { 2789 if (test.configKey().equals(config.configKey())) { 2790 savedNetId = test.networkId; 2791 loge("addOrUpdateNetworkNative " + config.configKey() 2792 + " was found, but no network Id"); 2793 break; 2794 } 2795 } 2796 } 2797 if (savedNetId != null) { 2798 netId = savedNetId; 2799 } else { 2800 if (mConfiguredHomeSPs.containsValue(config.FQDN)) { 2801 loge("addOrUpdateNetworkNative passpoint " + config.FQDN 2802 + " was found, but no network Id"); 2803 } 2804 newNetwork = true; 2805 netId = mWifiNative.addNetwork(); 2806 if (netId < 0) { 2807 loge("Failed to add a network!"); 2808 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2809 } else { 2810 loge("addOrUpdateNetworkNative created netId=" + netId); 2811 } 2812 } 2813 } 2814 2815 boolean updateFailed = true; 2816 2817 setVariables: { 2818 2819 if (config.SSID != null && 2820 !mWifiNative.setNetworkVariable( 2821 netId, 2822 WifiConfiguration.ssidVarName, 2823 encodeSSID(config.SSID))) { 2824 loge("failed to set SSID: "+config.SSID); 2825 break setVariables; 2826 } 2827 2828 if (config.isPasspoint()) { 2829 if (!mWifiNative.setNetworkVariable( 2830 netId, 2831 idStringVarName, 2832 Long.toString(getChecksum(config.FQDN)))) { 2833 loge("failed to set id_str: " + config.SSID); 2834 break setVariables; 2835 } 2836 } else { 2837 loge("not writing id_str: "+config.SSID + " because not a passpoint network"); 2838 loge("Config is : " + config); 2839 } 2840 2841 if (config.BSSID != null) { 2842 loge("Setting BSSID for " + config.configKey() + " to " + config.BSSID); 2843 if (!mWifiNative.setNetworkVariable( 2844 netId, 2845 WifiConfiguration.bssidVarName, 2846 config.BSSID)) { 2847 loge("failed to set BSSID: " + config.BSSID); 2848 break setVariables; 2849 } 2850 } 2851 2852 String allowedKeyManagementString = 2853 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 2854 if (config.allowedKeyManagement.cardinality() != 0 && 2855 !mWifiNative.setNetworkVariable( 2856 netId, 2857 WifiConfiguration.KeyMgmt.varName, 2858 allowedKeyManagementString)) { 2859 loge("failed to set key_mgmt: "+ 2860 allowedKeyManagementString); 2861 break setVariables; 2862 } 2863 2864 String allowedProtocolsString = 2865 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 2866 if (config.allowedProtocols.cardinality() != 0 && 2867 !mWifiNative.setNetworkVariable( 2868 netId, 2869 WifiConfiguration.Protocol.varName, 2870 allowedProtocolsString)) { 2871 loge("failed to set proto: "+ 2872 allowedProtocolsString); 2873 break setVariables; 2874 } 2875 2876 String allowedAuthAlgorithmsString = 2877 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 2878 if (config.allowedAuthAlgorithms.cardinality() != 0 && 2879 !mWifiNative.setNetworkVariable( 2880 netId, 2881 WifiConfiguration.AuthAlgorithm.varName, 2882 allowedAuthAlgorithmsString)) { 2883 loge("failed to set auth_alg: "+ 2884 allowedAuthAlgorithmsString); 2885 break setVariables; 2886 } 2887 2888 String allowedPairwiseCiphersString = 2889 makeString(config.allowedPairwiseCiphers, 2890 WifiConfiguration.PairwiseCipher.strings); 2891 if (config.allowedPairwiseCiphers.cardinality() != 0 && 2892 !mWifiNative.setNetworkVariable( 2893 netId, 2894 WifiConfiguration.PairwiseCipher.varName, 2895 allowedPairwiseCiphersString)) { 2896 loge("failed to set pairwise: "+ 2897 allowedPairwiseCiphersString); 2898 break setVariables; 2899 } 2900 2901 String allowedGroupCiphersString = 2902 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 2903 if (config.allowedGroupCiphers.cardinality() != 0 && 2904 !mWifiNative.setNetworkVariable( 2905 netId, 2906 WifiConfiguration.GroupCipher.varName, 2907 allowedGroupCiphersString)) { 2908 loge("failed to set group: "+ 2909 allowedGroupCiphersString); 2910 break setVariables; 2911 } 2912 2913 // Prevent client screw-up by passing in a WifiConfiguration we gave it 2914 // by preventing "*" as a key. 2915 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 2916 !mWifiNative.setNetworkVariable( 2917 netId, 2918 WifiConfiguration.pskVarName, 2919 config.preSharedKey)) { 2920 loge("failed to set psk"); 2921 break setVariables; 2922 } 2923 2924 boolean hasSetKey = false; 2925 if (config.wepKeys != null) { 2926 for (int i = 0; i < config.wepKeys.length; i++) { 2927 // Prevent client screw-up by passing in a WifiConfiguration we gave it 2928 // by preventing "*" as a key. 2929 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 2930 if (!mWifiNative.setNetworkVariable( 2931 netId, 2932 WifiConfiguration.wepKeyVarNames[i], 2933 config.wepKeys[i])) { 2934 loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); 2935 break setVariables; 2936 } 2937 hasSetKey = true; 2938 } 2939 } 2940 } 2941 2942 if (hasSetKey) { 2943 if (!mWifiNative.setNetworkVariable( 2944 netId, 2945 WifiConfiguration.wepTxKeyIdxVarName, 2946 Integer.toString(config.wepTxKeyIndex))) { 2947 loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); 2948 break setVariables; 2949 } 2950 } 2951 2952 if (!mWifiNative.setNetworkVariable( 2953 netId, 2954 WifiConfiguration.priorityVarName, 2955 Integer.toString(config.priority))) { 2956 loge(config.SSID + ": failed to set priority: " 2957 +config.priority); 2958 break setVariables; 2959 } 2960 2961 if (config.hiddenSSID && !mWifiNative.setNetworkVariable( 2962 netId, 2963 WifiConfiguration.hiddenSSIDVarName, 2964 Integer.toString(config.hiddenSSID ? 1 : 0))) { 2965 loge(config.SSID + ": failed to set hiddenSSID: "+ 2966 config.hiddenSSID); 2967 break setVariables; 2968 } 2969 2970 if (config.requirePMF && !mWifiNative.setNetworkVariable( 2971 netId, 2972 WifiConfiguration.pmfVarName, 2973 "2")) { 2974 loge(config.SSID + ": failed to set requirePMF: "+ 2975 config.requirePMF); 2976 break setVariables; 2977 } 2978 2979 if (config.updateIdentifier != null && !mWifiNative.setNetworkVariable( 2980 netId, 2981 WifiConfiguration.updateIdentiferVarName, 2982 config.updateIdentifier)) { 2983 loge(config.SSID + ": failed to set updateIdentifier: "+ 2984 config.updateIdentifier); 2985 break setVariables; 2986 } 2987 2988 if (config.enterpriseConfig != null && 2989 config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { 2990 2991 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 2992 2993 if (needsKeyStore(enterpriseConfig)) { 2994 /** 2995 * Keyguard settings may eventually be controlled by device policy. 2996 * We check here if keystore is unlocked before installing 2997 * credentials. 2998 * TODO: Do we need a dialog here ? 2999 */ 3000 if (mKeyStore.state() != KeyStore.State.UNLOCKED) { 3001 loge(config.SSID + ": key store is locked"); 3002 break setVariables; 3003 } 3004 3005 try { 3006 /* config passed may include only fields being updated. 3007 * In order to generate the key id, fetch uninitialized 3008 * fields from the currently tracked configuration 3009 */ 3010 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 3011 String keyId = config.getKeyIdForCredentials(currentConfig); 3012 3013 if (!installKeys(enterpriseConfig, keyId)) { 3014 loge(config.SSID + ": failed to install keys"); 3015 break setVariables; 3016 } 3017 } catch (IllegalStateException e) { 3018 loge(config.SSID + " invalid config for key installation"); 3019 break setVariables; 3020 } 3021 } 3022 3023 HashMap<String, String> enterpriseFields = enterpriseConfig.getFields(); 3024 for (String key : enterpriseFields.keySet()) { 3025 String value = enterpriseFields.get(key); 3026 if (key.equals("password") && value != null && value.equals("*")) { 3027 // No need to try to set an obfuscated password, which will fail 3028 continue; 3029 } 3030 if (key.equals(WifiEnterpriseConfig.REALM_KEY) 3031 || key.equals(WifiEnterpriseConfig.PLMN_KEY)) { 3032 // No need to save realm or PLMN in supplicant 3033 continue; 3034 } 3035 if (!mWifiNative.setNetworkVariable( 3036 netId, 3037 key, 3038 value)) { 3039 removeKeys(enterpriseConfig); 3040 loge(config.SSID + ": failed to set " + key + 3041 ": " + value); 3042 break setVariables; 3043 } 3044 } 3045 } 3046 updateFailed = false; 3047 } // End of setVariables 3048 3049 if (updateFailed) { 3050 if (newNetwork) { 3051 mWifiNative.removeNetwork(netId); 3052 loge("Failed to set a network variable, removed network: " + netId); 3053 } 3054 return new NetworkUpdateResult(INVALID_NETWORK_ID); 3055 } 3056 3057 /* An update of the network variables requires reading them 3058 * back from the supplicant to update mConfiguredNetworks. 3059 * This is because some of the variables (SSID, wep keys & 3060 * passphrases) reflect different values when read back than 3061 * when written. For example, wep key is stored as * irrespective 3062 * of the value sent to the supplicant 3063 */ 3064 WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); 3065 if (currentConfig == null) { 3066 currentConfig = new WifiConfiguration(); 3067 currentConfig.setIpAssignment(IpAssignment.DHCP); 3068 currentConfig.setProxySettings(ProxySettings.NONE); 3069 currentConfig.networkId = netId; 3070 if (config != null) { 3071 // Carry over the creation parameters 3072 currentConfig.selfAdded = config.selfAdded; 3073 currentConfig.didSelfAdd = config.didSelfAdd; 3074 currentConfig.ephemeral = config.ephemeral; 3075 currentConfig.autoJoinUseAggressiveJoinAttemptThreshold 3076 = config.autoJoinUseAggressiveJoinAttemptThreshold; 3077 currentConfig.lastConnectUid = config.lastConnectUid; 3078 currentConfig.lastUpdateUid = config.lastUpdateUid; 3079 currentConfig.creatorUid = config.creatorUid; 3080 currentConfig.creatorName = config.creatorName; 3081 currentConfig.lastUpdateName = config.lastUpdateName; 3082 currentConfig.peerWifiConfiguration = config.peerWifiConfiguration; 3083 currentConfig.FQDN = config.FQDN; 3084 currentConfig.providerFriendlyName = config.providerFriendlyName; 3085 currentConfig.roamingConsortiumIds = config.roamingConsortiumIds; 3086 } 3087 if (DBG) { 3088 loge("created new config netId=" + Integer.toString(netId) 3089 + " uid=" + Integer.toString(currentConfig.creatorUid) 3090 + " name=" + currentConfig.creatorName); 3091 } 3092 } 3093 3094 /* save HomeSP object for passpoint networks */ 3095 if (config.isPasspoint()) { 3096 if (newNetwork == false) { 3097 /* when updating a network, we'll just create a new HomeSP */ 3098 mConfiguredHomeSPs.remove(netId); 3099 } 3100 3101 Credential credential = new Credential(config.enterpriseConfig); 3102 HomeSP homeSP = new HomeSP(Collections.<String, Long>emptyMap(), config.FQDN, 3103 config.roamingConsortiumIds, Collections.<String>emptySet(), 3104 Collections.<Long>emptySet(), Collections.<Long>emptyList(), 3105 config.providerFriendlyName, null, credential); 3106 mConfiguredHomeSPs.put(netId, homeSP); 3107 log("created a homeSP object for " + config.networkId + ":" + config.SSID); 3108 3109 /* fix enterprise config properties for passpoint */ 3110 currentConfig.enterpriseConfig.setRealm(config.enterpriseConfig.getRealm()); 3111 currentConfig.enterpriseConfig.setPlmn(config.enterpriseConfig.getPlmn()); 3112 } 3113 3114 if (uid >= 0) { 3115 if (newNetwork) { 3116 currentConfig.creatorUid = uid; 3117 } else { 3118 currentConfig.lastUpdateUid = uid; 3119 } 3120 } 3121 3122 if (newNetwork) { 3123 currentConfig.dirty = true; 3124 } 3125 3126 if (currentConfig.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { 3127 // Make sure the configuration is not deleted anymore since we just 3128 // added or modified it. 3129 currentConfig.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 3130 currentConfig.selfAdded = false; 3131 currentConfig.didSelfAdd = false; 3132 if (DBG) { 3133 loge("remove deleted status netId=" + Integer.toString(netId) 3134 + " " + currentConfig.configKey()); 3135 } 3136 } 3137 3138 if (currentConfig.status == WifiConfiguration.Status.ENABLED) { 3139 // Make sure autojoin remain in sync with user modifying the configuration 3140 currentConfig.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 3141 } 3142 3143 if (currentConfig.configKey().equals(getLastSelectedConfiguration()) && 3144 currentConfig.ephemeral) { 3145 // Make the config non-ephemeral since the user just explicitly clicked it. 3146 currentConfig.ephemeral = false; 3147 if (DBG) loge("remove ephemeral status netId=" + Integer.toString(netId) 3148 + " " + currentConfig.configKey()); 3149 } 3150 3151 if (DBG) loge("will read network variables netId=" + Integer.toString(netId)); 3152 3153 readNetworkVariables(currentConfig); 3154 3155 // Persist configuration paramaters that are not saved by supplicant. 3156 if (config.lastUpdateName != null) { 3157 currentConfig.lastUpdateName = config.lastUpdateName; 3158 } 3159 if (config.lastUpdateUid != -1) { 3160 currentConfig.lastUpdateUid = config.lastUpdateUid; 3161 } 3162 3163 mConfiguredNetworks.put(netId, currentConfig); 3164 mNetworkIds.put(configKey(currentConfig), netId); 3165 3166 NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); 3167 result.setIsNewNetwork(newNetwork); 3168 result.setNetworkId(netId); 3169 3170 writePasspointConfigs(); 3171 writeKnownNetworkHistory(false); 3172 3173 return result; 3174 } 3175 3176 public Collection<HomeSP> getHomeSPs() { 3177 return mConfiguredHomeSPs.values(); 3178 } 3179 3180 public WifiConfiguration getWifiConfigForHomeSP(HomeSP homeSP) { 3181 for (Map.Entry<Integer, HomeSP> e : mConfiguredHomeSPs.entrySet()) { 3182 if (homeSP.equals(e.getValue())) { 3183 Integer networkId = e.getKey(); 3184 return mConfiguredNetworks.get(networkId); 3185 } 3186 } 3187 3188 Log.e(TAG, "Could not find network for homeSP " + homeSP.getFQDN()); 3189 return null; 3190 } 3191 3192 public ScanDetailCache getScanDetailCache(WifiConfiguration config) { 3193 if (config == null) return null; 3194 ScanDetailCache cache = mScanDetailCaches.get(config.networkId); 3195 if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { 3196 cache = new ScanDetailCache(config); 3197 mScanDetailCaches.put(config.networkId, cache); 3198 } 3199 return cache; 3200 } 3201 3202 /** 3203 * This function run thru the Saved WifiConfigurations and check if some should be linked. 3204 * @param config 3205 */ 3206 public void linkConfiguration(WifiConfiguration config) { 3207 3208 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 6) { 3209 // Ignore configurations with large number of BSSIDs 3210 return; 3211 } 3212 if (!config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 3213 // Only link WPA_PSK config 3214 return; 3215 } 3216 for (WifiConfiguration link : mConfiguredNetworks.values()) { 3217 boolean doLink = false; 3218 3219 if (link.configKey().equals(config.configKey())) { 3220 continue; 3221 } 3222 3223 if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.ephemeral) { 3224 continue; 3225 } 3226 3227 // Autojoin will be allowed to dynamically jump from a linked configuration 3228 // to another, hence only link configurations that have equivalent level of security 3229 if (!link.allowedKeyManagement.equals(config.allowedKeyManagement)) { 3230 continue; 3231 } 3232 3233 ScanDetailCache linkedScanDetailCache = getScanDetailCache(link); 3234 if (linkedScanDetailCache != null && linkedScanDetailCache.size() > 6) { 3235 // Ignore configurations with large number of BSSIDs 3236 continue; 3237 } 3238 3239 if (config.defaultGwMacAddress != null && link.defaultGwMacAddress != null) { 3240 // If both default GW are known, link only if they are equal 3241 if (config.defaultGwMacAddress.equals(link.defaultGwMacAddress)) { 3242 if (VDBG) { 3243 loge("linkConfiguration link due to same gw " + link.SSID + 3244 " and " + config.SSID + " GW " + config.defaultGwMacAddress); 3245 } 3246 doLink = true; 3247 } 3248 } else { 3249 // We do not know BOTH default gateways hence we will try to link 3250 // hoping that WifiConfigurations are indeed behind the same gateway. 3251 // once both WifiConfiguration have been tried and thus once both efault gateways 3252 // are known we will revisit the choice of linking them 3253 if ((getScanDetailCache(config) != null) 3254 && (getScanDetailCache(config).size() <= 6)) { 3255 3256 for (String abssid : getScanDetailCache(config).keySet()) { 3257 for (String bbssid : linkedScanDetailCache.keySet()) { 3258 if (VVDBG) { 3259 loge("linkConfiguration try to link due to DBDC BSSID match " 3260 + link.SSID + 3261 " and " + config.SSID + " bssida " + abssid 3262 + " bssidb " + bbssid); 3263 } 3264 if (abssid.regionMatches(true, 0, bbssid, 0, 16)) { 3265 // If first 16 ascii characters of BSSID matches, 3266 // we assume this is a DBDC 3267 doLink = true; 3268 } 3269 } 3270 } 3271 } 3272 } 3273 3274 if (doLink == true && onlyLinkSameCredentialConfigurations) { 3275 String apsk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); 3276 String bpsk = readNetworkVariableFromSupplicantFile(config.SSID, "psk"); 3277 if (apsk == null || bpsk == null 3278 || TextUtils.isEmpty(apsk) || TextUtils.isEmpty(apsk) 3279 || apsk.equals("*") || apsk.equals(DELETED_CONFIG_PSK) 3280 || !apsk.equals(bpsk)) { 3281 doLink = false; 3282 } 3283 } 3284 3285 if (doLink) { 3286 if (VDBG) { 3287 loge("linkConfiguration: will link " + link.configKey() 3288 + " and " + config.configKey()); 3289 } 3290 if (link.linkedConfigurations == null) { 3291 link.linkedConfigurations = new HashMap<String, Integer>(); 3292 } 3293 if (config.linkedConfigurations == null) { 3294 config.linkedConfigurations = new HashMap<String, Integer>(); 3295 } 3296 if (link.linkedConfigurations.get(config.configKey()) == null) { 3297 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 3298 link.dirty = true; 3299 } 3300 if (config.linkedConfigurations.get(link.configKey()) == null) { 3301 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 3302 config.dirty = true; 3303 } 3304 } else { 3305 if (link.linkedConfigurations != null 3306 && (link.linkedConfigurations.get(config.configKey()) != null)) { 3307 if (VDBG) { 3308 loge("linkConfiguration: un-link " + config.configKey() 3309 + " from " + link.configKey()); 3310 } 3311 link.dirty = true; 3312 link.linkedConfigurations.remove(config.configKey()); 3313 } 3314 if (config.linkedConfigurations != null 3315 && (config.linkedConfigurations.get(link.configKey()) != null)) { 3316 if (VDBG) { 3317 loge("linkConfiguration: un-link " + link.configKey() 3318 + " from " + config.configKey()); 3319 } 3320 config.dirty = true; 3321 config.linkedConfigurations.remove(link.configKey()); 3322 } 3323 } 3324 } 3325 } 3326 3327 /* 3328 * We try to link a scan result with a WifiConfiguration for which SSID and 3329 * key management dont match, 3330 * for instance, we try identify the 5GHz SSID of a DBDC AP, 3331 * even though we know only of the 2.4GHz 3332 * 3333 * Obviously, this function is not optimal since it is used to compare every scan 3334 * result with every Saved WifiConfiguration, with a string.equals operation. 3335 * As a speed up, might be better to implement the mConfiguredNetworks store as a 3336 * <String, WifiConfiguration> object instead of a <Integer, WifiConfiguration> object 3337 * so as to speed this up. Also to prevent the tiny probability of hash collision. 3338 * 3339 */ 3340 public WifiConfiguration associateWithConfiguration(ScanDetail scanDetail) { 3341 3342 ScanResult result = scanDetail.getScanResult(); 3343 boolean doNotAdd = false; 3344 String configKey = WifiConfiguration.configKey(result); 3345 if (configKey == null) { 3346 if (DBG) loge("associateWithConfiguration(): no config key " ); 3347 return null; 3348 } 3349 3350 // Need to compare with quoted string 3351 String SSID = "\"" + result.SSID + "\""; 3352 3353 if (VVDBG) { 3354 loge("associateWithConfiguration(): try " + configKey); 3355 } 3356 3357 Checksum csum = new CRC32(); 3358 csum.update(SSID.getBytes(), 0, SSID.getBytes().length); 3359 if (mDeletedSSIDs.contains(csum.getValue())) { 3360 doNotAdd = true; 3361 } 3362 3363 WifiConfiguration config = null; 3364 for (WifiConfiguration link : mConfiguredNetworks.values()) { 3365 boolean doLink = false; 3366 3367 if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.selfAdded || 3368 link.ephemeral) { 3369 if (VVDBG) loge("associateWithConfiguration(): skip selfadd " + link.configKey() ); 3370 // Make sure we dont associate the scan result to a deleted config 3371 continue; 3372 } 3373 3374 if (!link.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 3375 if (VVDBG) loge("associateWithConfiguration(): skip non-PSK " + link.configKey() ); 3376 // Make sure we dont associate the scan result to a non-PSK config 3377 continue; 3378 } 3379 3380 if (configKey.equals(link.configKey())) { 3381 if (VVDBG) loge("associateWithConfiguration(): found it!!! " + configKey ); 3382 return link; // Found it exactly 3383 } 3384 3385 ScanDetailCache linkedScanDetailCache = getScanDetailCache(link); 3386 if (!doNotAdd 3387 && (linkedScanDetailCache != null) && (linkedScanDetailCache.size() <= 6)) { 3388 for (String bssid : linkedScanDetailCache.keySet()) { 3389 if (result.BSSID.regionMatches(true, 0, bssid, 0, 16) 3390 && SSID.regionMatches(false, 0, link.SSID, 0, 4)) { 3391 // If first 16 ascii characters of BSSID matches, and first 3 3392 // characters of SSID match, we assume this is a home setup 3393 // and thus we will try to transfer the password from the known 3394 // BSSID/SSID to the recently found BSSID/SSID 3395 3396 // If (VDBG) 3397 // loge("associateWithConfiguration OK " ); 3398 doLink = true; 3399 break; 3400 } 3401 } 3402 } 3403 3404 if (doLink) { 3405 // Try to make a non verified WifiConfiguration, but only if the original 3406 // configuration was not self already added 3407 if (VDBG) { 3408 loge("associateWithConfiguration: try to create " + 3409 result.SSID + " and associate it with: " + link.SSID 3410 + " key " + link.configKey()); 3411 } 3412 config = wifiConfigurationFromScanResult(scanDetail); 3413 if (config != null) { 3414 config.selfAdded = true; 3415 config.didSelfAdd = true; 3416 config.dirty = true; 3417 config.peerWifiConfiguration = link.configKey(); 3418 config.lastUpdateName = link.lastUpdateName; 3419 config.creatorName = link.creatorName; 3420 config.lastUpdateUid = link.lastUpdateUid; 3421 config.creatorUid = link.creatorUid; 3422 config.userApproved = link.userApproved; 3423 3424 if (config.allowedKeyManagement.equals(link.allowedKeyManagement) && 3425 config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 3426 if (VDBG && config != null) { 3427 loge("associateWithConfiguration: got a config from beacon" 3428 + config.SSID + " key " + config.configKey()); 3429 } 3430 // Transfer the credentials from the configuration we are linking from 3431 String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); 3432 if (psk != null) { 3433 config.preSharedKey = psk; 3434 if (VDBG) { 3435 if (config.preSharedKey != null) 3436 loge(" transfer PSK : " + config.preSharedKey); 3437 } 3438 3439 // Link configurations 3440 if (link.linkedConfigurations == null) { 3441 link.linkedConfigurations = new HashMap<String, Integer>(); 3442 } 3443 if (config.linkedConfigurations == null) { 3444 config.linkedConfigurations = new HashMap<String, Integer>(); 3445 } 3446 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 3447 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 3448 3449 // Carry over the Ip configuration 3450 if (link.getIpConfiguration() != null) { 3451 config.setIpConfiguration(link.getIpConfiguration()); 3452 } 3453 } else { 3454 config = null; 3455 } 3456 } else { 3457 config = null; 3458 } 3459 if (config != null) break; 3460 } 3461 if (VDBG && config != null) { 3462 loge("associateWithConfiguration: success, created: " + config.SSID 3463 + " key " + config.configKey()); 3464 } 3465 } 3466 } 3467 return config; 3468 } 3469 3470 public HashSet<Integer> makeChannelList(WifiConfiguration config, int age, boolean restrict) { 3471 if (config == null) 3472 return null; 3473 long now_ms = System.currentTimeMillis(); 3474 3475 HashSet<Integer> channels = new HashSet<Integer>(); 3476 3477 //get channels for this configuration, if there are at least 2 BSSIDs 3478 if (getScanDetailCache(config) == null && config.linkedConfigurations == null) { 3479 return null; 3480 } 3481 3482 if (VDBG) { 3483 StringBuilder dbg = new StringBuilder(); 3484 dbg.append("makeChannelList age=" + Integer.toString(age) 3485 + " for " + config.configKey() 3486 + " max=" + maxNumActiveChannelsForPartialScans); 3487 if (getScanDetailCache(config) != null) { 3488 dbg.append(" bssids=" + getScanDetailCache(config).size()); 3489 } 3490 if (config.linkedConfigurations != null) { 3491 dbg.append(" linked=" + config.linkedConfigurations.size()); 3492 } 3493 loge(dbg.toString()); 3494 } 3495 3496 int numChannels = 0; 3497 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 0) { 3498 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 3499 ScanResult result = scanDetail.getScanResult(); 3500 //TODO : cout active and passive channels separately 3501 if (numChannels > maxNumActiveChannelsForPartialScans.get()) { 3502 break; 3503 } 3504 if (VDBG) { 3505 boolean test = (now_ms - result.seen) < age; 3506 loge("has " + result.BSSID + " freq=" + Integer.toString(result.frequency) 3507 + " age=" + Long.toString(now_ms - result.seen) + " ?=" + test); 3508 } 3509 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 3510 channels.add(result.frequency); 3511 numChannels++; 3512 } 3513 } 3514 } 3515 3516 //get channels for linked configurations 3517 if (config.linkedConfigurations != null) { 3518 for (String key : config.linkedConfigurations.keySet()) { 3519 WifiConfiguration linked = getWifiConfiguration(key); 3520 if (linked == null) 3521 continue; 3522 if (getScanDetailCache(linked) == null) { 3523 continue; 3524 } 3525 for (ScanDetail scanDetail : getScanDetailCache(linked).values()) { 3526 ScanResult result = scanDetail.getScanResult(); 3527 if (VDBG) { 3528 loge("has link: " + result.BSSID 3529 + " freq=" + Integer.toString(result.frequency) 3530 + " age=" + Long.toString(now_ms - result.seen)); 3531 } 3532 if (numChannels > maxNumActiveChannelsForPartialScans.get()) { 3533 break; 3534 } 3535 if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) { 3536 channels.add(result.frequency); 3537 numChannels++; 3538 } 3539 } 3540 } 3541 } 3542 return channels; 3543 } 3544 3545 // !!! JNo >> 3546 3547 // !!! Call from addToScanCache 3548 private Map<HomeSP, PasspointMatch> matchPasspointNetworks(ScanDetail scanDetail) { 3549 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3550 if (!networkDetail.hasInterworking()) { 3551 return null; 3552 } 3553 updateAnqpCache(scanDetail, networkDetail.getANQPElements()); 3554 3555 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, 3556 networkDetail.getANQPElements() == null); 3557 Log.d("HS2J", scanDetail.getSSID() + " pass 1 matches: " + toMatchString(matches)); 3558 return matches; 3559 } 3560 3561 private Map<HomeSP, PasspointMatch> matchNetwork(ScanDetail scanDetail, boolean query) { 3562 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3563 3564 ANQPData anqpData = mAnqpCache.getEntry(networkDetail); 3565 3566 Map<Constants.ANQPElementType, ANQPElement> anqpElements = 3567 anqpData != null ? anqpData.getANQPElements() : null; 3568 3569 boolean queried = !query; 3570 Collection<HomeSP> homeSPs = getHomeSPs(); 3571 Map<HomeSP, PasspointMatch> matches = new HashMap<>(homeSPs.size()); 3572 Log.d("HS2J", "match nwk " + scanDetail.getSSID() + 3573 ", anqp " + ( anqpData != null ? "present" : "missing" ) + 3574 ", query " + query + ", home sps: " + homeSPs.size()); 3575 for (HomeSP homeSP : homeSPs) { 3576 PasspointMatch match = homeSP.match(networkDetail, anqpElements, mImsis); 3577 3578 if (match == PasspointMatch.Incomplete && networkDetail.isInterworking() && !queried) { 3579 if (mAnqpCache.initiate(networkDetail)) { 3580 mSupplicantBridge.startANQP(scanDetail); 3581 } 3582 queried = true; 3583 } 3584 matches.put(homeSP, match); 3585 } 3586 return matches; 3587 } 3588 3589 public void notifyANQPDone(Long bssid, boolean success) { 3590 mSupplicantBridge.notifyANQPDone(bssid, success); 3591 } 3592 3593 public void notifyANQPResponse(ScanDetail scanDetail, 3594 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 3595 3596 updateAnqpCache(scanDetail, anqpElements); 3597 if (anqpElements == null) { 3598 return; 3599 } 3600 3601 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, false); 3602 Log.d("HS2J", scanDetail.getSSID() + " pass 2 matches: " + toMatchString(matches)); 3603 3604 cacheScanResultForPasspointConfig(scanDetail, matches); 3605 } 3606 3607 3608 private void updateAnqpCache(ScanDetail scanDetail, 3609 Map<Constants.ANQPElementType,ANQPElement> anqpElements) 3610 { 3611 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3612 3613 if (anqpElements == null) { 3614 ANQPData data = mAnqpCache.getEntry(networkDetail); 3615 if (data != null) { 3616 scanDetail.propagateANQPInfo(data.getANQPElements()); 3617 } 3618 return; 3619 } 3620 3621 mAnqpCache.update(networkDetail, anqpElements); 3622 3623 scanDetail.propagateANQPInfo(anqpElements); 3624 } 3625 3626 private static String toMatchString(Map<HomeSP, PasspointMatch> matches) { 3627 StringBuilder sb = new StringBuilder(); 3628 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 3629 sb.append(' ').append(entry.getKey().getFQDN()).append("->").append(entry.getValue()); 3630 } 3631 return sb.toString(); 3632 } 3633 3634 // !!! << JNo 3635 3636 private void cacheScanResultForPasspointConfig(ScanDetail scanDetail, 3637 Map<HomeSP,PasspointMatch> matches) { 3638 3639 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 3640 WifiConfiguration config = getWifiConfigForHomeSP(entry.getKey()); 3641 if (config != null) { 3642 cacheScanResultForConfig(config, scanDetail); 3643 } else { 3644 /* perhaps the configuration was deleted?? */ 3645 } 3646 } 3647 } 3648 3649 private void cacheScanResultForConfig(WifiConfiguration config, ScanDetail scanDetail) { 3650 3651 ScanResult scanResult = scanDetail.getScanResult(); 3652 3653 if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DELETED) { 3654 if (VVDBG) { 3655 loge("updateSavedNetworkHistory(): found a deleted, skip it... " 3656 + config.configKey()); 3657 } 3658 // The scan result belongs to a deleted config: 3659 // - increment numConfigFound to remember that we found a config 3660 // matching for this scan result 3661 // - dont do anything since the config was deleted, just skip... 3662 return; 3663 } 3664 3665 ScanDetailCache scanDetailCache = getScanDetailCache(config); 3666 if (scanDetailCache == null) { 3667 Log.w(TAG, "Could not allocate scan cache for " + config.SSID); 3668 return; 3669 } 3670 3671 // Adding a new BSSID 3672 ScanResult result = scanDetailCache.get(scanResult.BSSID); 3673 if (result != null) { 3674 // transfer the black list status 3675 scanResult.autoJoinStatus = result.autoJoinStatus; 3676 scanResult.blackListTimestamp = result.blackListTimestamp; 3677 scanResult.numIpConfigFailures = result.numIpConfigFailures; 3678 scanResult.numConnection = result.numConnection; 3679 scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate; 3680 } 3681 3682 if (config.ephemeral) { 3683 // For an ephemeral Wi-Fi config, the ScanResult should be considered 3684 // untrusted. 3685 scanResult.untrusted = true; 3686 } 3687 3688 if (scanDetailCache.size() > (maxNumScanCacheEntries + 64)) { 3689 long now_dbg = 0; 3690 if (VVDBG) { 3691 loge(" Will trim config " + config.configKey() 3692 + " size " + scanDetailCache.size()); 3693 3694 for (ScanDetail sd : scanDetailCache.values()) { 3695 loge(" " + sd.getBSSIDString() + " " + sd.getSeen()); 3696 } 3697 now_dbg = SystemClock.elapsedRealtimeNanos(); 3698 } 3699 // Trim the scan result cache to maxNumScanCacheEntries entries max 3700 // Since this operation is expensive, make sure it is not performed 3701 // until the cache has grown significantly above the trim treshold 3702 scanDetailCache.trim(maxNumScanCacheEntries); 3703 if (VVDBG) { 3704 long diff = SystemClock.elapsedRealtimeNanos() - now_dbg; 3705 loge(" Finished trimming config, time(ns) " + diff); 3706 for (ScanDetail sd : scanDetailCache.values()) { 3707 loge(" " + sd.getBSSIDString() + " " + sd.getSeen()); 3708 } 3709 } 3710 } 3711 3712 // Add the scan result to this WifiConfiguration 3713 scanDetailCache.put(scanDetail); 3714 // Since we added a scan result to this configuration, re-attempt linking 3715 linkConfiguration(config); 3716 } 3717 3718 3719 // Update the WifiConfiguration database with the new scan result 3720 // A scan result can be associated to multiple WifiConfigurations 3721 public boolean updateSavedNetworkHistory(ScanDetail scanDetail) { 3722 3723 ScanResult scanResult = scanDetail.getScanResult(); 3724 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 3725 3726 int numConfigFound = 0; 3727 if (scanResult == null) 3728 return false; 3729 3730 String SSID = "\"" + scanResult.SSID + "\""; 3731 3732 if (networkDetail.hasInterworking()) { 3733 Map<HomeSP, PasspointMatch> matches = matchPasspointNetworks(scanDetail); 3734 cacheScanResultForPasspointConfig(scanDetail, matches); 3735 return matches.size() != 0; 3736 } 3737 3738 for (WifiConfiguration config : mConfiguredNetworks.values()) { 3739 boolean found = false; 3740 3741 if (config.SSID == null || !config.SSID.equals(SSID)) { 3742 // SSID mismatch 3743 if (VVDBG) { 3744 loge("updateSavedNetworkHistory(): SSID mismatch " + config.configKey() 3745 + " SSID=" + config.SSID + " " + SSID); 3746 } 3747 continue; 3748 } 3749 if (VDBG) { 3750 loge("updateSavedNetworkHistory(): try " + config.configKey() 3751 + " SSID=" + config.SSID + " " + scanResult.SSID 3752 + " " + scanResult.capabilities 3753 + " ajst=" + config.autoJoinStatus); 3754 } 3755 if (scanResult.capabilities.contains("WEP") 3756 && config.configKey().contains("WEP")) { 3757 found = true; 3758 } else if (scanResult.capabilities.contains("PSK") 3759 && config.configKey().contains("PSK")) { 3760 found = true; 3761 } else if (scanResult.capabilities.contains("EAP") 3762 && config.configKey().contains("EAP")) { 3763 found = true; 3764 } else if (!scanResult.capabilities.contains("WEP") 3765 && !scanResult.capabilities.contains("PSK") 3766 && !scanResult.capabilities.contains("EAP") 3767 && !config.configKey().contains("WEP") 3768 && !config.configKey().contains("PSK") 3769 && !config.configKey().contains("EAP")) { 3770 found = true; 3771 } 3772 3773 if (found) { 3774 numConfigFound ++; 3775 cacheScanResultForConfig(config, scanDetail); 3776 } 3777 3778 if (VDBG && found) { 3779 String status = ""; 3780 if (scanResult.autoJoinStatus > 0) { 3781 status = " status=" + Integer.toString(scanResult.autoJoinStatus); 3782 } 3783 loge(" got known scan result " + 3784 scanResult.BSSID + " key : " 3785 + config.configKey() + " num: " + 3786 Integer.toString(getScanDetailCache(config).size()) 3787 + " rssi=" + Integer.toString(scanResult.level) 3788 + " freq=" + Integer.toString(scanResult.frequency) 3789 + status); 3790 } 3791 } 3792 return numConfigFound != 0; 3793 } 3794 3795 /* Compare current and new configuration and write to file on change */ 3796 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 3797 WifiConfiguration currentConfig, 3798 WifiConfiguration newConfig) { 3799 boolean ipChanged = false; 3800 boolean proxyChanged = false; 3801 3802 if (VDBG) { 3803 loge("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " + 3804 newConfig.SSID + " path: " + ipConfigFile); 3805 } 3806 3807 3808 switch (newConfig.getIpAssignment()) { 3809 case STATIC: 3810 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 3811 ipChanged = true; 3812 } else { 3813 ipChanged = !Objects.equals( 3814 currentConfig.getStaticIpConfiguration(), 3815 newConfig.getStaticIpConfiguration()); 3816 } 3817 break; 3818 case DHCP: 3819 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 3820 ipChanged = true; 3821 } 3822 break; 3823 case UNASSIGNED: 3824 /* Ignore */ 3825 break; 3826 default: 3827 loge("Ignore invalid ip assignment during write"); 3828 break; 3829 } 3830 3831 switch (newConfig.getProxySettings()) { 3832 case STATIC: 3833 case PAC: 3834 ProxyInfo newHttpProxy = newConfig.getHttpProxy(); 3835 ProxyInfo currentHttpProxy = currentConfig.getHttpProxy(); 3836 3837 if (newHttpProxy != null) { 3838 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 3839 } else { 3840 proxyChanged = (currentHttpProxy != null); 3841 } 3842 break; 3843 case NONE: 3844 if (currentConfig.getProxySettings() != newConfig.getProxySettings()) { 3845 proxyChanged = true; 3846 } 3847 break; 3848 case UNASSIGNED: 3849 /* Ignore */ 3850 break; 3851 default: 3852 loge("Ignore invalid proxy configuration during write"); 3853 break; 3854 } 3855 3856 if (ipChanged) { 3857 currentConfig.setIpAssignment(newConfig.getIpAssignment()); 3858 currentConfig.setStaticIpConfiguration(newConfig.getStaticIpConfiguration()); 3859 log("IP config changed SSID = " + currentConfig.SSID); 3860 if (currentConfig.getStaticIpConfiguration() != null) { 3861 log(" static configuration: " + 3862 currentConfig.getStaticIpConfiguration().toString()); 3863 } 3864 } 3865 3866 if (proxyChanged) { 3867 currentConfig.setProxySettings(newConfig.getProxySettings()); 3868 currentConfig.setHttpProxy(newConfig.getHttpProxy()); 3869 log("proxy changed SSID = " + currentConfig.SSID); 3870 if (currentConfig.getHttpProxy() != null) { 3871 log(" proxyProperties: " + currentConfig.getHttpProxy().toString()); 3872 } 3873 } 3874 3875 if (ipChanged || proxyChanged) { 3876 writeIpAndProxyConfigurations(); 3877 sendConfiguredNetworksChangedBroadcast(currentConfig, 3878 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 3879 } 3880 return new NetworkUpdateResult(ipChanged, proxyChanged); 3881 } 3882 3883 /** Returns true if a particular config key needs to be quoted when passed to the supplicant. */ 3884 private boolean enterpriseConfigKeyShouldBeQuoted(String key) { 3885 switch (key) { 3886 case WifiEnterpriseConfig.EAP_KEY: 3887 case WifiEnterpriseConfig.ENGINE_KEY: 3888 return false; 3889 default: 3890 return true; 3891 } 3892 } 3893 3894 /** 3895 * Read the variables from the supplicant daemon that are needed to 3896 * fill in the WifiConfiguration object. 3897 * 3898 * @param config the {@link WifiConfiguration} object to be filled in. 3899 */ 3900 private void readNetworkVariables(WifiConfiguration config) { 3901 3902 int netId = config.networkId; 3903 if (netId < 0) 3904 return; 3905 3906 /* 3907 * TODO: maybe should have a native method that takes an array of 3908 * variable names and returns an array of values. But we'd still 3909 * be doing a round trip to the supplicant daemon for each variable. 3910 */ 3911 String value; 3912 3913 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); 3914 if (!TextUtils.isEmpty(value)) { 3915 if (value.charAt(0) != '"') { 3916 config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; 3917 //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted 3918 //supplicant string 3919 } else { 3920 config.SSID = value; 3921 } 3922 } else { 3923 config.SSID = null; 3924 } 3925 3926 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); 3927 if (!TextUtils.isEmpty(value)) { 3928 config.BSSID = value; 3929 } else { 3930 config.BSSID = null; 3931 } 3932 3933 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); 3934 config.priority = -1; 3935 if (!TextUtils.isEmpty(value)) { 3936 try { 3937 config.priority = Integer.parseInt(value); 3938 } catch (NumberFormatException ignore) { 3939 } 3940 } 3941 3942 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); 3943 config.hiddenSSID = false; 3944 if (!TextUtils.isEmpty(value)) { 3945 try { 3946 config.hiddenSSID = Integer.parseInt(value) != 0; 3947 } catch (NumberFormatException ignore) { 3948 } 3949 } 3950 3951 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); 3952 config.wepTxKeyIndex = -1; 3953 if (!TextUtils.isEmpty(value)) { 3954 try { 3955 config.wepTxKeyIndex = Integer.parseInt(value); 3956 } catch (NumberFormatException ignore) { 3957 } 3958 } 3959 3960 for (int i = 0; i < 4; i++) { 3961 value = mWifiNative.getNetworkVariable(netId, 3962 WifiConfiguration.wepKeyVarNames[i]); 3963 if (!TextUtils.isEmpty(value)) { 3964 config.wepKeys[i] = value; 3965 } else { 3966 config.wepKeys[i] = null; 3967 } 3968 } 3969 3970 value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); 3971 if (!TextUtils.isEmpty(value)) { 3972 config.preSharedKey = value; 3973 } else { 3974 config.preSharedKey = null; 3975 } 3976 3977 value = mWifiNative.getNetworkVariable(config.networkId, 3978 WifiConfiguration.Protocol.varName); 3979 if (!TextUtils.isEmpty(value)) { 3980 String vals[] = value.split(" "); 3981 for (String val : vals) { 3982 int index = 3983 lookupString(val, WifiConfiguration.Protocol.strings); 3984 if (0 <= index) { 3985 config.allowedProtocols.set(index); 3986 } 3987 } 3988 } 3989 3990 value = mWifiNative.getNetworkVariable(config.networkId, 3991 WifiConfiguration.KeyMgmt.varName); 3992 if (!TextUtils.isEmpty(value)) { 3993 String vals[] = value.split(" "); 3994 for (String val : vals) { 3995 int index = 3996 lookupString(val, WifiConfiguration.KeyMgmt.strings); 3997 if (0 <= index) { 3998 config.allowedKeyManagement.set(index); 3999 } 4000 } 4001 } 4002 4003 value = mWifiNative.getNetworkVariable(config.networkId, 4004 WifiConfiguration.AuthAlgorithm.varName); 4005 if (!TextUtils.isEmpty(value)) { 4006 String vals[] = value.split(" "); 4007 for (String val : vals) { 4008 int index = 4009 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 4010 if (0 <= index) { 4011 config.allowedAuthAlgorithms.set(index); 4012 } 4013 } 4014 } 4015 4016 value = mWifiNative.getNetworkVariable(config.networkId, 4017 WifiConfiguration.PairwiseCipher.varName); 4018 if (!TextUtils.isEmpty(value)) { 4019 String vals[] = value.split(" "); 4020 for (String val : vals) { 4021 int index = 4022 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 4023 if (0 <= index) { 4024 config.allowedPairwiseCiphers.set(index); 4025 } 4026 } 4027 } 4028 4029 value = mWifiNative.getNetworkVariable(config.networkId, 4030 WifiConfiguration.GroupCipher.varName); 4031 if (!TextUtils.isEmpty(value)) { 4032 String vals[] = value.split(" "); 4033 for (String val : vals) { 4034 int index = 4035 lookupString(val, WifiConfiguration.GroupCipher.strings); 4036 if (0 <= index) { 4037 config.allowedGroupCiphers.set(index); 4038 } 4039 } 4040 } 4041 4042 if (config.enterpriseConfig == null) { 4043 config.enterpriseConfig = new WifiEnterpriseConfig(); 4044 } 4045 HashMap<String, String> enterpriseFields = config.enterpriseConfig.getFields(); 4046 for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { 4047 value = mWifiNative.getNetworkVariable(netId, key); 4048 if (!TextUtils.isEmpty(value)) { 4049 if (!enterpriseConfigKeyShouldBeQuoted(key)) { 4050 value = removeDoubleQuotes(value); 4051 } 4052 enterpriseFields.put(key, value); 4053 } else { 4054 enterpriseFields.put(key, EMPTY_VALUE); 4055 } 4056 } 4057 4058 if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { 4059 saveConfig(); 4060 } 4061 4062 migrateCerts(config.enterpriseConfig); 4063 // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); 4064 } 4065 4066 private static String removeDoubleQuotes(String string) { 4067 int length = string.length(); 4068 if ((length > 1) && (string.charAt(0) == '"') 4069 && (string.charAt(length - 1) == '"')) { 4070 return string.substring(1, length - 1); 4071 } 4072 return string; 4073 } 4074 4075 private static String makeString(BitSet set, String[] strings) { 4076 StringBuffer buf = new StringBuffer(); 4077 int nextSetBit = -1; 4078 4079 /* Make sure all set bits are in [0, strings.length) to avoid 4080 * going out of bounds on strings. (Shouldn't happen, but...) */ 4081 set = set.get(0, strings.length); 4082 4083 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 4084 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 4085 } 4086 4087 // remove trailing space 4088 if (set.cardinality() > 0) { 4089 buf.setLength(buf.length() - 1); 4090 } 4091 4092 return buf.toString(); 4093 } 4094 4095 private int lookupString(String string, String[] strings) { 4096 int size = strings.length; 4097 4098 string = string.replace('-', '_'); 4099 4100 for (int i = 0; i < size; i++) 4101 if (string.equals(strings[i])) 4102 return i; 4103 4104 // if we ever get here, we should probably add the 4105 // value to WifiConfiguration to reflect that it's 4106 // supported by the WPA supplicant 4107 loge("Failed to look-up a string: " + string); 4108 4109 return -1; 4110 } 4111 4112 /* return the allowed key management based on a scan result */ 4113 4114 public WifiConfiguration wifiConfigurationFromScanResult(ScanDetail scanDetail) { 4115 4116 ScanResult result = scanDetail.getScanResult(); 4117 WifiConfiguration config = new WifiConfiguration(); 4118 4119 config.SSID = "\"" + result.SSID + "\""; 4120 4121 if (VDBG) { 4122 loge("WifiConfiguration from scan results " + 4123 config.SSID + " cap " + result.capabilities); 4124 } 4125 if (result.capabilities.contains("WEP")) { 4126 config.allowedKeyManagement.set(KeyMgmt.NONE); 4127 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); //? 4128 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 4129 } 4130 4131 if (result.capabilities.contains("PSK")) { 4132 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 4133 } 4134 4135 if (result.capabilities.contains("EAP")) { 4136 //this is probably wrong, as we don't have a way to enter the enterprise config 4137 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 4138 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 4139 } 4140 4141 /* getScanDetailCache(config).put(scanDetail); */ 4142 4143 return config; 4144 } 4145 4146 4147 /* Returns a unique for a given configuration */ 4148 private static int configKey(WifiConfiguration config) { 4149 String key = config.configKey(); 4150 return key.hashCode(); 4151 } 4152 4153 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4154 pw.println("Dump of WifiConfigStore"); 4155 pw.println("mLastPriority " + mLastPriority); 4156 pw.println("Configured networks"); 4157 for (WifiConfiguration conf : getConfiguredNetworks()) { 4158 pw.println(conf); 4159 } 4160 pw.println(); 4161 4162 if (mLocalLog != null) { 4163 pw.println("WifiConfigStore - Log Begin ----"); 4164 mLocalLog.dump(fd, pw, args); 4165 pw.println("WifiConfigStore - Log End ----"); 4166 } 4167 } 4168 4169 public String getConfigFile() { 4170 return ipConfigFile; 4171 } 4172 4173 protected void loge(String s) { 4174 loge(s, false); 4175 } 4176 4177 protected void loge(String s, boolean stack) { 4178 if (stack) { 4179 Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 4180 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 4181 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 4182 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 4183 } else { 4184 Log.e(TAG, s); 4185 } 4186 } 4187 4188 protected void log(String s) { 4189 Log.d(TAG, s); 4190 } 4191 4192 private void localLog(String s) { 4193 if (mLocalLog != null) { 4194 mLocalLog.log(s); 4195 } 4196 } 4197 4198 private void localLog(String s, boolean force) { 4199 localLog(s); 4200 if (force) loge(s); 4201 } 4202 4203 private void localLog(String s, int netId) { 4204 if (mLocalLog == null) { 4205 return; 4206 } 4207 4208 WifiConfiguration config; 4209 synchronized(mConfiguredNetworks) { 4210 config = mConfiguredNetworks.get(netId); 4211 } 4212 4213 if (config != null) { 4214 mLocalLog.log(s + " " + config.getPrintableSsid() + " " + netId 4215 + " status=" + config.status 4216 + " key=" + config.configKey()); 4217 } else { 4218 mLocalLog.log(s + " " + netId); 4219 } 4220 } 4221 4222 // Certificate and private key management for EnterpriseConfig 4223 static boolean needsKeyStore(WifiEnterpriseConfig config) { 4224 // Has no keys to be installed 4225 if (config.getClientCertificate() == null && config.getCaCertificate() == null) 4226 return false; 4227 return true; 4228 } 4229 4230 static boolean isHardwareBackedKey(PrivateKey key) { 4231 return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); 4232 } 4233 4234 static boolean hasHardwareBackedKey(Certificate certificate) { 4235 return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); 4236 } 4237 4238 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 4239 String client = config.getClientCertificateAlias(); 4240 if (!TextUtils.isEmpty(client)) { 4241 // a valid client certificate is configured 4242 4243 // BUGBUG: keyStore.get() never returns certBytes; because it is not 4244 // taking WIFI_UID as a parameter. It always looks for certificate 4245 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 4246 // all certificates need software keystore until we get the get() API 4247 // fixed. 4248 4249 return true; 4250 } 4251 4252 /* 4253 try { 4254 4255 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 4256 .USER_CERTIFICATE + client); 4257 4258 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 4259 if (factory == null) { 4260 Slog.e(TAG, "Error getting certificate factory"); 4261 return; 4262 } 4263 4264 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 4265 if (certBytes != null) { 4266 Certificate cert = (X509Certificate) factory.generateCertificate( 4267 new ByteArrayInputStream(certBytes)); 4268 4269 if (cert != null) { 4270 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 4271 4272 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 4273 .USER_CERTIFICATE + client); 4274 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 4275 "does not need" ) + " software key store"); 4276 } else { 4277 Slog.d(TAG, "could not generate certificate"); 4278 } 4279 } else { 4280 Slog.e(TAG, "Could not load client certificate " + Credentials 4281 .USER_CERTIFICATE + client); 4282 mNeedsSoftwareKeystore = true; 4283 } 4284 4285 } catch(CertificateException e) { 4286 Slog.e(TAG, "Could not read certificates"); 4287 mCaCert = null; 4288 mClientCertificate = null; 4289 } 4290 */ 4291 4292 return false; 4293 } 4294 4295 boolean isNetworkConfigured(WifiConfiguration config) { 4296 // Check if either we have a network Id or a WifiConfiguration 4297 // matching the one we are trying to add. 4298 4299 if(config.networkId != INVALID_NETWORK_ID) { 4300 return (mConfiguredNetworks.get(config.networkId) != null); 4301 } 4302 4303 Integer savedNetId = mNetworkIds.get(configKey(config)); 4304 if (savedNetId == null) { 4305 for (WifiConfiguration test : mConfiguredNetworks.values()) { 4306 if (test.configKey().equals(config.configKey())) { 4307 Log.d(TAG, "isNetworkConfigured " + config.configKey() 4308 + " was found, but no network Id"); 4309 return true; 4310 } 4311 } 4312 4313 return false; 4314 } 4315 4316 return true; 4317 } 4318 4319 /** 4320 * Checks if uid has access to modify the configuration corresponding to networkId. 4321 * 4322 * uid has access only if was the last to modify this network, or holds the 4323 * OVERRIDE_WIFI_CONFIG permission. 4324 */ 4325 boolean canModifyNetwork(int uid, int networkId) { 4326 WifiConfiguration config = mConfiguredNetworks.get(networkId); 4327 4328 String currentApp = mContext.getPackageManager().getNameForUid(uid); 4329 4330 if (config == null) { 4331 loge("canModifyNetwork: cannot find config networkId " + networkId); 4332 return false; 4333 } if (currentApp == null) { 4334 loge("canModifyNetwork: unkown uid " + uid); 4335 return false; 4336 } 4337 4338 final DevicePolicyManagerInternal dpmi = LocalServices.getService( 4339 DevicePolicyManagerInternal.class); 4340 if (dpmi.isActiveAdminWithPolicy(config.creatorUid, 4341 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) { 4342 return uid == config.creatorUid; 4343 } 4344 4345 if (config.lastUpdateName == null) { 4346 Log.e(TAG, "Last update name should not be null"); 4347 return checkConfigOverridePermission(uid); 4348 } 4349 4350 return config.lastUpdateName.equals( currentApp ) || checkConfigOverridePermission(uid); 4351 } 4352 4353 /** 4354 * Checks if uid has access to modify config. 4355 */ 4356 boolean canModifyNetwork(int uid, WifiConfiguration config) { 4357 if (config == null) { 4358 loge("canModifyNetowrk recieved null configuration"); 4359 return false; 4360 } 4361 4362 // Resolve the correct network id. 4363 int netid; 4364 if (config.networkId != INVALID_NETWORK_ID){ 4365 netid = config.networkId; 4366 } else { 4367 Integer savedNetId = mNetworkIds.get(configKey(config)); 4368 if (savedNetId == null) { 4369 netid = INVALID_NETWORK_ID; 4370 4371 for (WifiConfiguration test : mConfiguredNetworks.values()) { 4372 // This should never happen. 4373 if (test.configKey().equals(config.configKey())) { 4374 loge("canModifyNetwork found WifiConfiguration " + config.configKey() 4375 + " , but not saved in configuredNetworks"); 4376 netid = test.networkId; 4377 } 4378 } 4379 4380 if (netid == INVALID_NETWORK_ID) { 4381 return false; 4382 } 4383 } else { 4384 netid = savedNetId; 4385 } 4386 } 4387 4388 return canModifyNetwork(uid, netid); 4389 } 4390 4391 boolean checkConfigOverridePermission(int uid) { 4392 try { 4393 return (AppGlobals.getPackageManager().checkUidPermission( 4394 android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid) 4395 == PackageManager.PERMISSION_GRANTED); 4396 } catch (RemoteException e) { 4397 return false; 4398 } 4399 } 4400 4401 /** called when CS ask WiFistateMachine to disconnect the current network 4402 * because the score is bad. 4403 */ 4404 void handleBadNetworkDisconnectReport(int netId, WifiInfo info) { 4405 /* TODO verify the bad network is current */ 4406 WifiConfiguration config = mConfiguredNetworks.get(netId); 4407 if (config != null) { 4408 if ((info.getRssi() < WifiConfiguration.UNWANTED_BLACKLIST_SOFT_RSSI_24 4409 && info.is24GHz()) || (info.getRssi() < 4410 WifiConfiguration.UNWANTED_BLACKLIST_SOFT_RSSI_5 && info.is5GHz())) { 4411 // We got disconnected and RSSI was bad, so disable light 4412 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED 4413 + WifiConfiguration.UNWANTED_BLACKLIST_SOFT_BUMP); 4414 loge("handleBadNetworkDisconnectReport (+4) " 4415 + Integer.toString(netId) + " " + info); 4416 } else { 4417 // We got disabled but RSSI is good, so disable hard 4418 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED 4419 + WifiConfiguration.UNWANTED_BLACKLIST_HARD_BUMP); 4420 loge("handleBadNetworkDisconnectReport (+8) " 4421 + Integer.toString(netId) + " " + info); 4422 } 4423 } 4424 // Record last time Connectivity Service switched us away from WiFi and onto Cell 4425 lastUnwantedNetworkDisconnectTimestamp = System.currentTimeMillis(); 4426 } 4427 4428 boolean handleBSSIDBlackList(int netId, String BSSID, boolean enable) { 4429 boolean found = false; 4430 if (BSSID == null) 4431 return found; 4432 4433 // Look for the BSSID in our config store 4434 for (WifiConfiguration config : mConfiguredNetworks.values()) { 4435 if (getScanDetailCache(config) != null) { 4436 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 4437 if (scanDetail.getBSSIDString().equals(BSSID)) { 4438 if (enable) { 4439 scanDetail.getScanResult().setAutoJoinStatus(ScanResult.ENABLED); 4440 } else { 4441 // Black list the BSSID we were trying to join 4442 // so as the Roam state machine 4443 // doesn't pick it up over and over 4444 scanDetail.getScanResult().setAutoJoinStatus( 4445 ScanResult.AUTO_ROAM_DISABLED); 4446 found = true; 4447 } 4448 } 4449 } 4450 } 4451 } 4452 return found; 4453 } 4454 4455 int getMaxDhcpRetries() { 4456 return Settings.Global.getInt(mContext.getContentResolver(), 4457 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 4458 DEFAULT_MAX_DHCP_RETRIES); 4459 } 4460 4461 void handleSSIDStateChange(int netId, boolean enabled, String message, String BSSID) { 4462 WifiConfiguration config = mConfiguredNetworks.get(netId); 4463 if (config != null) { 4464 if (enabled) { 4465 loge("SSID re-enabled for " + config.configKey() + 4466 " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus) 4467 + " self added " + config.selfAdded + " ephemeral " + config.ephemeral); 4468 //TODO: http://b/16381983 Fix Wifi Network Blacklisting 4469 //TODO: really I don't know if re-enabling is right but we 4470 //TODO: should err on the side of trying to connect 4471 //TODO: even if the attempt will fail 4472 if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { 4473 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 4474 } 4475 } else { 4476 loge("SSID temp disabled for " + config.configKey() + 4477 " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus) 4478 + " self added " + config.selfAdded + " ephemeral " + config.ephemeral); 4479 if (message != null) { 4480 loge(" message=" + message); 4481 } 4482 if (config.selfAdded && config.lastConnected == 0) { 4483 // This is a network we self added, and we never succeeded, 4484 // the user did not create this network and never entered its credentials, 4485 // so we want to be very aggressive in disabling it completely. 4486 removeConfigAndSendBroadcastIfNeeded(config.networkId); 4487 } else { 4488 if (message != null) { 4489 if (message.contains("no identity")) { 4490 config.setAutoJoinStatus( 4491 WifiConfiguration.AUTO_JOIN_DISABLED_NO_CREDENTIALS); 4492 if (DBG) { 4493 loge("no identity blacklisted " + config.configKey() + " to " 4494 + Integer.toString(config.autoJoinStatus)); 4495 } 4496 } else if (message.contains("WRONG_KEY") 4497 || message.contains("AUTH_FAILED")) { 4498 // This configuration has received an auth failure, so disable it 4499 // temporarily because we don't want auto-join to try it out. 4500 // this network may be re-enabled by the "usual" 4501 // enableAllNetwork function 4502 config.numAuthFailures++; 4503 if (config.numAuthFailures > maxAuthErrorsToBlacklist) { 4504 config.setAutoJoinStatus 4505 (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); 4506 disableNetwork(netId, 4507 WifiConfiguration.DISABLED_AUTH_FAILURE); 4508 loge("Authentication failure, blacklist " + config.configKey() + " " 4509 + Integer.toString(config.networkId) 4510 + " num failures " + config.numAuthFailures); 4511 } 4512 } else if (message.contains("DHCP FAILURE")) { 4513 config.numIpConfigFailures++; 4514 config.lastConnectionFailure = System.currentTimeMillis(); 4515 int maxRetries = getMaxDhcpRetries(); 4516 // maxRetries == 0 means keep trying forever 4517 if (maxRetries > 0 && config.numIpConfigFailures > maxRetries) { 4518 /** 4519 * If we've exceeded the maximum number of retries for DHCP 4520 * to a given network, disable the network 4521 */ 4522 config.setAutoJoinStatus 4523 (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); 4524 disableNetwork(netId, WifiConfiguration.DISABLED_DHCP_FAILURE); 4525 loge("DHCP failure, blacklist " + config.configKey() + " " 4526 + Integer.toString(config.networkId) 4527 + " num failures " + config.numIpConfigFailures); 4528 } 4529 4530 // Also blacklist the BSSId if we find it 4531 ScanResult result = null; 4532 String bssidDbg = ""; 4533 if (getScanDetailCache(config) != null && BSSID != null) { 4534 result = getScanDetailCache(config).get(BSSID); 4535 } 4536 if (result != null) { 4537 result.numIpConfigFailures ++; 4538 bssidDbg = BSSID + " ipfail=" + result.numIpConfigFailures; 4539 if (result.numIpConfigFailures > 3) { 4540 // Tell supplicant to stop trying this BSSID 4541 mWifiNative.addToBlacklist(BSSID); 4542 result.setAutoJoinStatus(ScanResult.AUTO_JOIN_DISABLED); 4543 } 4544 } 4545 4546 if (DBG) { 4547 loge("blacklisted " + config.configKey() + " to " 4548 + config.autoJoinStatus 4549 + " due to IP config failures, count=" 4550 + config.numIpConfigFailures 4551 + " disableReason=" + config.disableReason 4552 + " " + bssidDbg); 4553 } 4554 } else if (message.contains("CONN_FAILED")) { 4555 config.numConnectionFailures++; 4556 if (config.numConnectionFailures > maxConnectionErrorsToBlacklist) { 4557 config.setAutoJoinStatus 4558 (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); 4559 disableNetwork(netId, 4560 WifiConfiguration.DISABLED_ASSOCIATION_REJECT); 4561 loge("Connection failure, blacklist " + config.configKey() + " " 4562 + config.networkId 4563 + " num failures " + config.numConnectionFailures); 4564 } 4565 } 4566 message.replace("\n", ""); 4567 message.replace("\r", ""); 4568 config.lastFailure = message; 4569 } 4570 } 4571 } 4572 } 4573 } 4574 4575 boolean installKeys(WifiEnterpriseConfig config, String name) { 4576 boolean ret = true; 4577 String privKeyName = Credentials.USER_PRIVATE_KEY + name; 4578 String userCertName = Credentials.USER_CERTIFICATE + name; 4579 String caCertName = Credentials.CA_CERTIFICATE + name; 4580 if (config.getClientCertificate() != null) { 4581 byte[] privKeyData = config.getClientPrivateKey().getEncoded(); 4582 if (isHardwareBackedKey(config.getClientPrivateKey())) { 4583 // Hardware backed key store is secure enough to store keys un-encrypted, this 4584 // removes the need for user to punch a PIN to get access to these keys 4585 if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); 4586 ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, 4587 KeyStore.FLAG_NONE); 4588 } else { 4589 // Software backed key store is NOT secure enough to store keys un-encrypted. 4590 // Save keys encrypted so they are protected with user's PIN. User will 4591 // have to unlock phone before being able to use these keys and connect to 4592 // networks. 4593 if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); 4594 ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, 4595 KeyStore.FLAG_ENCRYPTED); 4596 } 4597 if (ret == false) { 4598 return ret; 4599 } 4600 4601 ret = putCertInKeyStore(userCertName, config.getClientCertificate()); 4602 if (ret == false) { 4603 // Remove private key installed 4604 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 4605 return ret; 4606 } 4607 } 4608 4609 if (config.getCaCertificate() != null) { 4610 ret = putCertInKeyStore(caCertName, config.getCaCertificate()); 4611 if (ret == false) { 4612 if (config.getClientCertificate() != null) { 4613 // Remove client key+cert 4614 mKeyStore.delKey(privKeyName, Process.WIFI_UID); 4615 mKeyStore.delete(userCertName, Process.WIFI_UID); 4616 } 4617 return ret; 4618 } 4619 } 4620 4621 // Set alias names 4622 if (config.getClientCertificate() != null) { 4623 config.setClientCertificateAlias(name); 4624 config.resetClientKeyEntry(); 4625 } 4626 4627 if (config.getCaCertificate() != null) { 4628 config.setCaCertificateAlias(name); 4629 config.resetCaCertificate(); 4630 } 4631 4632 return ret; 4633 } 4634 4635 private boolean putCertInKeyStore(String name, Certificate cert) { 4636 try { 4637 byte[] certData = Credentials.convertToPem(cert); 4638 if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); 4639 return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); 4640 4641 } catch (IOException e1) { 4642 return false; 4643 } catch (CertificateException e2) { 4644 return false; 4645 } 4646 } 4647 4648 void removeKeys(WifiEnterpriseConfig config) { 4649 String client = config.getClientCertificateAlias(); 4650 // a valid client certificate is configured 4651 if (!TextUtils.isEmpty(client)) { 4652 if (DBG) Log.d(TAG, "removing client private key and user cert"); 4653 mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 4654 mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 4655 } 4656 4657 String ca = config.getCaCertificateAlias(); 4658 // a valid ca certificate is configured 4659 if (!TextUtils.isEmpty(ca)) { 4660 if (DBG) Log.d(TAG, "removing CA cert"); 4661 mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 4662 } 4663 } 4664 4665 4666 /** Migrates the old style TLS config to the new config style. This should only be used 4667 * when restoring an old wpa_supplicant.conf or upgrading from a previous 4668 * platform version. 4669 * @return true if the config was updated 4670 * @hide 4671 */ 4672 boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { 4673 String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); 4674 /* 4675 * If the old configuration value is not present, then there is nothing 4676 * to do. 4677 */ 4678 if (TextUtils.isEmpty(oldPrivateKey)) { 4679 return false; 4680 } else { 4681 // Also ignore it if it's empty quotes. 4682 oldPrivateKey = removeDoubleQuotes(oldPrivateKey); 4683 if (TextUtils.isEmpty(oldPrivateKey)) { 4684 return false; 4685 } 4686 } 4687 4688 config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE); 4689 config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, 4690 WifiEnterpriseConfig.ENGINE_ID_KEYSTORE); 4691 4692 /* 4693 * The old key started with the keystore:// URI prefix, but we don't 4694 * need that anymore. Trim it off if it exists. 4695 */ 4696 final String keyName; 4697 if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) { 4698 keyName = new String( 4699 oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length())); 4700 } else { 4701 keyName = oldPrivateKey; 4702 } 4703 config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName); 4704 4705 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY, 4706 config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 4707 4708 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY, 4709 config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 4710 4711 mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, 4712 config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 4713 4714 // Remove old private_key string so we don't run this again. 4715 mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); 4716 4717 return true; 4718 } 4719 4720 /** Migrate certs from global pool to wifi UID if not already done */ 4721 void migrateCerts(WifiEnterpriseConfig config) { 4722 String client = config.getClientCertificateAlias(); 4723 // a valid client certificate is configured 4724 if (!TextUtils.isEmpty(client)) { 4725 if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { 4726 mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, 4727 Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); 4728 mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, 4729 Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); 4730 } 4731 } 4732 4733 String ca = config.getCaCertificateAlias(); 4734 // a valid ca certificate is configured 4735 if (!TextUtils.isEmpty(ca)) { 4736 if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { 4737 mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, 4738 Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); 4739 } 4740 } 4741 } 4742 4743} 4744