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