1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi.util; 18 19 import static com.android.wifi.flags.Flags.softapConfigStoreMaxChannelWidth; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SuppressLint; 24 import android.app.compat.CompatChanges; 25 import android.net.InetAddresses; 26 import android.net.IpConfiguration; 27 import android.net.IpConfiguration.IpAssignment; 28 import android.net.IpConfiguration.ProxySettings; 29 import android.net.LinkAddress; 30 import android.net.MacAddress; 31 import android.net.ProxyInfo; 32 import android.net.RouteInfo; 33 import android.net.StaticIpConfiguration; 34 import android.net.Uri; 35 import android.net.wifi.OuiKeyedData; 36 import android.net.wifi.ScanResult; 37 import android.net.wifi.SecurityParams; 38 import android.net.wifi.SoftApConfiguration; 39 import android.net.wifi.WifiConfiguration; 40 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; 41 import android.net.wifi.WifiEnterpriseConfig; 42 import android.net.wifi.WifiManager; 43 import android.net.wifi.WifiMigration; 44 import android.net.wifi.WifiSsid; 45 import android.net.wifi.util.Environment; 46 import android.os.ParcelUuid; 47 import android.os.PersistableBundle; 48 import android.text.TextUtils; 49 import android.util.Log; 50 import android.util.Pair; 51 import android.util.SparseIntArray; 52 53 import com.android.modules.utils.build.SdkLevel; 54 import com.android.wifi.flags.Flags; 55 56 import org.xmlpull.v1.XmlPullParser; 57 import org.xmlpull.v1.XmlPullParserException; 58 import org.xmlpull.v1.XmlSerializer; 59 60 import java.io.ByteArrayInputStream; 61 import java.io.ByteArrayOutputStream; 62 import java.io.IOException; 63 import java.net.Inet4Address; 64 import java.net.InetAddress; 65 import java.nio.charset.StandardCharsets; 66 import java.util.ArrayList; 67 import java.util.Arrays; 68 import java.util.BitSet; 69 import java.util.Collections; 70 import java.util.HashMap; 71 import java.util.List; 72 import java.util.Locale; 73 74 /** 75 * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core. 76 * The utility provides methods to write/parse section headers and write/parse values. 77 * This utility is designed for formatting the XML into the following format: 78 * <Document Header> 79 * <Section 1 Header> 80 * <Value 1> 81 * <Value 2> 82 * ... 83 * <Sub Section 1 Header> 84 * <Value 1> 85 * <Value 2> 86 * ... 87 * </Sub Section 1 Header> 88 * </Section 1 Header> 89 * </Document Header> 90 * 91 * Note: These utility methods are meant to be used for: 92 * 1. Backup/restore wifi network data to/from cloud. 93 * 2. Persisting wifi network data to/from disk. 94 */ 95 public class XmlUtil { 96 private static final String TAG = "WifiXmlUtil"; 97 98 public static final String XML_TAG_VENDOR_DATA_LIST = "VendorDataList"; 99 public static final String XML_TAG_OUI_KEYED_DATA = "OuiKeyedData"; 100 public static final String XML_TAG_VENDOR_DATA_OUI = "VendorDataOui"; 101 public static final String XML_TAG_PERSISTABLE_BUNDLE = "PersistableBundle"; 102 103 /** 104 * Ensure that the XML stream is at a start tag or the end of document. 105 * 106 * @throws XmlPullParserException if parsing errors occur. 107 */ gotoStartTag(XmlPullParser in)108 private static void gotoStartTag(XmlPullParser in) 109 throws XmlPullParserException, IOException { 110 int type = in.getEventType(); 111 while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { 112 type = in.next(); 113 } 114 } 115 116 /** 117 * Ensure that the XML stream is at an end tag or the end of document. 118 * 119 * @throws XmlPullParserException if parsing errors occur. 120 */ gotoEndTag(XmlPullParser in)121 private static void gotoEndTag(XmlPullParser in) 122 throws XmlPullParserException, IOException { 123 int type = in.getEventType(); 124 while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) { 125 type = in.next(); 126 } 127 } 128 129 /** 130 * Start processing the XML stream at the document header. 131 * 132 * @param in XmlPullParser instance pointing to the XML stream. 133 * @param headerName expected name for the start tag. 134 * @throws XmlPullParserException if parsing errors occur. 135 */ gotoDocumentStart(XmlPullParser in, String headerName)136 public static void gotoDocumentStart(XmlPullParser in, String headerName) 137 throws XmlPullParserException, IOException { 138 XmlUtilHelper.beginDocument(in, headerName); 139 } 140 141 /** 142 * Move the XML stream to the next section header or indicate if there are no more sections. 143 * The provided outerDepth is used to find sub sections within that depth. 144 * 145 * Use this to move across sections if the ordering of sections are variable. The returned name 146 * can be used to decide what section is next. 147 * 148 * @param in XmlPullParser instance pointing to the XML stream. 149 * @param headerName An array of one string, used to return the name of the next section. 150 * @param outerDepth Find section within this depth. 151 * @return {@code true} if a next section is found, {@code false} if there are no more sections. 152 * @throws XmlPullParserException if parsing errors occur. 153 */ gotoNextSectionOrEnd( XmlPullParser in, String[] headerName, int outerDepth)154 public static boolean gotoNextSectionOrEnd( 155 XmlPullParser in, String[] headerName, int outerDepth) 156 throws XmlPullParserException, IOException { 157 if (XmlUtilHelper.nextElementWithin(in, outerDepth)) { 158 headerName[0] = in.getName(); 159 return true; 160 } 161 return false; 162 } 163 164 /** 165 * Move the XML stream to the next section header or indicate if there are no more sections. 166 * If a section, exists ensure that the name matches the provided name. 167 * The provided outerDepth is used to find sub sections within that depth. 168 * 169 * Use this to move across repeated sections until the end. 170 * 171 * @param in XmlPullParser instance pointing to the XML stream. 172 * @param expectedName expected name for the section header. 173 * @param outerDepth Find section within this depth. 174 * @return {@code true} if a next section is found, {@code false} if there are no more sections. 175 * @throws XmlPullParserException if the section header name does not match |expectedName|, 176 * or if parsing errors occur. 177 */ gotoNextSectionWithNameOrEnd( XmlPullParser in, String expectedName, int outerDepth)178 public static boolean gotoNextSectionWithNameOrEnd( 179 XmlPullParser in, String expectedName, int outerDepth) 180 throws XmlPullParserException, IOException { 181 String[] headerName = new String[1]; 182 if (gotoNextSectionOrEnd(in, headerName, outerDepth)) { 183 if (headerName[0].equals(expectedName)) { 184 return true; 185 } 186 throw new XmlPullParserException( 187 "Next section name does not match expected name: " + expectedName); 188 } 189 return false; 190 } 191 192 /** 193 * Move the XML stream to the next section header and ensure that the name matches the provided 194 * name. 195 * The provided outerDepth is used to find sub sections within that depth. 196 * 197 * Use this to move across sections if the ordering of sections are fixed. 198 * 199 * @param in XmlPullParser instance pointing to the XML stream. 200 * @param expectedName expected name for the section header. 201 * @param outerDepth Find section within this depth. 202 * @throws XmlPullParserException if the section header name does not match |expectedName|, 203 * there are no more sections or if parsing errors occur. 204 */ gotoNextSectionWithName( XmlPullParser in, String expectedName, int outerDepth)205 public static void gotoNextSectionWithName( 206 XmlPullParser in, String expectedName, int outerDepth) 207 throws XmlPullParserException, IOException { 208 if (!gotoNextSectionWithNameOrEnd(in, expectedName, outerDepth)) { 209 throw new XmlPullParserException("Section not found. Expected: " + expectedName); 210 } 211 } 212 213 /** 214 * Checks if the stream is at the end of a section of values. This moves the stream to next tag 215 * and checks if it finds an end tag at the specified depth. 216 * 217 * @param in XmlPullParser instance pointing to the XML stream. 218 * @param sectionDepth depth of the start tag of this section. Used to match the end tag. 219 * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise 220 * @throws XmlPullParserException if parsing errors occur. 221 */ isNextSectionEnd(XmlPullParser in, int sectionDepth)222 public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth) 223 throws XmlPullParserException, IOException { 224 return !XmlUtilHelper.nextElementWithin(in, sectionDepth); 225 } 226 227 /** 228 * Read the current value in the XML stream using core XmlUtils and stores the retrieved 229 * value name in the string provided. This method reads the value contained in current start 230 * tag. 231 * Note: Because there could be genuine null values being read from the XML, this method raises 232 * an exception to indicate errors. 233 * 234 * @param in XmlPullParser instance pointing to the XML stream. 235 * @param valueName An array of one string, used to return the name attribute 236 * of the value's tag. 237 * @return value retrieved from the XML stream. 238 * @throws XmlPullParserException if parsing errors occur. 239 */ readCurrentValue(XmlPullParser in, String[] valueName)240 public static Object readCurrentValue(XmlPullParser in, String[] valueName) 241 throws XmlPullParserException, IOException { 242 Object value = XmlUtilHelper.readValueXml(in, valueName); 243 // XmlUtils.readValue does not always move the stream to the end of the tag. So, move 244 // it to the end tag before returning from here. 245 gotoEndTag(in); 246 return value; 247 } 248 249 /** 250 * Read the next value in the XML stream using core XmlUtils and ensure that it matches the 251 * provided name. This method moves the stream to the next start tag and reads the value 252 * contained in it. 253 * Note: Because there could be genuine null values being read from the XML, this method raises 254 * an exception to indicate errors. 255 * 256 * @param in XmlPullParser instance pointing to the XML stream. 257 * @return value retrieved from the XML stream. 258 * @throws XmlPullParserException if the value read does not match |expectedName|, 259 * or if parsing errors occur. 260 */ readNextValueWithName(XmlPullParser in, String expectedName)261 public static Object readNextValueWithName(XmlPullParser in, String expectedName) 262 throws XmlPullParserException, IOException { 263 String[] valueName = new String[1]; 264 XmlUtilHelper.nextElement(in); 265 Object value = readCurrentValue(in, valueName); 266 if (valueName[0].equals(expectedName)) { 267 return value; 268 } 269 throw new XmlPullParserException( 270 "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]); 271 } 272 273 /** 274 * Write the XML document start with the provided document header name. 275 * 276 * @param out XmlSerializer instance pointing to the XML stream. 277 * @param headerName name for the start tag. 278 */ writeDocumentStart(XmlSerializer out, String headerName)279 public static void writeDocumentStart(XmlSerializer out, String headerName) 280 throws IOException { 281 out.startDocument(null, true); 282 out.startTag(null, headerName); 283 } 284 285 /** 286 * Write the XML document end with the provided document header name. 287 * 288 * @param out XmlSerializer instance pointing to the XML stream. 289 * @param headerName name for the end tag. 290 */ writeDocumentEnd(XmlSerializer out, String headerName)291 public static void writeDocumentEnd(XmlSerializer out, String headerName) 292 throws IOException { 293 out.endTag(null, headerName); 294 out.endDocument(); 295 } 296 297 /** 298 * Write a section start header tag with the provided section name. 299 * 300 * @param out XmlSerializer instance pointing to the XML stream. 301 * @param headerName name for the start tag. 302 */ writeNextSectionStart(XmlSerializer out, String headerName)303 public static void writeNextSectionStart(XmlSerializer out, String headerName) 304 throws IOException { 305 out.startTag(null, headerName); 306 } 307 308 /** 309 * Write a section end header tag with the provided section name. 310 * 311 * @param out XmlSerializer instance pointing to the XML stream. 312 * @param headerName name for the end tag. 313 */ writeNextSectionEnd(XmlSerializer out, String headerName)314 public static void writeNextSectionEnd(XmlSerializer out, String headerName) 315 throws IOException { 316 out.endTag(null, headerName); 317 } 318 319 /** 320 * Write the value with the provided name in the XML stream using core XmlUtils. 321 * 322 * @param out XmlSerializer instance pointing to the XML stream. 323 * @param name name of the value. 324 * @param value value to be written. 325 */ writeNextValue(XmlSerializer out, String name, Object value)326 public static void writeNextValue(XmlSerializer out, String name, Object value) 327 throws XmlPullParserException, IOException { 328 XmlUtilHelper.writeValueXml(value, name, out); 329 } 330 331 /** 332 * Utility class to serialize and deserialize {@link WifiConfiguration} object to XML & 333 * vice versa. 334 * This is used by both {@link com.android.server.wifi.WifiConfigStore} & 335 * {@link com.android.server.wifi.WifiBackupRestore} modules. 336 * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store. 337 * There is only 1 version of |parseXmlToConfiguration| for both backup & config store. 338 * The parse method is written so that any element added/deleted in future revisions can 339 * be easily handled. 340 */ 341 public static class WifiConfigurationXmlUtil { 342 /** 343 * List of XML tags corresponding to WifiConfiguration object elements. 344 */ 345 public static final String XML_TAG_SSID = "SSID"; 346 public static final String XML_TAG_BSSID = "BSSID"; 347 public static final String XML_TAG_CONFIG_KEY = "ConfigKey"; 348 public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey"; 349 public static final String XML_TAG_WEP_KEYS = "WEPKeys"; 350 public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex"; 351 public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID"; 352 public static final String XML_TAG_REQUIRE_PMF = "RequirePMF"; 353 public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt"; 354 public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols"; 355 public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos"; 356 public static final String XML_TAG_ALLOWED_GROUP_CIPHERS = "AllowedGroupCiphers"; 357 public static final String XML_TAG_ALLOWED_PAIRWISE_CIPHERS = "AllowedPairwiseCiphers"; 358 public static final String XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS = "AllowedGroupMgmtCiphers"; 359 public static final String XML_TAG_ALLOWED_SUITE_B_CIPHERS = "AllowedSuiteBCiphers"; 360 public static final String XML_TAG_SHARED = "Shared"; 361 public static final String XML_TAG_STATUS = "Status"; 362 public static final String XML_TAG_FQDN = "FQDN"; 363 public static final String XML_TAG_PROVIDER_FRIENDLY_NAME = "ProviderFriendlyName"; 364 public static final String XML_TAG_LINKED_NETWORKS_LIST = "LinkedNetworksList"; 365 public static final String XML_TAG_DEFAULT_GW_MAC_ADDRESS = "DefaultGwMacAddress"; 366 public static final String XML_TAG_VALIDATED_INTERNET_ACCESS = "ValidatedInternetAccess"; 367 public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected"; 368 public static final String XML_TAG_METERED_HINT = "MeteredHint"; 369 public static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride"; 370 public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores"; 371 public static final String XML_TAG_CREATOR_UID = "CreatorUid"; 372 public static final String XML_TAG_CREATOR_NAME = "CreatorName"; 373 public static final String XML_TAG_LAST_UPDATE_UID = "LastUpdateUid"; 374 public static final String XML_TAG_LAST_UPDATE_NAME = "LastUpdateName"; 375 public static final String XML_TAG_LAST_CONNECT_UID = "LastConnectUid"; 376 public static final String XML_TAG_IS_LEGACY_PASSPOINT_CONFIG = "IsLegacyPasspointConfig"; 377 public static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs"; 378 public static final String XML_TAG_RANDOMIZED_MAC_ADDRESS = "RandomizedMacAddress"; 379 public static final String XML_TAG_MAC_RANDOMIZATION_SETTING = "MacRandomizationSetting"; 380 public static final String XML_TAG_SEND_DHCP_HOSTNAME = "SendDhcpHostname"; 381 public static final String XML_TAG_CARRIER_ID = "CarrierId"; 382 public static final String XML_TAG_SUBSCRIPTION_ID = "SubscriptionId"; 383 public static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled"; 384 public static final String XML_TAG_PRIORITY = "Priority"; 385 public static final String XML_TAG_DELETION_PRIORITY = "DeletionPriority"; 386 public static final String XML_TAG_NUM_REBOOTS_SINCE_LAST_USE = "NumRebootsSinceLastUse"; 387 388 public static final String XML_TAG_IS_TRUSTED = "Trusted"; 389 public static final String XML_TAG_IS_OEM_PAID = "OemPaid"; 390 public static final String XML_TAG_IS_OEM_PRIVATE = "OemPrivate"; 391 public static final String XML_TAG_IS_CARRIER_MERGED = "CarrierMerged"; 392 public static final String XML_TAG_SECURITY_PARAMS_LIST = "SecurityParamsList"; 393 public static final String XML_TAG_SECURITY_PARAMS = "SecurityParams"; 394 public static final String XML_TAG_SECURITY_TYPE = "SecurityType"; 395 public static final String XML_TAG_IS_ENABLED = "IsEnabled"; 396 public static final String XML_TAG_SAE_IS_H2E_ONLY_MODE = "SaeIsH2eOnlyMode"; 397 public static final String XML_TAG_SAE_IS_PK_ONLY_MODE = "SaeIsPkOnlyMode"; 398 public static final String XML_TAG_IS_ADDED_BY_AUTO_UPGRADE = "IsAddedByAutoUpgrade"; 399 private static final String XML_TAG_IS_MOST_RECENTLY_CONNECTED = "IsMostRecentlyConnected"; 400 private static final String XML_TAG_IS_RESTRICTED = "IsRestricted"; 401 private static final String XML_TAG_SUBSCRIPTION_GROUP = "SubscriptionGroup"; 402 public static final String XML_TAG_BSSID_ALLOW_LIST = "bssidAllowList"; 403 public static final String XML_TAG_IS_REPEATER_ENABLED = "RepeaterEnabled"; 404 public static final String XML_TAG_DPP_PRIVATE_EC_KEY = "DppPrivateEcKey"; 405 public static final String XML_TAG_DPP_CONNECTOR = "DppConnector"; 406 public static final String XML_TAG_DPP_CSIGN_KEY = "DppCSignKey"; 407 public static final String XML_TAG_DPP_NET_ACCESS_KEY = "DppNetAccessKey"; 408 public static final String XML_TAG_ENABLE_WIFI7 = "EnableWifi7"; 409 410 /** 411 * Write Wep Keys to the XML stream. 412 * WepKeys array is initialized in WifiConfiguration constructor and all the elements 413 * are set to null. User may choose to set any one of the key elements in WifiConfiguration. 414 * XmlUtils serialization doesn't handle this array of nulls well . 415 * So, write empty strings if the keys are not initialized and null if all 416 * the elements are empty. 417 */ writeWepKeysToXml(XmlSerializer out, String[] wepKeys, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)418 private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys, 419 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 420 throws XmlPullParserException, IOException { 421 final int len = wepKeys == null ? 0 : wepKeys.length; 422 String[] wepKeysToWrite = new String[len]; 423 boolean hasWepKey = false; 424 for (int i = 0; i < len; i++) { 425 if (wepKeys[i] == null) { 426 wepKeysToWrite[i] = new String(); 427 } else { 428 wepKeysToWrite[i] = wepKeys[i]; 429 hasWepKey = true; 430 } 431 } 432 if (!hasWepKey) { 433 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null); 434 return; 435 } 436 if (encryptionUtil == null) { 437 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite); 438 return; 439 } 440 EncryptedData[] encryptedDataArray = new EncryptedData[len]; 441 for (int i = 0; i < len; i++) { 442 if (wepKeys[i] == null) { 443 encryptedDataArray[i] = new EncryptedData(new byte[0], new byte[0]); 444 } else { 445 encryptedDataArray[i] = encryptionUtil.encrypt(wepKeys[i].getBytes()); 446 if (encryptedDataArray[i] == null) { 447 // We silently fail encryption failures! 448 Log.wtf(TAG, "Encryption of WEP keys failed"); 449 // If any key encryption fails, we just fall back with unencrypted keys. 450 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite); 451 return; 452 } 453 } 454 } 455 XmlUtil.writeNextSectionStart(out, XML_TAG_WEP_KEYS); 456 for (int i = 0; i < len; i++) { 457 XmlUtil.EncryptedDataXmlUtil.writeToXml(out, encryptedDataArray[i]); 458 } 459 XmlUtil.writeNextSectionEnd(out, XML_TAG_WEP_KEYS); 460 } 461 462 /** 463 * Write preshared key to the XML stream. 464 * 465 * If encryptionUtil is null or if encryption fails for some reason, the pre-shared 466 * key is stored in plaintext, else the encrypted psk is stored. 467 */ writePreSharedKeyToXml( XmlSerializer out, WifiConfiguration wifiConfig, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)468 private static void writePreSharedKeyToXml( 469 XmlSerializer out, WifiConfiguration wifiConfig, 470 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 471 throws XmlPullParserException, IOException { 472 EncryptedData encryptedData = null; 473 if (encryptionUtil != null && wifiConfig.preSharedKey != null) { 474 if (wifiConfig.hasEncryptedPreSharedKey() && !wifiConfig.hasPreSharedKeyChanged()) { 475 encryptedData = new EncryptedData(wifiConfig.getEncryptedPreSharedKey(), 476 wifiConfig.getEncryptedPreSharedKeyIv()); 477 } else { 478 encryptedData = encryptionUtil.encrypt(wifiConfig.preSharedKey.getBytes()); 479 if (encryptedData == null) { 480 // We silently fail encryption failures! 481 Log.wtf(TAG, "Encryption of preSharedKey failed"); 482 } 483 } 484 } 485 if (encryptedData != null) { 486 writeNextSectionStart(out, XML_TAG_PRE_SHARED_KEY); 487 EncryptedDataXmlUtil.writeToXml(out, encryptedData); 488 wifiConfig.setEncryptedPreSharedKey(encryptedData.getEncryptedData(), 489 encryptedData.getIv()); 490 wifiConfig.setHasPreSharedKeyChanged(false); 491 writeNextSectionEnd(out, XML_TAG_PRE_SHARED_KEY); 492 } else { 493 writeNextValue(out, XML_TAG_PRE_SHARED_KEY, wifiConfig.preSharedKey); 494 } 495 } 496 writeSecurityParamsListToXml( XmlSerializer out, WifiConfiguration configuration)497 private static void writeSecurityParamsListToXml( 498 XmlSerializer out, WifiConfiguration configuration) 499 throws XmlPullParserException, IOException { 500 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS_LIST); 501 for (SecurityParams params: configuration.getSecurityParamsList()) { 502 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS); 503 XmlUtil.writeNextValue( 504 out, XML_TAG_SECURITY_TYPE, 505 params.getSecurityType()); 506 XmlUtil.writeNextValue( 507 out, XML_TAG_IS_ENABLED, 508 params.isEnabled()); 509 XmlUtil.writeNextValue( 510 out, XML_TAG_SAE_IS_H2E_ONLY_MODE, 511 params.isSaeH2eOnlyMode()); 512 XmlUtil.writeNextValue( 513 out, XML_TAG_SAE_IS_PK_ONLY_MODE, 514 params.isSaePkOnlyMode()); 515 XmlUtil.writeNextValue( 516 out, XML_TAG_IS_ADDED_BY_AUTO_UPGRADE, 517 params.isAddedByAutoUpgrade()); 518 XmlUtil.writeNextValue( 519 out, XML_TAG_ALLOWED_SUITE_B_CIPHERS, 520 params.getAllowedSuiteBCiphers().toByteArray()); 521 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS); 522 } 523 524 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS_LIST); 525 } 526 writeEncryptedBytesToXml( XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, String tag, byte[] data)527 private static void writeEncryptedBytesToXml( 528 XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, 529 String tag, byte[] data) 530 throws XmlPullParserException, IOException { 531 EncryptedData encryptedData = null; 532 if (encryptionUtil != null) { 533 encryptedData = encryptionUtil.encrypt(data); 534 if (encryptedData == null && data != null && data.length != 0) { 535 // We silently fail encryption failures! 536 Log.wtf(TAG, "Encryption of " + tag + " failed"); 537 } 538 } 539 if (encryptedData != null) { 540 XmlUtil.writeNextSectionStart(out, tag); 541 EncryptedDataXmlUtil.writeToXml(out, encryptedData); 542 XmlUtil.writeNextSectionEnd(out, tag); 543 } else { 544 XmlUtil.writeNextValue(out, tag, data); 545 } 546 } 547 548 /** 549 * Write dpp configuration and connection keys to the XML stream. 550 * 551 * If encryptionUtil is null or if encryption fails for some reason, the dpp 552 * keys are stored in plaintext, else the encrypted keys are stored. 553 */ writeDppConfigurationToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)554 private static void writeDppConfigurationToXml( 555 XmlSerializer out, WifiConfiguration configuration, 556 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 557 throws XmlPullParserException, IOException { 558 writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_PRIVATE_EC_KEY, 559 configuration.getDppPrivateEcKey()); 560 writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_CONNECTOR, 561 configuration.getDppConnector()); 562 writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_CSIGN_KEY, 563 configuration.getDppCSignKey()); 564 writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_NET_ACCESS_KEY, 565 configuration.getDppNetAccessKey()); 566 } 567 568 /** 569 * Write the Configuration data elements that are common for backup & config store to the 570 * XML stream. 571 * 572 * @param out XmlSerializer instance pointing to the XML stream. 573 * @param configuration WifiConfiguration object to be serialized. 574 * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. Backup/restore stores 575 * keys unencrypted. 576 */ writeCommonElementsToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)577 public static void writeCommonElementsToXml( 578 XmlSerializer out, WifiConfiguration configuration, 579 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 580 throws XmlPullParserException, IOException { 581 XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.getKey()); 582 XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID); 583 writePreSharedKeyToXml(out, configuration, encryptionUtil); 584 writeWepKeysToXml(out, configuration.wepKeys, encryptionUtil); 585 XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex); 586 XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID); 587 XmlUtil.writeNextValue(out, XML_TAG_REQUIRE_PMF, configuration.requirePmf); 588 XmlUtil.writeNextValue( 589 out, XML_TAG_ALLOWED_KEY_MGMT, 590 configuration.allowedKeyManagement.toByteArray()); 591 XmlUtil.writeNextValue( 592 out, XML_TAG_ALLOWED_PROTOCOLS, 593 configuration.allowedProtocols.toByteArray()); 594 XmlUtil.writeNextValue( 595 out, XML_TAG_ALLOWED_AUTH_ALGOS, 596 configuration.allowedAuthAlgorithms.toByteArray()); 597 XmlUtil.writeNextValue( 598 out, XML_TAG_ALLOWED_GROUP_CIPHERS, 599 configuration.allowedGroupCiphers.toByteArray()); 600 XmlUtil.writeNextValue( 601 out, XML_TAG_ALLOWED_PAIRWISE_CIPHERS, 602 configuration.allowedPairwiseCiphers.toByteArray()); 603 XmlUtil.writeNextValue( 604 out, XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS, 605 configuration.allowedGroupManagementCiphers.toByteArray()); 606 XmlUtil.writeNextValue( 607 out, XML_TAG_ALLOWED_SUITE_B_CIPHERS, 608 configuration.allowedSuiteBCiphers.toByteArray()); 609 XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared); 610 XmlUtil.writeNextValue(out, XML_TAG_IS_AUTO_JOIN, configuration.allowAutojoin); 611 XmlUtil.writeNextValue(out, XML_TAG_PRIORITY, configuration.priority); 612 XmlUtil.writeNextValue( 613 out, XML_TAG_DELETION_PRIORITY, 614 configuration.getDeletionPriority()); 615 XmlUtil.writeNextValue( 616 out, XML_TAG_NUM_REBOOTS_SINCE_LAST_USE, 617 configuration.numRebootsSinceLastUse); 618 XmlUtil.writeNextValue(out, XML_TAG_IS_REPEATER_ENABLED, 619 configuration.isRepeaterEnabled()); 620 XmlUtil.writeNextValue(out, XML_TAG_ENABLE_WIFI7, configuration.isWifi7Enabled()); 621 writeSecurityParamsListToXml(out, configuration); 622 XmlUtil.writeNextValue(out, XML_TAG_SEND_DHCP_HOSTNAME, 623 configuration.isSendDhcpHostnameEnabled()); 624 } 625 626 /** 627 * Write the Configuration data elements for backup from the provided Configuration to the 628 * XML stream. 629 * Note: This is a subset of the elements serialized for config store. 630 * 631 * @param out XmlSerializer instance pointing to the XML stream. 632 * @param configuration WifiConfiguration object to be serialized. 633 */ writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)634 public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration) 635 throws XmlPullParserException, IOException { 636 writeCommonElementsToXml(out, configuration, null); 637 XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride); 638 } 639 640 /** 641 * Write the Configuration data elements for config store from the provided Configuration 642 * to the XML stream. 643 * 644 * @param out XmlSerializer instance pointing to the XML stream. 645 * @param configuration WifiConfiguration object to be serialized. 646 * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. 647 */ writeToXmlForConfigStore( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)648 public static void writeToXmlForConfigStore( 649 XmlSerializer out, WifiConfiguration configuration, 650 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 651 throws XmlPullParserException, IOException { 652 writeCommonElementsToXml(out, configuration, encryptionUtil); 653 XmlUtil.writeNextValue(out, XML_TAG_IS_TRUSTED, configuration.trusted); 654 XmlUtil.writeNextValue(out, XML_TAG_IS_RESTRICTED, configuration.restricted); 655 XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PAID, configuration.oemPaid); 656 XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PRIVATE, configuration.oemPrivate); 657 XmlUtil.writeNextValue(out, XML_TAG_IS_CARRIER_MERGED, 658 configuration.carrierMerged); 659 XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID); 660 XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status); 661 XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN); 662 XmlUtil.writeNextValue( 663 out, XML_TAG_PROVIDER_FRIENDLY_NAME, configuration.providerFriendlyName); 664 XmlUtil.writeNextValue( 665 out, XML_TAG_LINKED_NETWORKS_LIST, configuration.linkedConfigurations); 666 XmlUtil.writeNextValue( 667 out, XML_TAG_DEFAULT_GW_MAC_ADDRESS, configuration.defaultGwMacAddress); 668 XmlUtil.writeNextValue( 669 out, XML_TAG_VALIDATED_INTERNET_ACCESS, configuration.validatedInternetAccess); 670 XmlUtil.writeNextValue( 671 out, XML_TAG_NO_INTERNET_ACCESS_EXPECTED, 672 configuration.noInternetAccessExpected); 673 XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint); 674 XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride); 675 XmlUtil.writeNextValue( 676 out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores); 677 XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid); 678 XmlUtil.writeNextValue(out, XML_TAG_CREATOR_NAME, configuration.creatorName); 679 XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_UID, configuration.lastUpdateUid); 680 XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_NAME, configuration.lastUpdateName); 681 XmlUtil.writeNextValue(out, XML_TAG_LAST_CONNECT_UID, configuration.lastConnectUid); 682 XmlUtil.writeNextValue( 683 out, XML_TAG_IS_LEGACY_PASSPOINT_CONFIG, 684 configuration.isLegacyPasspointConfig); 685 XmlUtil.writeNextValue( 686 out, XML_TAG_ROAMING_CONSORTIUM_OIS, configuration.roamingConsortiumIds); 687 XmlUtil.writeNextValue(out, XML_TAG_RANDOMIZED_MAC_ADDRESS, 688 configuration.getRandomizedMacAddress().toString()); 689 XmlUtil.writeNextValue(out, XML_TAG_MAC_RANDOMIZATION_SETTING, 690 configuration.macRandomizationSetting); 691 XmlUtil.writeNextValue(out, XML_TAG_CARRIER_ID, configuration.carrierId); 692 XmlUtil.writeNextValue(out, XML_TAG_IS_MOST_RECENTLY_CONNECTED, 693 configuration.isMostRecentlyConnected); 694 XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_ID, configuration.subscriptionId); 695 if (configuration.getSubscriptionGroup() != null) { 696 XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_GROUP, 697 configuration.getSubscriptionGroup().toString()); 698 } 699 if (configuration.getBssidAllowlistInternal() != null) { 700 XmlUtil.writeNextValue(out, XML_TAG_BSSID_ALLOW_LIST, 701 covertMacAddressListToStringList(configuration 702 .getBssidAllowlistInternal())); 703 } 704 writeDppConfigurationToXml(out, configuration, encryptionUtil); 705 if (SdkLevel.isAtLeastV()) { 706 writeVendorDataListToXml(out, configuration.getVendorData()); 707 } 708 } 709 covertMacAddressListToStringList(List<MacAddress> macList)710 private static List<String> covertMacAddressListToStringList(List<MacAddress> macList) { 711 List<String> bssidList = new ArrayList<>(); 712 for (MacAddress address : macList) { 713 bssidList.add(address.toString()); 714 } 715 return bssidList; 716 } 717 covertStringListToMacAddressList(List<String> stringList)718 private static List<MacAddress> covertStringListToMacAddressList(List<String> stringList) { 719 List<MacAddress> macAddressList = new ArrayList<>(); 720 for (String address : stringList) { 721 try { 722 macAddressList.add(MacAddress.fromString(address)); 723 } catch (Exception e) { 724 Log.e(TAG, "Invalid BSSID String: " + address); 725 } 726 } 727 return macAddressList; 728 } 729 730 /** 731 * Populate wepKeys array elements only if they were non-empty in the backup data. 732 * 733 * @throws XmlPullParserException if parsing errors occur. 734 */ populateWepKeysFromXmlValue(Object value, String[] wepKeys)735 private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys) 736 throws XmlPullParserException, IOException { 737 String[] wepKeysInData = (String[]) value; 738 if (wepKeysInData == null) { 739 return; 740 } 741 if (wepKeysInData.length != wepKeys.length) { 742 throw new XmlPullParserException( 743 "Invalid Wep Keys length: " + wepKeysInData.length); 744 } 745 for (int i = 0; i < wepKeys.length; i++) { 746 if (wepKeysInData[i].isEmpty()) { 747 wepKeys[i] = null; 748 } else { 749 wepKeys[i] = wepKeysInData[i]; 750 } 751 } 752 } 753 populateWepKeysFromXmlValue(XmlPullParser in, int outerTagDepth, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil)754 private static String[] populateWepKeysFromXmlValue(XmlPullParser in, 755 int outerTagDepth, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) 756 throws XmlPullParserException, IOException { 757 List<String> wepKeyList = new ArrayList<>(); 758 final List<EncryptedData> encryptedDataList = 759 XmlUtil.EncryptedDataXmlUtil.parseListFromXml(in, outerTagDepth); 760 EncryptedData emptyData = new EncryptedData(new byte[0], new byte[0]); 761 for (int i = 0; i < encryptedDataList.size(); i++) { 762 if (encryptedDataList.get(i).equals(emptyData)) { 763 wepKeyList.add(null); 764 continue; 765 } 766 byte[] passphraseBytes = encryptionUtil.decrypt(encryptedDataList.get(i)); 767 if (passphraseBytes == null) { 768 Log.wtf(TAG, "Decryption of passphraseBytes failed"); 769 } else { 770 wepKeyList.add(new String(passphraseBytes, StandardCharsets.UTF_8)); 771 } 772 } 773 return wepKeyList.size() > 0 ? wepKeyList.toArray( 774 new String[wepKeyList.size()]) : null; 775 } 776 parseSecurityParamsFromXml( XmlPullParser in, int outerTagDepth)777 private static SecurityParams parseSecurityParamsFromXml( 778 XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { 779 SecurityParams params = null; 780 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 781 String[] valueName = new String[1]; 782 Object value = XmlUtil.readCurrentValue(in, valueName); 783 String tagName = valueName[0]; 784 if (tagName == null) { 785 throw new XmlPullParserException("Missing value name"); 786 } 787 switch (tagName) { 788 case WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE: 789 params = SecurityParams.createSecurityParamsBySecurityType((int) value); 790 break; 791 case WifiConfigurationXmlUtil.XML_TAG_IS_ENABLED: 792 params.setEnabled((boolean) value); 793 break; 794 case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_H2E_ONLY_MODE: 795 if (null == params) { 796 throw new XmlPullParserException("Missing security type."); 797 } 798 params.enableSaeH2eOnlyMode((boolean) value); 799 break; 800 case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_PK_ONLY_MODE: 801 if (null == params) { 802 throw new XmlPullParserException("Missing security type."); 803 } 804 params.enableSaePkOnlyMode((boolean) value); 805 break; 806 case WifiConfigurationXmlUtil.XML_TAG_IS_ADDED_BY_AUTO_UPGRADE: 807 if (null == params) { 808 throw new XmlPullParserException("Missing security type."); 809 } 810 params.setIsAddedByAutoUpgrade((boolean) value); 811 break; 812 case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_SUITE_B_CIPHERS: 813 if (null == params) { 814 throw new XmlPullParserException("Missing security type."); 815 } 816 byte[] suiteBCiphers = (byte[]) value; 817 BitSet suiteBCiphersBitSet = BitSet.valueOf(suiteBCiphers); 818 params.enableSuiteBCiphers( 819 suiteBCiphersBitSet.get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA), 820 suiteBCiphersBitSet.get(WifiConfiguration.SuiteBCipher.ECDHE_RSA)); 821 break; 822 } 823 } 824 return params; 825 } 826 readEncrytepdBytesFromXml( @ullable WifiConfigStoreEncryptionUtil encryptionUtil, XmlPullParser in, int outerTagDepth)827 private static byte[] readEncrytepdBytesFromXml( 828 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, 829 XmlPullParser in, int outerTagDepth) 830 throws XmlPullParserException, IOException { 831 if (encryptionUtil == null) { 832 throw new XmlPullParserException( 833 "Encrypted preSharedKey section not expected"); 834 } 835 EncryptedData encryptedData = 836 EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); 837 return encryptionUtil.decrypt(encryptedData); 838 } 839 parseSecurityParamsListFromXml( XmlPullParser in, int outerTagDepth, WifiConfiguration configuration)840 private static void parseSecurityParamsListFromXml( 841 XmlPullParser in, int outerTagDepth, 842 WifiConfiguration configuration) 843 throws XmlPullParserException, IOException { 844 List<SecurityParams> paramsList = new ArrayList<>(); 845 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 846 switch (in.getName()) { 847 case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS: 848 SecurityParams params = parseSecurityParamsFromXml(in, outerTagDepth + 1); 849 if (params != null) { 850 paramsList.add(params); 851 } 852 break; 853 } 854 } 855 if (!paramsList.isEmpty()) { 856 configuration.setSecurityParams(paramsList); 857 } 858 } 859 860 /** 861 * Parses the configuration data elements from the provided XML stream to a 862 * WifiConfiguration object. 863 * Note: This is used for parsing both backup data and config store data. Looping through 864 * the tags make it easy to add or remove elements in the future versions if needed. 865 * 866 * @param in XmlPullParser instance pointing to the XML stream. 867 * @param outerTagDepth depth of the outer tag in the XML document. 868 * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not. 869 * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. 870 * @param fromSuggestion Is this WifiConfiguration created from a WifiNetworkSuggestion. 871 * @return Pair<Config key, WifiConfiguration object> if parsing is successful, 872 * null otherwise. 873 */ parseFromXml( XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)874 public static Pair<String, WifiConfiguration> parseFromXml( 875 XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, 876 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion) 877 throws XmlPullParserException, IOException { 878 WifiConfiguration configuration = new WifiConfiguration(); 879 String configKeyInData = null; 880 boolean macRandomizationSettingExists = false; 881 boolean sendDhcpHostnameExists = false; 882 byte[] dppConnector = null; 883 byte[] dppCSign = null; 884 byte[] dppNetAccessKey = null; 885 886 // Loop through and parse out all the elements from the stream within this section. 887 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 888 if (in.getAttributeValue(null, "name") != null) { 889 // Value elements. 890 String[] valueName = new String[1]; 891 Object value = XmlUtil.readCurrentValue(in, valueName); 892 if (valueName[0] == null) { 893 throw new XmlPullParserException("Missing value name"); 894 } 895 switch (valueName[0]) { 896 case XML_TAG_CONFIG_KEY: 897 configKeyInData = (String) value; 898 break; 899 case XML_TAG_SSID: 900 configuration.SSID = (String) value; 901 break; 902 case XML_TAG_BSSID: 903 configuration.BSSID = (String) value; 904 break; 905 case XML_TAG_PRE_SHARED_KEY: 906 configuration.preSharedKey = (String) value; 907 break; 908 case XML_TAG_WEP_KEYS: 909 populateWepKeysFromXmlValue(value, configuration.wepKeys); 910 break; 911 case XML_TAG_WEP_TX_KEY_INDEX: 912 configuration.wepTxKeyIndex = (int) value; 913 break; 914 case XML_TAG_HIDDEN_SSID: 915 configuration.hiddenSSID = (boolean) value; 916 break; 917 case XML_TAG_REQUIRE_PMF: 918 configuration.requirePmf = (boolean) value; 919 break; 920 case XML_TAG_ALLOWED_KEY_MGMT: 921 byte[] allowedKeyMgmt = (byte[]) value; 922 configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); 923 break; 924 case XML_TAG_ALLOWED_PROTOCOLS: 925 byte[] allowedProtocols = (byte[]) value; 926 configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); 927 break; 928 case XML_TAG_ALLOWED_AUTH_ALGOS: 929 byte[] allowedAuthAlgorithms = (byte[]) value; 930 configuration.allowedAuthAlgorithms = BitSet.valueOf( 931 allowedAuthAlgorithms); 932 break; 933 case XML_TAG_ALLOWED_GROUP_CIPHERS: 934 byte[] allowedGroupCiphers = (byte[]) value; 935 configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers); 936 break; 937 case XML_TAG_ALLOWED_PAIRWISE_CIPHERS: 938 byte[] allowedPairwiseCiphers = (byte[]) value; 939 configuration.allowedPairwiseCiphers = 940 BitSet.valueOf(allowedPairwiseCiphers); 941 break; 942 case XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS: 943 byte[] allowedGroupMgmtCiphers = (byte[]) value; 944 configuration.allowedGroupManagementCiphers = 945 BitSet.valueOf(allowedGroupMgmtCiphers); 946 break; 947 case XML_TAG_ALLOWED_SUITE_B_CIPHERS: 948 byte[] allowedSuiteBCiphers = (byte[]) value; 949 configuration.allowedSuiteBCiphers = 950 BitSet.valueOf(allowedSuiteBCiphers); 951 break; 952 case XML_TAG_SHARED: 953 configuration.shared = (boolean) value; 954 break; 955 case XML_TAG_STATUS: 956 int status = (int) value; 957 // Any network which was CURRENT before reboot needs 958 // to be restored to ENABLED. 959 if (status == WifiConfiguration.Status.CURRENT) { 960 status = WifiConfiguration.Status.ENABLED; 961 } 962 configuration.status = status; 963 break; 964 case XML_TAG_FQDN: 965 configuration.FQDN = (String) value; 966 break; 967 case XML_TAG_PROVIDER_FRIENDLY_NAME: 968 configuration.providerFriendlyName = (String) value; 969 break; 970 case XML_TAG_LINKED_NETWORKS_LIST: 971 configuration.linkedConfigurations = (HashMap<String, Integer>) value; 972 break; 973 case XML_TAG_DEFAULT_GW_MAC_ADDRESS: 974 configuration.defaultGwMacAddress = (String) value; 975 break; 976 case XML_TAG_VALIDATED_INTERNET_ACCESS: 977 configuration.validatedInternetAccess = (boolean) value; 978 break; 979 case XML_TAG_NO_INTERNET_ACCESS_EXPECTED: 980 configuration.noInternetAccessExpected = (boolean) value; 981 break; 982 case XML_TAG_METERED_HINT: 983 configuration.meteredHint = (boolean) value; 984 break; 985 case XML_TAG_METERED_OVERRIDE: 986 configuration.meteredOverride = (int) value; 987 break; 988 case XML_TAG_USE_EXTERNAL_SCORES: 989 configuration.useExternalScores = (boolean) value; 990 break; 991 case XML_TAG_CREATOR_UID: 992 configuration.creatorUid = (int) value; 993 break; 994 case XML_TAG_CREATOR_NAME: 995 configuration.creatorName = (String) value; 996 break; 997 case XML_TAG_LAST_UPDATE_UID: 998 configuration.lastUpdateUid = (int) value; 999 break; 1000 case XML_TAG_LAST_UPDATE_NAME: 1001 configuration.lastUpdateName = (String) value; 1002 break; 1003 case XML_TAG_LAST_CONNECT_UID: 1004 configuration.lastConnectUid = (int) value; 1005 break; 1006 case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG: 1007 configuration.isLegacyPasspointConfig = (boolean) value; 1008 break; 1009 case XML_TAG_ROAMING_CONSORTIUM_OIS: 1010 configuration.roamingConsortiumIds = (long[]) value; 1011 break; 1012 case XML_TAG_RANDOMIZED_MAC_ADDRESS: 1013 configuration.setRandomizedMacAddress( 1014 MacAddress.fromString((String) value)); 1015 break; 1016 case XML_TAG_MAC_RANDOMIZATION_SETTING: 1017 configuration.macRandomizationSetting = (int) value; 1018 macRandomizationSettingExists = true; 1019 break; 1020 case XML_TAG_SEND_DHCP_HOSTNAME: 1021 configuration.setSendDhcpHostnameEnabled((boolean) value); 1022 sendDhcpHostnameExists = true; 1023 break; 1024 case XML_TAG_CARRIER_ID: 1025 configuration.carrierId = (int) value; 1026 break; 1027 case XML_TAG_SUBSCRIPTION_ID: 1028 configuration.subscriptionId = (int) value; 1029 break; 1030 case XML_TAG_IS_AUTO_JOIN: 1031 configuration.allowAutojoin = (boolean) value; 1032 break; 1033 case XML_TAG_PRIORITY: 1034 configuration.priority = (int) value; 1035 break; 1036 case XML_TAG_DELETION_PRIORITY: 1037 configuration.setDeletionPriority((int) value); 1038 break; 1039 case XML_TAG_NUM_REBOOTS_SINCE_LAST_USE: 1040 configuration.numRebootsSinceLastUse = (int) value; 1041 break; 1042 case XML_TAG_IS_TRUSTED: 1043 configuration.trusted = (boolean) value; 1044 break; 1045 case XML_TAG_IS_OEM_PAID: 1046 configuration.oemPaid = (boolean) value; 1047 break; 1048 case XML_TAG_IS_OEM_PRIVATE: 1049 configuration.oemPrivate = (boolean) value; 1050 break; 1051 case XML_TAG_IS_MOST_RECENTLY_CONNECTED: 1052 configuration.isMostRecentlyConnected = (boolean) value; 1053 break; 1054 case XML_TAG_IS_CARRIER_MERGED: 1055 configuration.carrierMerged = (boolean) value; 1056 break; 1057 case XML_TAG_IS_RESTRICTED: 1058 configuration.restricted = (boolean) value; 1059 break; 1060 case XML_TAG_SUBSCRIPTION_GROUP: 1061 configuration.setSubscriptionGroup( 1062 ParcelUuid.fromString((String) value)); 1063 break; 1064 case XML_TAG_BSSID_ALLOW_LIST: 1065 configuration.setBssidAllowlist( 1066 covertStringListToMacAddressList((List<String>) value)); 1067 break; 1068 case XML_TAG_IS_REPEATER_ENABLED: 1069 configuration.setRepeaterEnabled((boolean) value); 1070 break; 1071 case XML_TAG_DPP_PRIVATE_EC_KEY: 1072 configuration.setDppConfigurator((byte[]) value); 1073 break; 1074 case XML_TAG_DPP_CONNECTOR: 1075 dppConnector = (byte[]) value; 1076 break; 1077 case XML_TAG_DPP_CSIGN_KEY: 1078 dppCSign = (byte[]) value; 1079 break; 1080 case XML_TAG_DPP_NET_ACCESS_KEY: 1081 dppNetAccessKey = (byte[]) value; 1082 break; 1083 case XML_TAG_ENABLE_WIFI7: 1084 configuration.setWifi7Enabled((boolean) value); 1085 break; 1086 default: 1087 Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); 1088 break; 1089 } 1090 } else { 1091 String tagName = in.getName(); 1092 if (tagName == null) { 1093 throw new XmlPullParserException("Unexpected null tag found"); 1094 } 1095 switch (tagName) { 1096 case XML_TAG_PRE_SHARED_KEY: 1097 if (!shouldExpectEncryptedCredentials || encryptionUtil == null) { 1098 throw new XmlPullParserException( 1099 "Encrypted preSharedKey section not expected"); 1100 } 1101 EncryptedData encryptedData = 1102 EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); 1103 byte[] preSharedKeyBytes = encryptionUtil.decrypt(encryptedData); 1104 if (preSharedKeyBytes == null) { 1105 Log.wtf(TAG, "Decryption of preSharedKey failed"); 1106 } else { 1107 configuration.preSharedKey = new String(preSharedKeyBytes); 1108 configuration.setEncryptedPreSharedKey( 1109 encryptedData.getEncryptedData(), 1110 encryptedData.getIv()); 1111 } 1112 break; 1113 case XML_TAG_WEP_KEYS: 1114 if (!shouldExpectEncryptedCredentials || encryptionUtil == null) { 1115 throw new XmlPullParserException( 1116 "Encrypted wepKeys section not expected"); 1117 } 1118 configuration.wepKeys = populateWepKeysFromXmlValue(in, 1119 outerTagDepth + 1, encryptionUtil); 1120 break; 1121 case XML_TAG_SECURITY_PARAMS_LIST: 1122 parseSecurityParamsListFromXml(in, outerTagDepth + 1, configuration); 1123 break; 1124 case XML_TAG_DPP_PRIVATE_EC_KEY: 1125 configuration.setDppConfigurator(readEncrytepdBytesFromXml( 1126 encryptionUtil, in, outerTagDepth)); 1127 break; 1128 case XML_TAG_DPP_CONNECTOR: 1129 dppConnector = readEncrytepdBytesFromXml(encryptionUtil, in, 1130 outerTagDepth); 1131 break; 1132 case XML_TAG_DPP_CSIGN_KEY: 1133 dppCSign = readEncrytepdBytesFromXml(encryptionUtil, in, 1134 outerTagDepth); 1135 break; 1136 case XML_TAG_DPP_NET_ACCESS_KEY: 1137 dppNetAccessKey = readEncrytepdBytesFromXml(encryptionUtil, in, 1138 outerTagDepth); 1139 break; 1140 case XML_TAG_VENDOR_DATA_LIST: 1141 if (SdkLevel.isAtLeastV()) { 1142 configuration.setVendorData( 1143 parseVendorDataListFromXml(in, outerTagDepth + 1)); 1144 } 1145 break; 1146 default: 1147 Log.w(TAG, "Ignoring unknown tag found: " + tagName); 1148 break; 1149 } 1150 } 1151 } 1152 if (!macRandomizationSettingExists) { 1153 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; 1154 } 1155 if (configuration.macRandomizationSetting 1156 == WifiConfiguration.RANDOMIZATION_PERSISTENT && !fromSuggestion) { 1157 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO; 1158 } 1159 if (!sendDhcpHostnameExists) { 1160 // Update legacy configs to send the DHCP hostname for secure networks only. 1161 configuration.setSendDhcpHostnameEnabled( 1162 !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN) 1163 && !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE)); 1164 } 1165 configuration.convertLegacyFieldsToSecurityParamsIfNeeded(); 1166 configuration.setDppConnectionKeys(dppConnector, dppCSign, dppNetAccessKey); 1167 return Pair.create(configKeyInData, configuration); 1168 } 1169 } 1170 1171 /** 1172 * Utility class to serialize and deseriaize {@link IpConfiguration} object to XML & vice versa. 1173 * This is used by both {@link com.android.server.wifi.WifiConfigStore} & 1174 * {@link com.android.server.wifi.WifiBackupRestore} modules. 1175 */ 1176 public static class IpConfigurationXmlUtil { 1177 1178 /** 1179 * List of XML tags corresponding to IpConfiguration object elements. 1180 */ 1181 public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment"; 1182 public static final String XML_TAG_LINK_ADDRESS = "LinkAddress"; 1183 public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength"; 1184 public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress"; 1185 public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers"; 1186 public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings"; 1187 public static final String XML_TAG_PROXY_HOST = "ProxyHost"; 1188 public static final String XML_TAG_PROXY_PORT = "ProxyPort"; 1189 public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac"; 1190 public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList"; 1191 parseProxyExclusionListString( @ullable String exclusionListString)1192 private static List<String> parseProxyExclusionListString( 1193 @Nullable String exclusionListString) { 1194 if (exclusionListString == null) { 1195 return Collections.emptyList(); 1196 } else { 1197 return Arrays.asList(exclusionListString.toLowerCase(Locale.ROOT).split(",")); 1198 } 1199 } 1200 generateProxyExclusionListString(@onNull String[] exclusionList)1201 private static String generateProxyExclusionListString(@NonNull String[] exclusionList) { 1202 return TextUtils.join(",", exclusionList); 1203 } 1204 1205 /** 1206 * Write the static IP configuration data elements to XML stream. 1207 */ writeStaticIpConfigurationToXml( XmlSerializer out, StaticIpConfiguration staticIpConfiguration)1208 private static void writeStaticIpConfigurationToXml( 1209 XmlSerializer out, StaticIpConfiguration staticIpConfiguration) 1210 throws XmlPullParserException, IOException { 1211 if (staticIpConfiguration.getIpAddress() != null) { 1212 XmlUtil.writeNextValue( 1213 out, XML_TAG_LINK_ADDRESS, 1214 staticIpConfiguration.getIpAddress().getAddress().getHostAddress()); 1215 XmlUtil.writeNextValue( 1216 out, XML_TAG_LINK_PREFIX_LENGTH, 1217 staticIpConfiguration.getIpAddress().getPrefixLength()); 1218 } else { 1219 XmlUtil.writeNextValue( 1220 out, XML_TAG_LINK_ADDRESS, null); 1221 XmlUtil.writeNextValue( 1222 out, XML_TAG_LINK_PREFIX_LENGTH, null); 1223 } 1224 if (staticIpConfiguration.getGateway() != null) { 1225 XmlUtil.writeNextValue( 1226 out, XML_TAG_GATEWAY_ADDRESS, 1227 staticIpConfiguration.getGateway().getHostAddress()); 1228 } else { 1229 XmlUtil.writeNextValue( 1230 out, XML_TAG_GATEWAY_ADDRESS, null); 1231 1232 } 1233 // Create a string array of DNS server addresses 1234 String[] dnsServers = new String[staticIpConfiguration.getDnsServers().size()]; 1235 int dnsServerIdx = 0; 1236 for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) { 1237 dnsServers[dnsServerIdx++] = inetAddr.getHostAddress(); 1238 } 1239 XmlUtil.writeNextValue( 1240 out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers); 1241 } 1242 1243 /** 1244 * Write the IP configuration data elements from the provided Configuration to the XML 1245 * stream. 1246 * 1247 * @param out XmlSerializer instance pointing to the XML stream. 1248 * @param ipConfiguration IpConfiguration object to be serialized. 1249 */ writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)1250 public static void writeToXml(XmlSerializer out, IpConfiguration ipConfiguration) 1251 throws XmlPullParserException, IOException { 1252 // Write IP assignment settings 1253 XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT, 1254 ipConfiguration.getIpAssignment().toString()); 1255 switch (ipConfiguration.getIpAssignment()) { 1256 case STATIC: 1257 writeStaticIpConfigurationToXml( 1258 out, ipConfiguration.getStaticIpConfiguration()); 1259 break; 1260 case DHCP: 1261 case UNASSIGNED: 1262 break; 1263 default: 1264 Log.w(TAG, "Ignoring unknown ip assignment type: " 1265 + ipConfiguration.getIpAssignment()); 1266 break; 1267 } 1268 1269 // Write proxy settings 1270 XmlUtil.writeNextValue( 1271 out, XML_TAG_PROXY_SETTINGS, 1272 ipConfiguration.getProxySettings().toString()); 1273 switch (ipConfiguration.getProxySettings()) { 1274 case STATIC: 1275 XmlUtil.writeNextValue( 1276 out, XML_TAG_PROXY_HOST, 1277 ipConfiguration.getHttpProxy().getHost()); 1278 XmlUtil.writeNextValue( 1279 out, XML_TAG_PROXY_PORT, 1280 ipConfiguration.getHttpProxy().getPort()); 1281 XmlUtil.writeNextValue( 1282 out, XML_TAG_PROXY_EXCLUSION_LIST, 1283 generateProxyExclusionListString( 1284 ipConfiguration.getHttpProxy().getExclusionList())); 1285 break; 1286 case PAC: 1287 XmlUtil.writeNextValue( 1288 out, XML_TAG_PROXY_PAC_FILE, 1289 ipConfiguration.getHttpProxy().getPacFileUrl().toString()); 1290 break; 1291 case NONE: 1292 case UNASSIGNED: 1293 break; 1294 default: 1295 Log.w(TAG, "Ignoring unknown proxy settings type: " 1296 + ipConfiguration.getProxySettings()); 1297 break; 1298 } 1299 } 1300 1301 /** 1302 * Parse out the static IP configuration from the XML stream. 1303 */ parseStaticIpConfigurationFromXml(XmlPullParser in)1304 private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in) 1305 throws XmlPullParserException, IOException { 1306 StaticIpConfiguration.Builder builder = new StaticIpConfiguration.Builder(); 1307 1308 String linkAddressString = 1309 (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS); 1310 Integer linkPrefixLength = 1311 (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH); 1312 if (linkAddressString != null && linkPrefixLength != null) { 1313 LinkAddress linkAddress = new LinkAddress( 1314 InetAddresses.parseNumericAddress(linkAddressString), 1315 linkPrefixLength); 1316 if (linkAddress.getAddress() instanceof Inet4Address) { 1317 builder.setIpAddress(linkAddress); 1318 } else { 1319 Log.w(TAG, "Non-IPv4 address: " + linkAddress); 1320 } 1321 } 1322 String gatewayAddressString = 1323 (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS); 1324 if (gatewayAddressString != null) { 1325 InetAddress gateway = 1326 InetAddresses.parseNumericAddress(gatewayAddressString); 1327 RouteInfo route = new RouteInfo(null, gateway, null, RouteInfo.RTN_UNICAST); 1328 if (route.isDefaultRoute() 1329 && route.getDestination().getAddress() instanceof Inet4Address) { 1330 builder.setGateway(gateway); 1331 } else { 1332 Log.w(TAG, "Non-IPv4 default route: " + route); 1333 } 1334 } 1335 String[] dnsServerAddressesString = 1336 (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES); 1337 if (dnsServerAddressesString != null) { 1338 List<InetAddress> dnsServerAddresses = new ArrayList<>(); 1339 for (String dnsServerAddressString : dnsServerAddressesString) { 1340 InetAddress dnsServerAddress = 1341 InetAddresses.parseNumericAddress(dnsServerAddressString); 1342 dnsServerAddresses.add(dnsServerAddress); 1343 } 1344 builder.setDnsServers(dnsServerAddresses); 1345 } 1346 return builder.build(); 1347 } 1348 1349 /** 1350 * Parses the IP configuration data elements from the provided XML stream to an 1351 * IpConfiguration object. 1352 * 1353 * @param in XmlPullParser instance pointing to the XML stream. 1354 * @param outerTagDepth depth of the outer tag in the XML document. 1355 * @return IpConfiguration object if parsing is successful, null otherwise. 1356 */ parseFromXml(XmlPullParser in, int outerTagDepth)1357 public static IpConfiguration parseFromXml(XmlPullParser in, int outerTagDepth) 1358 throws XmlPullParserException, IOException { 1359 IpConfiguration ipConfiguration = new IpConfiguration(); 1360 1361 // Parse out the IP assignment info first. 1362 String ipAssignmentString = 1363 (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT); 1364 IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString); 1365 ipConfiguration.setIpAssignment(ipAssignment); 1366 switch (ipAssignment) { 1367 case STATIC: 1368 ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in)); 1369 break; 1370 case DHCP: 1371 case UNASSIGNED: 1372 break; 1373 default: 1374 Log.w(TAG, "Ignoring unknown ip assignment type: " + ipAssignment); 1375 break; 1376 } 1377 1378 // Parse out the proxy settings next. 1379 String proxySettingsString = 1380 (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS); 1381 ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString); 1382 ipConfiguration.setProxySettings(proxySettings); 1383 switch (proxySettings) { 1384 case STATIC: 1385 String proxyHost = 1386 (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST); 1387 int proxyPort = 1388 (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT); 1389 String proxyExclusionList = 1390 (String) XmlUtil.readNextValueWithName( 1391 in, XML_TAG_PROXY_EXCLUSION_LIST); 1392 ipConfiguration.setHttpProxy( 1393 ProxyInfo.buildDirectProxy( 1394 proxyHost, proxyPort, 1395 parseProxyExclusionListString(proxyExclusionList))); 1396 break; 1397 case PAC: 1398 String proxyPacFile = 1399 (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE); 1400 ipConfiguration.setHttpProxy( 1401 ProxyInfo.buildPacProxy(Uri.parse(proxyPacFile))); 1402 break; 1403 case NONE: 1404 case UNASSIGNED: 1405 break; 1406 default: 1407 Log.w(TAG, "Ignoring unknown proxy settings type: " + proxySettings); 1408 break; 1409 } 1410 return ipConfiguration; 1411 } 1412 } 1413 1414 /** 1415 * Utility class to serialize and deserialize {@link NetworkSelectionStatus} object to XML & 1416 * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module. 1417 */ 1418 public static class NetworkSelectionStatusXmlUtil { 1419 1420 /** 1421 * List of XML tags corresponding to NetworkSelectionStatus object elements. 1422 */ 1423 public static final String XML_TAG_SELECTION_STATUS = "SelectionStatus"; 1424 public static final String XML_TAG_DISABLE_REASON = "DisableReason"; 1425 public static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice"; 1426 public static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected"; 1427 public static final String XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED = 1428 "CaptivePortalNeverDetected"; 1429 public static final String XML_TAG_HAS_EVER_VALIDATED_INTERNET_ACCESS = 1430 "HasEverValidatedInternetAccess"; 1431 public static final String XML_TAG_CONNECT_CHOICE_RSSI = "ConnectChoiceRssi"; 1432 1433 /** 1434 * Write the NetworkSelectionStatus data elements from the provided status to the XML 1435 * stream. 1436 * 1437 * @param out XmlSerializer instance pointing to the XML stream. 1438 * @param selectionStatus NetworkSelectionStatus object to be serialized. 1439 */ writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)1440 public static void writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus) 1441 throws XmlPullParserException, IOException { 1442 XmlUtil.writeNextValue( 1443 out, XML_TAG_SELECTION_STATUS, selectionStatus.getNetworkStatusString()); 1444 XmlUtil.writeNextValue( 1445 out, XML_TAG_DISABLE_REASON, 1446 selectionStatus.getNetworkSelectionDisableReasonString()); 1447 XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, selectionStatus.getConnectChoice()); 1448 XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE_RSSI, 1449 selectionStatus.getConnectChoiceRssi()); 1450 XmlUtil.writeNextValue( 1451 out, XML_TAG_HAS_EVER_CONNECTED, selectionStatus.hasEverConnected()); 1452 XmlUtil.writeNextValue(out, XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED, 1453 selectionStatus.hasNeverDetectedCaptivePortal()); 1454 XmlUtil.writeNextValue(out, XML_TAG_HAS_EVER_VALIDATED_INTERNET_ACCESS, 1455 selectionStatus.hasEverValidatedInternetAccess()); 1456 } 1457 1458 /** 1459 * Parses the NetworkSelectionStatus data elements from the provided XML stream to a 1460 * NetworkSelectionStatus object. 1461 * 1462 * @param in XmlPullParser instance pointing to the XML stream. 1463 * @param outerTagDepth depth of the outer tag in the XML document. 1464 * @return NetworkSelectionStatus object if parsing is successful, null otherwise. 1465 */ parseFromXml(XmlPullParser in, int outerTagDepth)1466 public static NetworkSelectionStatus parseFromXml(XmlPullParser in, int outerTagDepth) 1467 throws XmlPullParserException, IOException { 1468 NetworkSelectionStatus selectionStatus = new NetworkSelectionStatus(); 1469 String statusString = ""; 1470 String disableReasonString = ""; 1471 // Initialize hasNeverDetectedCaptivePortal to "false" for upgrading legacy configs 1472 // which do not have the XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED tag. 1473 selectionStatus.setHasNeverDetectedCaptivePortal(false); 1474 1475 // Initialize hasEverValidatedInternetAccess to "true" for existing configs which don't 1476 // have any value stored. 1477 selectionStatus.setHasEverValidatedInternetAccess(true); 1478 1479 // Loop through and parse out all the elements from the stream within this section. 1480 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 1481 String[] valueName = new String[1]; 1482 Object value = XmlUtil.readCurrentValue(in, valueName); 1483 if (valueName[0] == null) { 1484 throw new XmlPullParserException("Missing value name"); 1485 } 1486 switch (valueName[0]) { 1487 case XML_TAG_SELECTION_STATUS: 1488 statusString = (String) value; 1489 break; 1490 case XML_TAG_DISABLE_REASON: 1491 disableReasonString = (String) value; 1492 break; 1493 case XML_TAG_CONNECT_CHOICE: 1494 selectionStatus.setConnectChoice((String) value); 1495 break; 1496 case XML_TAG_CONNECT_CHOICE_RSSI: 1497 selectionStatus.setConnectChoiceRssi((int) value); 1498 break; 1499 case XML_TAG_HAS_EVER_CONNECTED: 1500 selectionStatus.setHasEverConnected((boolean) value); 1501 break; 1502 case XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED: 1503 selectionStatus.setHasNeverDetectedCaptivePortal((boolean) value); 1504 break; 1505 case XML_TAG_HAS_EVER_VALIDATED_INTERNET_ACCESS: 1506 selectionStatus.setHasEverValidatedInternetAccess((boolean) value); 1507 break; 1508 default: 1509 Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); 1510 break; 1511 } 1512 } 1513 // Now figure out the network selection status codes from |selectionStatusString| & 1514 // |disableReasonString|. 1515 int status = 1516 Arrays.asList(NetworkSelectionStatus.QUALITY_NETWORK_SELECTION_STATUS) 1517 .indexOf(statusString); 1518 int disableReason = 1519 NetworkSelectionStatus.getDisableReasonByString(disableReasonString); 1520 1521 // If either of the above codes are invalid or if the network was temporarily disabled 1522 // (blacklisted), restore the status as enabled. We don't want to persist blacklists 1523 // across reboots. 1524 if (status == -1 || disableReason == -1 || 1525 status == NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) { 1526 status = NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; 1527 disableReason = NetworkSelectionStatus.DISABLED_NONE; 1528 } 1529 selectionStatus.setNetworkSelectionStatus(status); 1530 selectionStatus.setNetworkSelectionDisableReason(disableReason); 1531 if (status == NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED) { 1532 // Make the counter non-zero so that logging code works properly 1533 selectionStatus.setDisableReasonCounter(disableReason, 1); 1534 } 1535 return selectionStatus; 1536 } 1537 } 1538 1539 /** 1540 * Utility class to serialize and deseriaize {@link WifiEnterpriseConfig} object to XML & 1541 * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module. 1542 */ 1543 public static class WifiEnterpriseConfigXmlUtil { 1544 1545 /** 1546 * List of XML tags corresponding to WifiEnterpriseConfig object elements. 1547 */ 1548 public static final String XML_TAG_IDENTITY = "Identity"; 1549 public static final String XML_TAG_ANON_IDENTITY = "AnonIdentity"; 1550 public static final String XML_TAG_PASSWORD = "Password"; 1551 public static final String XML_TAG_CLIENT_CERT = "ClientCert"; 1552 public static final String XML_TAG_CA_CERT = "CaCert"; 1553 public static final String XML_TAG_SUBJECT_MATCH = "SubjectMatch"; 1554 public static final String XML_TAG_ENGINE = "Engine"; 1555 public static final String XML_TAG_ENGINE_ID = "EngineId"; 1556 public static final String XML_TAG_PRIVATE_KEY_ID = "PrivateKeyId"; 1557 public static final String XML_TAG_ALT_SUBJECT_MATCH = "AltSubjectMatch"; 1558 public static final String XML_TAG_DOM_SUFFIX_MATCH = "DomSuffixMatch"; 1559 public static final String XML_TAG_CA_PATH = "CaPath"; 1560 public static final String XML_TAG_EAP_METHOD = "EapMethod"; 1561 public static final String XML_TAG_PHASE2_METHOD = "Phase2Method"; 1562 public static final String XML_TAG_PLMN = "PLMN"; 1563 public static final String XML_TAG_REALM = "Realm"; 1564 public static final String XML_TAG_OCSP = "Ocsp"; 1565 public static final String XML_TAG_WAPI_CERT_SUITE = "WapiCertSuite"; 1566 public static final String XML_TAG_APP_INSTALLED_ROOT_CA_CERT = "AppInstalledRootCaCert"; 1567 public static final String XML_TAG_APP_INSTALLED_PRIVATE_KEY = "AppInstalledPrivateKey"; 1568 public static final String XML_TAG_KEYCHAIN_KEY_ALIAS = "KeyChainAlias"; 1569 public static final String XML_TAG_DECORATED_IDENTITY_PREFIX = "DecoratedIdentityPrefix"; 1570 public static final String XML_TAG_TRUST_ON_FIRST_USE = "TrustOnFirstUse"; 1571 public static final String XML_TAG_USER_APPROVE_NO_CA_CERT = "UserApproveNoCaCert"; 1572 public static final String XML_TAG_MINIMUM_TLS_VERSION = "MinimumTlsVersion"; 1573 public static final String XML_TAG_TOFU_DIALOG_STATE = "TofuDialogState"; 1574 public static final String XML_TAG_TOFU_CONNECTION_STATE = "TofuConnectionState"; 1575 1576 /** 1577 * Write password key to the XML stream. 1578 * 1579 * If encryptionUtil is null or if encryption fails for some reason, the password is stored 1580 * in plaintext, else the encrypted psk is stored. 1581 */ writePasswordToXml( XmlSerializer out, String password, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1582 private static void writePasswordToXml( 1583 XmlSerializer out, String password, 1584 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 1585 throws XmlPullParserException, IOException { 1586 EncryptedData encryptedData = null; 1587 if (encryptionUtil != null) { 1588 if (password != null) { 1589 encryptedData = encryptionUtil.encrypt(password.getBytes()); 1590 if (encryptedData == null) { 1591 // We silently fail encryption failures! 1592 Log.wtf(TAG, "Encryption of password failed"); 1593 } 1594 } 1595 } 1596 if (encryptedData != null) { 1597 XmlUtil.writeNextSectionStart(out, XML_TAG_PASSWORD); 1598 EncryptedDataXmlUtil.writeToXml(out, encryptedData); 1599 XmlUtil.writeNextSectionEnd(out, XML_TAG_PASSWORD); 1600 } else { 1601 XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, password); 1602 } 1603 } 1604 1605 /** 1606 * Write the WifiEnterpriseConfig data elements from the provided config to the XML 1607 * stream. 1608 * 1609 * @param out XmlSerializer instance pointing to the XML stream. 1610 * @param enterpriseConfig WifiEnterpriseConfig object to be serialized. 1611 * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. 1612 */ writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1613 public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, 1614 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 1615 throws XmlPullParserException, IOException { 1616 XmlUtil.writeNextValue(out, XML_TAG_IDENTITY, 1617 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY)); 1618 XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY, 1619 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY)); 1620 writePasswordToXml( 1621 out, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY), 1622 encryptionUtil); 1623 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT, 1624 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY)); 1625 XmlUtil.writeNextValue(out, XML_TAG_CA_CERT, 1626 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY)); 1627 XmlUtil.writeNextValue(out, XML_TAG_SUBJECT_MATCH, 1628 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY)); 1629 XmlUtil.writeNextValue(out, XML_TAG_ENGINE, 1630 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY)); 1631 XmlUtil.writeNextValue(out, XML_TAG_ENGINE_ID, 1632 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY)); 1633 XmlUtil.writeNextValue(out, XML_TAG_PRIVATE_KEY_ID, 1634 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY)); 1635 XmlUtil.writeNextValue(out, XML_TAG_ALT_SUBJECT_MATCH, 1636 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY)); 1637 XmlUtil.writeNextValue(out, XML_TAG_DOM_SUFFIX_MATCH, 1638 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY)); 1639 XmlUtil.writeNextValue(out, XML_TAG_CA_PATH, 1640 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_PATH_KEY)); 1641 XmlUtil.writeNextValue(out, XML_TAG_EAP_METHOD, enterpriseConfig.getEapMethod()); 1642 XmlUtil.writeNextValue(out, XML_TAG_PHASE2_METHOD, enterpriseConfig.getPhase2Method()); 1643 XmlUtil.writeNextValue(out, XML_TAG_PLMN, enterpriseConfig.getPlmn()); 1644 XmlUtil.writeNextValue(out, XML_TAG_REALM, enterpriseConfig.getRealm()); 1645 XmlUtil.writeNextValue(out, XML_TAG_OCSP, enterpriseConfig.getOcsp()); 1646 XmlUtil.writeNextValue(out, 1647 XML_TAG_WAPI_CERT_SUITE, enterpriseConfig.getWapiCertSuite()); 1648 XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_ROOT_CA_CERT, 1649 enterpriseConfig.isAppInstalledCaCert()); 1650 XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_PRIVATE_KEY, 1651 enterpriseConfig.isAppInstalledDeviceKeyAndCert()); 1652 XmlUtil.writeNextValue(out, XML_TAG_KEYCHAIN_KEY_ALIAS, 1653 enterpriseConfig.getClientKeyPairAliasInternal()); 1654 if (SdkLevel.isAtLeastS()) { 1655 XmlUtil.writeNextValue(out, XML_TAG_DECORATED_IDENTITY_PREFIX, 1656 enterpriseConfig.getDecoratedIdentityPrefix()); 1657 } 1658 XmlUtil.writeNextValue(out, XML_TAG_TRUST_ON_FIRST_USE, 1659 enterpriseConfig.isTrustOnFirstUseEnabled()); 1660 XmlUtil.writeNextValue(out, XML_TAG_USER_APPROVE_NO_CA_CERT, 1661 enterpriseConfig.isUserApproveNoCaCert()); 1662 XmlUtil.writeNextValue(out, XML_TAG_MINIMUM_TLS_VERSION, 1663 enterpriseConfig.getMinimumTlsVersion()); 1664 XmlUtil.writeNextValue(out, XML_TAG_TOFU_DIALOG_STATE, 1665 enterpriseConfig.getTofuDialogState()); 1666 XmlUtil.writeNextValue(out, XML_TAG_TOFU_CONNECTION_STATE, 1667 enterpriseConfig.getTofuConnectionState()); 1668 } 1669 1670 /** 1671 * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object. 1672 * 1673 * @param in XmlPullParser instance pointing to the XML stream. 1674 * @param outerTagDepth depth of the outer tag in the XML document. 1675 * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not. 1676 * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. 1677 * @return WifiEnterpriseConfig object if parsing is successful, null otherwise. 1678 */ parseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1679 public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth, 1680 boolean shouldExpectEncryptedCredentials, 1681 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 1682 throws XmlPullParserException, IOException { 1683 WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); 1684 1685 // Loop through and parse out all the elements from the stream within this section. 1686 while (XmlUtilHelper.nextElementWithin(in, outerTagDepth)) { 1687 if (in.getAttributeValue(null, "name") != null) { 1688 // Value elements. 1689 String[] valueName = new String[1]; 1690 Object value = XmlUtil.readCurrentValue(in, valueName); 1691 if (valueName[0] == null) { 1692 throw new XmlPullParserException("Missing value name"); 1693 } 1694 switch (valueName[0]) { 1695 case XML_TAG_IDENTITY: 1696 enterpriseConfig.setFieldValue( 1697 WifiEnterpriseConfig.IDENTITY_KEY, (String) value); 1698 break; 1699 case XML_TAG_ANON_IDENTITY: 1700 enterpriseConfig.setFieldValue( 1701 WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value); 1702 break; 1703 case XML_TAG_PASSWORD: 1704 enterpriseConfig.setFieldValue( 1705 WifiEnterpriseConfig.PASSWORD_KEY, (String) value); 1706 if (shouldExpectEncryptedCredentials 1707 && !TextUtils.isEmpty(enterpriseConfig.getFieldValue( 1708 WifiEnterpriseConfig.PASSWORD_KEY))) { 1709 // Indicates that encryption of password failed when it was last 1710 // written. 1711 Log.e(TAG, "password value not expected"); 1712 } 1713 break; 1714 case XML_TAG_CLIENT_CERT: 1715 enterpriseConfig.setFieldValue( 1716 WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value); 1717 break; 1718 case XML_TAG_CA_CERT: 1719 enterpriseConfig.setFieldValue( 1720 WifiEnterpriseConfig.CA_CERT_KEY, (String) value); 1721 break; 1722 case XML_TAG_SUBJECT_MATCH: 1723 enterpriseConfig.setFieldValue( 1724 WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value); 1725 break; 1726 case XML_TAG_ENGINE: 1727 enterpriseConfig.setFieldValue( 1728 WifiEnterpriseConfig.ENGINE_KEY, (String) value); 1729 break; 1730 case XML_TAG_ENGINE_ID: 1731 enterpriseConfig.setFieldValue( 1732 WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value); 1733 break; 1734 case XML_TAG_PRIVATE_KEY_ID: 1735 enterpriseConfig.setFieldValue( 1736 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value); 1737 break; 1738 case XML_TAG_ALT_SUBJECT_MATCH: 1739 enterpriseConfig.setFieldValue( 1740 WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value); 1741 break; 1742 case XML_TAG_DOM_SUFFIX_MATCH: 1743 enterpriseConfig.setFieldValue( 1744 WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value); 1745 break; 1746 case XML_TAG_CA_PATH: 1747 enterpriseConfig.setFieldValue( 1748 WifiEnterpriseConfig.CA_PATH_KEY, (String) value); 1749 break; 1750 case XML_TAG_OCSP: 1751 enterpriseConfig.setOcsp((int) value); 1752 break; 1753 case XML_TAG_EAP_METHOD: 1754 enterpriseConfig.setEapMethod((int) value); 1755 break; 1756 case XML_TAG_PHASE2_METHOD: 1757 enterpriseConfig.setPhase2Method((int) value); 1758 break; 1759 case XML_TAG_PLMN: 1760 enterpriseConfig.setPlmn((String) value); 1761 break; 1762 case XML_TAG_REALM: 1763 enterpriseConfig.setRealm((String) value); 1764 break; 1765 case XML_TAG_WAPI_CERT_SUITE: 1766 enterpriseConfig.setWapiCertSuite((String) value); 1767 break; 1768 case XML_TAG_APP_INSTALLED_ROOT_CA_CERT: 1769 enterpriseConfig.initIsAppInstalledCaCert((boolean) value); 1770 break; 1771 case XML_TAG_APP_INSTALLED_PRIVATE_KEY: 1772 enterpriseConfig.initIsAppInstalledDeviceKeyAndCert((boolean) value); 1773 break; 1774 case XML_TAG_KEYCHAIN_KEY_ALIAS: 1775 if (SdkLevel.isAtLeastS()) { 1776 enterpriseConfig.setClientKeyPairAlias((String) value); 1777 } 1778 break; 1779 case XML_TAG_DECORATED_IDENTITY_PREFIX: 1780 if (SdkLevel.isAtLeastS()) { 1781 enterpriseConfig.setDecoratedIdentityPrefix((String) value); 1782 } 1783 break; 1784 case XML_TAG_TRUST_ON_FIRST_USE: 1785 enterpriseConfig.enableTrustOnFirstUse((boolean) value); 1786 break; 1787 case XML_TAG_USER_APPROVE_NO_CA_CERT: 1788 enterpriseConfig.setUserApproveNoCaCert((boolean) value); 1789 break; 1790 case XML_TAG_MINIMUM_TLS_VERSION: 1791 enterpriseConfig.setMinimumTlsVersion((int) value); 1792 break; 1793 case XML_TAG_TOFU_DIALOG_STATE: 1794 enterpriseConfig.setTofuDialogState((int) value); 1795 break; 1796 case XML_TAG_TOFU_CONNECTION_STATE: 1797 enterpriseConfig.setTofuConnectionState((int) value); 1798 break; 1799 default: 1800 Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); 1801 break; 1802 } 1803 } else { 1804 String tagName = in.getName(); 1805 if (tagName == null) { 1806 throw new XmlPullParserException("Unexpected null tag found"); 1807 } 1808 switch (tagName) { 1809 case XML_TAG_PASSWORD: 1810 if (!shouldExpectEncryptedCredentials || encryptionUtil == null) { 1811 throw new XmlPullParserException( 1812 "encrypted password section not expected"); 1813 } 1814 EncryptedData encryptedData = 1815 EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); 1816 byte[] passwordBytes = encryptionUtil.decrypt(encryptedData); 1817 if (passwordBytes == null) { 1818 Log.wtf(TAG, "Decryption of password failed"); 1819 } else { 1820 enterpriseConfig.setFieldValue( 1821 WifiEnterpriseConfig.PASSWORD_KEY, 1822 new String(passwordBytes)); 1823 } 1824 break; 1825 default: 1826 Log.w(TAG, "Ignoring unknown tag name found: " + tagName); 1827 break; 1828 } 1829 } 1830 } 1831 return enterpriseConfig; 1832 } 1833 } 1834 1835 /** 1836 * Utility class to serialize and deseriaize {@link EncryptedData} object to XML & 1837 * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module. 1838 */ 1839 public static class EncryptedDataXmlUtil { 1840 /** 1841 * List of XML tags corresponding to EncryptedData object elements. 1842 */ 1843 private static final String XML_TAG_ENCRYPTED_DATA = "EncryptedData"; 1844 private static final String XML_TAG_IV = "IV"; 1845 1846 /** 1847 * Write the NetworkSelectionStatus data elements from the provided status to the XML 1848 * stream. 1849 * 1850 * @param out XmlSerializer instance pointing to the XML stream. 1851 * @param encryptedData EncryptedData object to be serialized. 1852 */ writeToXml(XmlSerializer out, EncryptedData encryptedData)1853 public static void writeToXml(XmlSerializer out, EncryptedData encryptedData) 1854 throws XmlPullParserException, IOException { 1855 XmlUtil.writeNextValue( 1856 out, XML_TAG_ENCRYPTED_DATA, encryptedData.getEncryptedData()); 1857 XmlUtil.writeNextValue(out, XML_TAG_IV, encryptedData.getIv()); 1858 } 1859 1860 /** 1861 * Parses the EncryptedData data elements from the provided XML stream to a 1862 * EncryptedData object. 1863 * 1864 * @param in XmlPullParser instance pointing to the XML stream. 1865 * @param outerTagDepth depth of the outer tag in the XML document. 1866 * @return EncryptedData object if parsing is successful, null otherwise. 1867 */ parseFromXml(XmlPullParser in, int outerTagDepth)1868 public static EncryptedData parseFromXml(XmlPullParser in, int outerTagDepth) 1869 throws XmlPullParserException, IOException { 1870 byte[] encryptedData = null; 1871 byte[] iv = null; 1872 1873 // Loop through and parse out all the elements from the stream within this section. 1874 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 1875 String[] valueName = new String[1]; 1876 Object value = XmlUtil.readCurrentValue(in, valueName); 1877 if (valueName[0] == null) { 1878 throw new XmlPullParserException("Missing value name"); 1879 } 1880 switch (valueName[0]) { 1881 case XML_TAG_ENCRYPTED_DATA: 1882 encryptedData = (byte[]) value; 1883 break; 1884 case XML_TAG_IV: 1885 iv = (byte[]) value; 1886 break; 1887 default: 1888 Log.e(TAG, "Unknown value name found: " + valueName[0]); 1889 break; 1890 } 1891 } 1892 return new EncryptedData(encryptedData, iv); 1893 } 1894 1895 /** 1896 * Parses the EncryptedData data elements arrays from the provided XML stream to a list of 1897 * EncryptedData object. 1898 * 1899 * @param in XmlPullParser instance pointing to the XML stream. 1900 * @param outerTagDepth depth of the outer tag in the XML document. 1901 * @return List of encryptedData object if parsing is successful, empty otherwise. 1902 */ parseListFromXml(XmlPullParser in, int outerTagDepth)1903 public static @NonNull List<EncryptedData> parseListFromXml(XmlPullParser in, 1904 int outerTagDepth) throws XmlPullParserException, IOException { 1905 List<EncryptedData> encryptedDataList = new ArrayList<>(); 1906 // Loop through and parse out all the elements from the stream within this section. 1907 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 1908 if (in.getAttributeValue(null, "name") != null) { 1909 String[] valueName = new String[1]; 1910 Object value = XmlUtil.readCurrentValue(in, valueName); 1911 if (valueName[0] == null) { 1912 throw new XmlPullParserException("Missing value name"); 1913 } 1914 byte[] encryptedData; 1915 byte[] iv; 1916 if (XML_TAG_ENCRYPTED_DATA.equals(valueName[0])) { 1917 encryptedData = (byte[]) value; 1918 if (!XmlUtil.isNextSectionEnd(in, outerTagDepth) && in.getAttributeValue( 1919 null, "name") != null) { 1920 value = XmlUtil.readCurrentValue(in, valueName); 1921 if (valueName[0] == null) { 1922 throw new XmlPullParserException("Missing value name"); 1923 } 1924 if (XML_TAG_IV.equals(valueName[0])) { 1925 iv = (byte[]) value; 1926 encryptedDataList.add(new EncryptedData(encryptedData, iv)); 1927 } 1928 } 1929 } 1930 } 1931 } 1932 return encryptedDataList; 1933 } 1934 } 1935 nextElementWithin(XmlPullParser parser, int outerDepth)1936 public static boolean nextElementWithin(XmlPullParser parser, int outerDepth) 1937 throws IOException, XmlPullParserException { 1938 return XmlUtilHelper.nextElementWithin(parser, outerDepth); 1939 } 1940 1941 /** 1942 * Utility class to serialize and deseriaize {@link SoftApConfiguration} object to XML 1943 * & vice versa. This is used by both {@link com.android.server.wifi.SoftApStore} modules. 1944 */ 1945 public static class SoftApConfigurationXmlUtil { 1946 /** 1947 * List of XML tags corresponding to SoftApConfiguration object elements. 1948 */ 1949 public static final String XML_TAG_CLIENT_MACADDRESS = "ClientMacAddress"; 1950 public static final String XML_TAG_BAND_CHANNEL = "BandChannel"; 1951 public static final String XML_TAG_SSID = "SSID"; // Use XML_TAG_WIFI_SSID instead 1952 public static final String XML_TAG_WIFI_SSID = "WifiSsid"; 1953 public static final String XML_TAG_BSSID = "Bssid"; 1954 public static final String XML_TAG_BAND = "Band"; 1955 public static final String XML_TAG_CHANNEL = "Channel"; 1956 public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID"; 1957 public static final String XML_TAG_SECURITY_TYPE = "SecurityType"; 1958 public static final String XML_TAG_WPA2_PASSPHRASE = "Wpa2Passphrase"; 1959 public static final String XML_TAG_AP_BAND = "ApBand"; 1960 public static final String XML_TAG_PASSPHRASE = "Passphrase"; 1961 public static final String XML_TAG_MAX_NUMBER_OF_CLIENTS = "MaxNumberOfClients"; 1962 public static final String XML_TAG_AUTO_SHUTDOWN_ENABLED = "AutoShutdownEnabled"; 1963 public static final String XML_TAG_SHUTDOWN_TIMEOUT_MILLIS = "ShutdownTimeoutMillis"; 1964 public static final String XML_TAG_CLIENT_CONTROL_BY_USER = "ClientControlByUser"; 1965 public static final String XML_TAG_BLOCKED_CLIENT_LIST = "BlockedClientList"; 1966 public static final String XML_TAG_ALLOWED_CLIENT_LIST = "AllowedClientList"; 1967 public static final String XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED = 1968 "BridgedModeOpportunisticShutdownEnabled"; 1969 public static final String XML_TAG_MAC_RAMDOMIZATION_SETTING = "MacRandomizationSetting"; 1970 public static final String XML_TAG_BAND_CHANNEL_MAP = "BandChannelMap"; 1971 public static final String XML_TAG_80211_AX_ENABLED = "80211axEnabled"; 1972 public static final String XML_TAG_80211_BE_ENABLED = "80211beEnabled"; 1973 public static final String XML_TAG_USER_CONFIGURATION = "UserConfiguration"; 1974 public static final String XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS = 1975 "BridgedModeOpportunisticShutdownTimeoutMillis"; 1976 public static final String XML_TAG_VENDOR_ELEMENT = "VendorElement"; 1977 public static final String XML_TAG_VENDOR_ELEMENTS = "VendorElements"; 1978 public static final String XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS = 1979 "PersistentRandomizedMacAddress"; 1980 public static final String XML_TAG_MAX_CHANNEL_WIDTH = "MaxChannelWidth"; 1981 public static final String XML_TAG_CLIENT_ISOLATION = "ClientIsolation"; 1982 1983 1984 /** 1985 * Parses the client list from the provided XML stream to a ArrayList object. 1986 * 1987 * @param in XmlPullParser instance pointing to the XML stream. 1988 * @param outerTagDepth depth of the outer tag in the XML document. 1989 * @return ArrayList object if parsing is successful, null otherwise. 1990 */ parseClientListFromXml(XmlPullParser in, int outerTagDepth)1991 public static List<MacAddress> parseClientListFromXml(XmlPullParser in, 1992 int outerTagDepth) throws XmlPullParserException, IOException, 1993 IllegalArgumentException { 1994 List<MacAddress> clientList = new ArrayList<>(); 1995 // Loop through and parse out all the elements from the stream within this section. 1996 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 1997 String[] valueName = new String[1]; 1998 Object value = XmlUtil.readCurrentValue(in, valueName); 1999 if (valueName[0] == null) { 2000 throw new XmlPullParserException("Missing value name"); 2001 } 2002 switch (valueName[0]) { 2003 case XML_TAG_CLIENT_MACADDRESS: 2004 MacAddress client = MacAddress.fromString((String) value); 2005 clientList.add(client); 2006 break; 2007 default: 2008 Log.e(TAG, "Unknown value name found: " + valueName[0]); 2009 break; 2010 } 2011 } 2012 return clientList; 2013 } 2014 2015 /** 2016 * Write the SoftApConfiguration client control list data elements 2017 * from the provided list to the XML stream. 2018 * 2019 * @param out XmlSerializer instance pointing to the XML stream. 2020 * @param clientList Client list object to be serialized. 2021 */ writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)2022 public static void writeClientListToXml(XmlSerializer out, List<MacAddress> clientList) 2023 throws XmlPullParserException, IOException { 2024 for (MacAddress mac: clientList) { 2025 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_MACADDRESS, mac.toString()); 2026 } 2027 } 2028 2029 /** 2030 * Write the SoftApConfiguration vendor elements list information elements to the XML 2031 * 2032 * @param out XmlSerializer instance pointing to the XML stream 2033 * @param elements Vendor elements list 2034 */ writeVendorElementsSetToXml( XmlSerializer out, List<ScanResult.InformationElement> elements)2035 public static void writeVendorElementsSetToXml( 2036 XmlSerializer out, List<ScanResult.InformationElement> elements) 2037 throws XmlPullParserException, IOException { 2038 for (ScanResult.InformationElement e : elements) { 2039 XmlUtil.writeNextValue(out, XML_TAG_VENDOR_ELEMENT, 2040 InformationElementUtil.toHexString(e)); 2041 } 2042 } 2043 2044 /** 2045 * Parses the vendor elements from the provided XML stream to HashSet object. 2046 * 2047 * @param in XmlPullParser instance pointing to the XML stream 2048 * @param outerTagDepth depth of the outer tag in the XML document 2049 * @return HashSet object if parsing is successful, empty set otherwise 2050 */ parseVendorElementsFromXml( XmlPullParser in, int outerTagDepth)2051 public static List<ScanResult.InformationElement> parseVendorElementsFromXml( 2052 XmlPullParser in, int outerTagDepth) 2053 throws XmlPullParserException, IOException, IllegalArgumentException { 2054 List<ScanResult.InformationElement> elements = new ArrayList<>(); 2055 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 2056 String[] valueName = new String[1]; 2057 Object value = XmlUtil.readCurrentValue(in, valueName); 2058 if (valueName[0] == null) { 2059 throw new XmlPullParserException("Missing value name"); 2060 } 2061 if (XML_TAG_VENDOR_ELEMENT.equals(valueName[0])) { 2062 ScanResult.InformationElement[] data = 2063 InformationElementUtil.parseInformationElements((String) value); 2064 elements.addAll(Arrays.asList(data)); 2065 } else { 2066 Log.e(TAG, "Unknown value name found: " + valueName[0]); 2067 } 2068 } 2069 return elements; 2070 } 2071 2072 /** 2073 * Parses the band and channel from the provided XML stream to a SparseIntArray object. 2074 * 2075 * @param in XmlPullParser instance pointing to the XML stream. 2076 * @param outerTagDepth depth of the outer tag in the XML document. 2077 * @return SparseIntArray object if parsing is successful, null otherwise. 2078 */ parseChannelsFromXml(XmlPullParser in, int outerTagDepth)2079 public static SparseIntArray parseChannelsFromXml(XmlPullParser in, 2080 int outerTagDepth) throws XmlPullParserException, IOException, 2081 IllegalArgumentException { 2082 SparseIntArray channels = new SparseIntArray(); 2083 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 2084 int band = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL; 2085 int channel = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL; 2086 switch (in.getName()) { 2087 case XML_TAG_BAND_CHANNEL: 2088 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth + 1)) { 2089 String[] valueName = new String[1]; 2090 Object value = XmlUtil.readCurrentValue(in, valueName); 2091 if (valueName[0] == null) { 2092 throw new XmlPullParserException("Missing value name"); 2093 } 2094 switch (valueName[0]) { 2095 case XML_TAG_BAND: 2096 band = (int) value; 2097 break; 2098 case XML_TAG_CHANNEL: 2099 channel = (int) value; 2100 break; 2101 default: 2102 Log.e(TAG, "Unknown value name found: " + valueName[0]); 2103 break; 2104 } 2105 } 2106 channels.put(band, channel); 2107 break; 2108 } 2109 } 2110 return channels; 2111 } 2112 2113 /** 2114 * Write the SoftApConfiguration channels data elements 2115 * from the provided SparseIntArray to the XML stream. 2116 * 2117 * @param out XmlSerializer instance pointing to the XML stream. 2118 * @param channels SparseIntArray, which includes bands and channels, to be serialized. 2119 */ writeChannelsToXml(XmlSerializer out, SparseIntArray channels)2120 public static void writeChannelsToXml(XmlSerializer out, SparseIntArray channels) 2121 throws XmlPullParserException, IOException { 2122 for (int i = 0; i < channels.size(); i++) { 2123 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL); 2124 XmlUtil.writeNextValue(out, XML_TAG_BAND, channels.keyAt(i)); 2125 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, channels.valueAt(i)); 2126 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL); 2127 } 2128 } 2129 2130 /** 2131 * Write the SoftApConfiguration data elements to the XML stream. 2132 * 2133 * @param out XmlSerializer instance pointing to the XML stream. 2134 * @param softApConfig configuration of the Soft AP. 2135 */ 2136 @SuppressLint("NewApi") writeSoftApConfigurationToXml(@onNull XmlSerializer out, @NonNull SoftApConfiguration softApConfig, WifiConfigStoreEncryptionUtil encryptionUtil)2137 public static void writeSoftApConfigurationToXml(@NonNull XmlSerializer out, 2138 @NonNull SoftApConfiguration softApConfig, 2139 WifiConfigStoreEncryptionUtil encryptionUtil) 2140 throws XmlPullParserException, IOException { 2141 if (softApConfig.getWifiSsid() != null) { 2142 XmlUtil.writeNextValue(out, XML_TAG_WIFI_SSID, 2143 softApConfig.getWifiSsid().toString()); 2144 } 2145 if (softApConfig.getBssid() != null) { 2146 XmlUtil.writeNextValue(out, XML_TAG_BSSID, softApConfig.getBssid().toString()); 2147 } 2148 if (!SdkLevel.isAtLeastS()) { 2149 // Band and channel change to store in Tag:BandChannelMap from S. 2150 XmlUtil.writeNextValue(out, XML_TAG_AP_BAND, softApConfig.getBand()); 2151 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, softApConfig.getChannel()); 2152 } 2153 XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, softApConfig.isHiddenSsid()); 2154 XmlUtil.writeNextValue(out, XML_TAG_SECURITY_TYPE, softApConfig.getSecurityType()); 2155 if (!ApConfigUtil.isNonPasswordAP(softApConfig.getSecurityType())) { 2156 XmlUtil.writeSoftApPassphraseToXml(out, softApConfig.getPassphrase(), 2157 encryptionUtil); 2158 } 2159 2160 XmlUtil.writeNextValue(out, XML_TAG_MAX_NUMBER_OF_CLIENTS, 2161 softApConfig.getMaxNumberOfClients()); 2162 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CONTROL_BY_USER, 2163 softApConfig.isClientControlByUserEnabled()); 2164 XmlUtil.writeNextValue(out, XML_TAG_AUTO_SHUTDOWN_ENABLED, 2165 softApConfig.isAutoShutdownEnabled()); 2166 XmlUtil.writeNextValue(out, XML_TAG_SHUTDOWN_TIMEOUT_MILLIS, 2167 softApConfig.getShutdownTimeoutMillis()); 2168 XmlUtil.writeNextSectionStart(out, XML_TAG_BLOCKED_CLIENT_LIST); 2169 XmlUtil.SoftApConfigurationXmlUtil.writeClientListToXml(out, 2170 softApConfig.getBlockedClientList()); 2171 XmlUtil.writeNextSectionEnd(out, XML_TAG_BLOCKED_CLIENT_LIST); 2172 2173 XmlUtil.writeNextSectionStart(out, XML_TAG_ALLOWED_CLIENT_LIST); 2174 XmlUtil.SoftApConfigurationXmlUtil.writeClientListToXml(out, 2175 softApConfig.getAllowedClientList()); 2176 XmlUtil.writeNextSectionEnd(out, XML_TAG_ALLOWED_CLIENT_LIST); 2177 if (SdkLevel.isAtLeastS()) { 2178 XmlUtil.writeNextValue(out, XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED, 2179 softApConfig.isBridgedModeOpportunisticShutdownEnabled()); 2180 XmlUtil.writeNextValue(out, XML_TAG_MAC_RAMDOMIZATION_SETTING, 2181 softApConfig.getMacRandomizationSetting()); 2182 2183 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL_MAP); 2184 XmlUtil.SoftApConfigurationXmlUtil.writeChannelsToXml(out, 2185 softApConfig.getChannels()); 2186 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL_MAP); 2187 XmlUtil.writeNextValue(out, XML_TAG_80211_AX_ENABLED, 2188 softApConfig.isIeee80211axEnabled()); 2189 XmlUtil.writeNextValue(out, XML_TAG_USER_CONFIGURATION, 2190 softApConfig.isUserConfiguration()); 2191 } 2192 if (SdkLevel.isAtLeastT()) { 2193 XmlUtil.writeNextValue(out, 2194 XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS, 2195 softApConfig.getBridgedModeOpportunisticShutdownTimeoutMillisInternal()); 2196 XmlUtil.writeNextSectionStart(out, XML_TAG_VENDOR_ELEMENTS); 2197 XmlUtil.SoftApConfigurationXmlUtil.writeVendorElementsSetToXml(out, 2198 softApConfig.getVendorElementsInternal()); 2199 XmlUtil.writeNextSectionEnd(out, XML_TAG_VENDOR_ELEMENTS); 2200 XmlUtil.writeNextValue(out, XML_TAG_80211_BE_ENABLED, 2201 softApConfig.isIeee80211beEnabled()); 2202 if (softApConfig.getPersistentRandomizedMacAddress() != null) { 2203 XmlUtil.writeNextValue(out, XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS, 2204 softApConfig.getPersistentRandomizedMacAddress().toString()); 2205 } 2206 if (softapConfigStoreMaxChannelWidth()) { 2207 XmlUtil.writeNextValue(out, XML_TAG_MAX_CHANNEL_WIDTH, 2208 softApConfig.getMaxChannelBandwidth()); 2209 } 2210 } 2211 if (SdkLevel.isAtLeastV()) { 2212 writeVendorDataListToXml(out, softApConfig.getVendorData()); 2213 } 2214 if (Flags.apIsolate() && Environment.isSdkAtLeastB()) { 2215 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_ISOLATION, 2216 softApConfig.isClientIsolationEnabled()); 2217 } 2218 } // End of writeSoftApConfigurationToXml 2219 2220 /** 2221 * Returns configuration of the SoftAp from the XML stream. 2222 * 2223 * @param in XmlPullParser instance pointing to the XML stream. 2224 * @param outerTagDepth depth of the outer tag in the XML document. 2225 * @param settingsMigrationDataHolder the class instance of SettingsMigrationDataHolder 2226 */ 2227 @SuppressLint("NewApi") 2228 @Nullable parseFromXml(XmlPullParser in, int outerTagDepth, SettingsMigrationDataHolder settingsMigrationDataHolder, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)2229 public static SoftApConfiguration parseFromXml(XmlPullParser in, int outerTagDepth, 2230 SettingsMigrationDataHolder settingsMigrationDataHolder, 2231 boolean shouldExpectEncryptedCredentials, 2232 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 2233 throws XmlPullParserException, IOException { 2234 SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder(); 2235 int securityType = SoftApConfiguration.SECURITY_TYPE_OPEN; 2236 String passphrase = null; 2237 // SSID may be retrieved from the old encoding (XML_TAG_SSID) or the new encoding 2238 // (XML_TAG_WIFI_SSID). 2239 boolean hasSsid = false; 2240 String bssid = null; 2241 // Note that, during deserialization, we may read the old band encoding (XML_TAG_BAND) 2242 // or the new band encoding (XML_TAG_AP_BAND) that is used after the introduction of the 2243 // 6GHz band. If the old encoding is found, a conversion is done. 2244 int channel = -1; 2245 int apBand = -1; 2246 boolean hasBandChannelMap = false; 2247 List<MacAddress> blockedList = new ArrayList<>(); 2248 List<MacAddress> allowedList = new ArrayList<>(); 2249 boolean autoShutdownEnabledTagPresent = false; 2250 try { 2251 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 2252 if (in.getAttributeValue(null, "name") != null) { 2253 String[] valueName = new String[1]; 2254 Object value = XmlUtil.readCurrentValue(in, valueName); 2255 if (TextUtils.isEmpty(valueName[0])) { 2256 throw new XmlPullParserException("Missing value name"); 2257 } 2258 switch (valueName[0]) { 2259 case XML_TAG_SSID: 2260 hasSsid = true; 2261 softApConfigBuilder.setSsid((String) value); 2262 break; 2263 case XML_TAG_WIFI_SSID: 2264 hasSsid = true; 2265 final WifiSsid wifiSsid = WifiSsid.fromString((String) value); 2266 if (SdkLevel.isAtLeastT()) { 2267 softApConfigBuilder.setWifiSsid(wifiSsid); 2268 } else { 2269 // If the SSID is non-UTF-8, then use WifiManager.UNKNOWN_SSID. 2270 // This should not happen since non-UTF-8 SSIDs may only be set 2271 // with SoftApConfiguration#Builder#setWifiSsid(WifiSsid), 2272 // which is only available in T and above. 2273 final CharSequence utf8Ssid = wifiSsid.getUtf8Text(); 2274 softApConfigBuilder.setSsid(utf8Ssid != null 2275 ? utf8Ssid.toString() : WifiManager.UNKNOWN_SSID); 2276 } 2277 break; 2278 case XML_TAG_BSSID: 2279 bssid = (String) value; 2280 softApConfigBuilder.setBssid(MacAddress.fromString(bssid)); 2281 break; 2282 case XML_TAG_BAND: 2283 apBand = ApConfigUtil.convertWifiConfigBandToSoftApConfigBand( 2284 (int) value); 2285 break; 2286 case XML_TAG_AP_BAND: 2287 apBand = (int) value; 2288 break; 2289 case XML_TAG_CHANNEL: 2290 channel = (int) value; 2291 break; 2292 case XML_TAG_HIDDEN_SSID: 2293 softApConfigBuilder.setHiddenSsid((boolean) value); 2294 break; 2295 case XML_TAG_SECURITY_TYPE: 2296 securityType = (int) value; 2297 break; 2298 case XML_TAG_WPA2_PASSPHRASE: 2299 case XML_TAG_PASSPHRASE: 2300 passphrase = (String) value; 2301 break; 2302 case XML_TAG_MAX_NUMBER_OF_CLIENTS: 2303 softApConfigBuilder.setMaxNumberOfClients((int) value); 2304 break; 2305 case XML_TAG_AUTO_SHUTDOWN_ENABLED: 2306 softApConfigBuilder.setAutoShutdownEnabled((boolean) value); 2307 autoShutdownEnabledTagPresent = true; 2308 break; 2309 case XML_TAG_SHUTDOWN_TIMEOUT_MILLIS: 2310 long shutDownMillis = 0; 2311 if (value instanceof Integer) { 2312 shutDownMillis = Long.valueOf((int) value); 2313 } else if (value instanceof Long) { 2314 shutDownMillis = (long) value; 2315 } 2316 if (shutDownMillis == 0 2317 && CompatChanges.isChangeEnabled( 2318 SoftApConfiguration.REMOVE_ZERO_FOR_TIMEOUT_SETTING)) { 2319 shutDownMillis = SoftApConfiguration.DEFAULT_TIMEOUT; 2320 } 2321 softApConfigBuilder.setShutdownTimeoutMillis(shutDownMillis); 2322 break; 2323 case XML_TAG_CLIENT_CONTROL_BY_USER: 2324 softApConfigBuilder.setClientControlByUserEnabled((boolean) value); 2325 break; 2326 case XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED: 2327 if (SdkLevel.isAtLeastS()) { 2328 softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled( 2329 (boolean) value); 2330 } 2331 break; 2332 case XML_TAG_MAC_RAMDOMIZATION_SETTING: 2333 if (SdkLevel.isAtLeastS()) { 2334 softApConfigBuilder.setMacRandomizationSetting((int) value); 2335 } 2336 break; 2337 case XML_TAG_80211_AX_ENABLED: 2338 if (SdkLevel.isAtLeastS()) { 2339 softApConfigBuilder.setIeee80211axEnabled((boolean) value); 2340 } 2341 break; 2342 case XML_TAG_80211_BE_ENABLED: 2343 if (SdkLevel.isAtLeastT()) { 2344 softApConfigBuilder.setIeee80211beEnabled((boolean) value); 2345 } 2346 break; 2347 case XML_TAG_USER_CONFIGURATION: 2348 if (SdkLevel.isAtLeastS()) { 2349 softApConfigBuilder.setUserConfiguration((boolean) value); 2350 } 2351 break; 2352 case XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS: 2353 if (SdkLevel.isAtLeastT()) { 2354 long bridgedTimeout = (long) value; 2355 bridgedTimeout = bridgedTimeout == 0 2356 ? SoftApConfiguration.DEFAULT_TIMEOUT : bridgedTimeout; 2357 softApConfigBuilder 2358 .setBridgedModeOpportunisticShutdownTimeoutMillis( 2359 bridgedTimeout); 2360 } 2361 break; 2362 case XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS: 2363 if (SdkLevel.isAtLeastT()) { 2364 softApConfigBuilder.setRandomizedMacAddress( 2365 MacAddress.fromString((String) value)); 2366 } 2367 break; 2368 case XML_TAG_MAX_CHANNEL_WIDTH: 2369 if (SdkLevel.isAtLeastT() 2370 && softapConfigStoreMaxChannelWidth()) { 2371 softApConfigBuilder.setMaxChannelBandwidth((int) value); 2372 } 2373 break; 2374 case XML_TAG_CLIENT_ISOLATION: 2375 if (Flags.apIsolate() && Environment.isSdkAtLeastB()) { 2376 softApConfigBuilder.setClientIsolationEnabled((boolean) value); 2377 } 2378 break; 2379 default: 2380 Log.w(TAG, "Ignoring unknown value name " + valueName[0]); 2381 break; 2382 } 2383 } else { 2384 String tagName = in.getName(); 2385 List<MacAddress> parseredList; 2386 if (tagName == null) { 2387 throw new XmlPullParserException("Unexpected null tag found"); 2388 } 2389 switch (tagName) { 2390 case XML_TAG_BLOCKED_CLIENT_LIST: 2391 parseredList = 2392 XmlUtil.SoftApConfigurationXmlUtil.parseClientListFromXml( 2393 in, outerTagDepth + 1); 2394 if (parseredList != null) { 2395 blockedList = new ArrayList<>(parseredList); 2396 } 2397 break; 2398 case XML_TAG_ALLOWED_CLIENT_LIST: 2399 parseredList = 2400 XmlUtil.SoftApConfigurationXmlUtil.parseClientListFromXml( 2401 in, outerTagDepth + 1); 2402 if (parseredList != null) { 2403 allowedList = new ArrayList<>(parseredList); 2404 } 2405 break; 2406 case XML_TAG_BAND_CHANNEL_MAP: 2407 if (SdkLevel.isAtLeastS()) { 2408 hasBandChannelMap = true; 2409 SparseIntArray channels = XmlUtil.SoftApConfigurationXmlUtil 2410 .parseChannelsFromXml(in, outerTagDepth + 1); 2411 softApConfigBuilder.setChannels(channels); 2412 } 2413 break; 2414 case XML_TAG_VENDOR_ELEMENTS: 2415 if (SdkLevel.isAtLeastT()) { 2416 softApConfigBuilder.setVendorElements( 2417 SoftApConfigurationXmlUtil.parseVendorElementsFromXml( 2418 in, outerTagDepth + 1)); 2419 } 2420 break; 2421 case XML_TAG_PASSPHRASE: 2422 passphrase = readSoftApPassphraseFromXml(in, outerTagDepth, 2423 shouldExpectEncryptedCredentials, encryptionUtil); 2424 break; 2425 case XML_TAG_VENDOR_DATA_LIST: 2426 if (SdkLevel.isAtLeastV()) { 2427 softApConfigBuilder.setVendorData( 2428 parseVendorDataListFromXml(in, outerTagDepth + 1)); 2429 } 2430 break; 2431 default: 2432 Log.w(TAG, "Ignoring unknown tag found: " + tagName); 2433 break; 2434 } 2435 } 2436 } 2437 softApConfigBuilder.setBlockedClientList(blockedList); 2438 softApConfigBuilder.setAllowedClientList(allowedList); 2439 if (!hasBandChannelMap) { 2440 // Set channel and band 2441 if (channel == 0) { 2442 softApConfigBuilder.setBand(apBand); 2443 } else { 2444 softApConfigBuilder.setChannel(channel, apBand); 2445 } 2446 } 2447 2448 // We should at least have an SSID restored from store. 2449 if (!hasSsid) { 2450 Log.e(TAG, "Failed to parse SSID"); 2451 return null; 2452 } 2453 if (ApConfigUtil.isNonPasswordAP(securityType)) { 2454 softApConfigBuilder.setPassphrase(null, securityType); 2455 } else { 2456 softApConfigBuilder.setPassphrase(passphrase, securityType); 2457 } 2458 if (!autoShutdownEnabledTagPresent) { 2459 // Migrate data out of settings. 2460 WifiMigration.SettingsMigrationData migrationData = 2461 settingsMigrationDataHolder.retrieveData(); 2462 if (migrationData == null) { 2463 Log.e(TAG, "No migration data present"); 2464 } else { 2465 softApConfigBuilder.setAutoShutdownEnabled( 2466 migrationData.isSoftApTimeoutEnabled()); 2467 } 2468 } 2469 if (bssid != null && SdkLevel.isAtLeastS()) { 2470 // Force MAC randomization setting to none when BSSID is configured 2471 softApConfigBuilder.setMacRandomizationSetting( 2472 SoftApConfiguration.RANDOMIZATION_NONE); 2473 } 2474 } catch (IllegalArgumentException e) { 2475 Log.e(TAG, "Failed to parse configuration " + e); 2476 return null; 2477 } 2478 return softApConfigBuilder.build(); 2479 } // End of parseFromXml 2480 } 2481 writeSoftApPassphraseToXml( XmlSerializer out, String passphrase, WifiConfigStoreEncryptionUtil encryptionUtil)2482 private static void writeSoftApPassphraseToXml( 2483 XmlSerializer out, String passphrase, WifiConfigStoreEncryptionUtil encryptionUtil) 2484 throws XmlPullParserException, IOException { 2485 EncryptedData encryptedData = null; 2486 if (encryptionUtil != null && passphrase != null) { 2487 encryptedData = encryptionUtil.encrypt(passphrase.getBytes()); 2488 if (encryptedData == null) { 2489 // We silently fail encryption failures! 2490 Log.wtf(TAG, "Encryption of softAp passphrase failed"); 2491 } 2492 } 2493 if (encryptedData != null) { 2494 writeNextSectionStart(out, SoftApConfigurationXmlUtil.XML_TAG_PASSPHRASE); 2495 EncryptedDataXmlUtil.writeToXml(out, encryptedData); 2496 writeNextSectionEnd(out, SoftApConfigurationXmlUtil.XML_TAG_PASSPHRASE); 2497 } else { 2498 writeNextValue(out, SoftApConfigurationXmlUtil.XML_TAG_PASSPHRASE, passphrase); 2499 } 2500 } 2501 readSoftApPassphraseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, WifiConfigStoreEncryptionUtil encryptionUtil)2502 private static String readSoftApPassphraseFromXml(XmlPullParser in, int outerTagDepth, 2503 boolean shouldExpectEncryptedCredentials, WifiConfigStoreEncryptionUtil encryptionUtil) 2504 throws XmlPullParserException, IOException { 2505 if (!shouldExpectEncryptedCredentials || encryptionUtil == null) { 2506 throw new XmlPullParserException( 2507 "Encrypted passphraseBytes section not expected"); 2508 } 2509 EncryptedData encryptedData = 2510 XmlUtil.EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); 2511 byte[] passphraseBytes = encryptionUtil.decrypt(encryptedData); 2512 if (passphraseBytes == null) { 2513 Log.wtf(TAG, "Decryption of passphraseBytes failed"); 2514 return null; 2515 } else { 2516 return new String(passphraseBytes); 2517 } 2518 } 2519 2520 /** 2521 * Write the provided vendor data list to XML. 2522 * 2523 * @param out XmlSerializer instance pointing to the XML stream 2524 * @param vendorDataList Vendor data list 2525 */ writeVendorDataListToXml( XmlSerializer out, List<OuiKeyedData> vendorDataList)2526 private static void writeVendorDataListToXml( 2527 XmlSerializer out, List<OuiKeyedData> vendorDataList) 2528 throws XmlPullParserException, IOException { 2529 if (vendorDataList == null || vendorDataList.isEmpty()) { 2530 return; 2531 } 2532 XmlUtil.writeNextSectionStart(out, XML_TAG_VENDOR_DATA_LIST); 2533 for (OuiKeyedData data : vendorDataList) { 2534 writeOuiKeyedDataToXml(out, data); 2535 } 2536 XmlUtil.writeNextSectionEnd(out, XML_TAG_VENDOR_DATA_LIST); 2537 } 2538 writeOuiKeyedDataToXml( XmlSerializer out, OuiKeyedData ouiKeyedData)2539 private static void writeOuiKeyedDataToXml( 2540 XmlSerializer out, OuiKeyedData ouiKeyedData) 2541 throws XmlPullParserException, IOException { 2542 // PersistableBundle cannot be written directly to XML 2543 // Use byte[] as an intermediate data structure 2544 if (ouiKeyedData == null) return; 2545 byte[] bundleBytes; 2546 try { 2547 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 2548 ouiKeyedData.getData().writeToStream(outputStream); 2549 bundleBytes = outputStream.toByteArray(); 2550 } catch (Exception e) { 2551 Log.e(TAG, "Unable to write PersistableBundle to byte[]"); 2552 return; 2553 } 2554 XmlUtil.writeNextSectionStart(out, XML_TAG_OUI_KEYED_DATA); 2555 XmlUtil.writeNextValue(out, XML_TAG_VENDOR_DATA_OUI, ouiKeyedData.getOui()); 2556 XmlUtil.writeNextValue(out, XML_TAG_PERSISTABLE_BUNDLE, bundleBytes); 2557 XmlUtil.writeNextSectionEnd(out, XML_TAG_OUI_KEYED_DATA); 2558 } 2559 2560 /** 2561 * Parses the vendor data list from the provided XML stream . 2562 * 2563 * @param in XmlPullParser instance pointing to the XML stream 2564 * @param outerTagDepth depth of the outer tag in the XML document 2565 * @return List of OuiKeyedData if successful, empty list otherwise 2566 */ parseVendorDataListFromXml( XmlPullParser in, int outerTagDepth)2567 private static List<OuiKeyedData> parseVendorDataListFromXml( 2568 XmlPullParser in, int outerTagDepth) 2569 throws XmlPullParserException, IOException, IllegalArgumentException { 2570 List<OuiKeyedData> vendorDataList = new ArrayList<>(); 2571 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 2572 String tagName = in.getName(); 2573 if (tagName == null) { 2574 throw new XmlPullParserException("Unexpected null tag found"); 2575 } 2576 switch (tagName) { 2577 case XML_TAG_OUI_KEYED_DATA: 2578 OuiKeyedData data = parseOuiKeyedDataFromXml(in, outerTagDepth + 1); 2579 if (data != null) { 2580 vendorDataList.add(data); 2581 } 2582 break; 2583 default: 2584 Log.w(TAG, "Ignoring unknown tag found: " + tagName); 2585 break; 2586 } 2587 } 2588 return vendorDataList; 2589 } 2590 readPersistableBundleFromBytes(byte[] bundleBytes)2591 private static PersistableBundle readPersistableBundleFromBytes(byte[] bundleBytes) { 2592 try { 2593 ByteArrayInputStream inputStream = new ByteArrayInputStream(bundleBytes); 2594 return PersistableBundle.readFromStream(inputStream); 2595 } catch (Exception e) { 2596 Log.e(TAG, "Unable to read PersistableBundle from byte[]"); 2597 return null; 2598 } 2599 } 2600 parseOuiKeyedDataFromXml( XmlPullParser in, int outerTagDepth)2601 private static OuiKeyedData parseOuiKeyedDataFromXml( 2602 XmlPullParser in, int outerTagDepth) 2603 throws XmlPullParserException, IOException, IllegalArgumentException { 2604 int oui = 0; 2605 PersistableBundle bundle = null; 2606 2607 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 2608 String[] valueName = new String[1]; 2609 Object value = XmlUtil.readCurrentValue(in, valueName); 2610 if (valueName[0] == null) { 2611 throw new XmlPullParserException("Missing value name"); 2612 } 2613 switch (valueName[0]) { 2614 case XML_TAG_VENDOR_DATA_OUI: 2615 oui = (int) value; 2616 break; 2617 case XML_TAG_PERSISTABLE_BUNDLE: 2618 bundle = readPersistableBundleFromBytes((byte[]) value); 2619 break; 2620 default: 2621 Log.e(TAG, "Unknown value name found: " + valueName[0]); 2622 break; 2623 } 2624 } 2625 2626 try { 2627 return new OuiKeyedData.Builder(oui, bundle).build(); 2628 } catch (Exception e) { 2629 Log.e(TAG, "Unable to build OuiKeyedData"); 2630 return null; 2631 } 2632 } 2633 } 2634